@lodestar/beacon-node 1.51.0-dev.02c5a19f35 → 1.51.0-dev.0586e6e617

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/lib/api/impl/api.js +1 -1
  2. package/lib/api/impl/api.js.map +1 -1
  3. package/lib/api/impl/beacon/blocks/index.d.ts +2 -1
  4. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/blocks/index.js +29 -34
  6. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  7. package/lib/api/impl/beacon/index.d.ts +2 -1
  8. package/lib/api/impl/beacon/index.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/index.js +2 -2
  10. package/lib/api/impl/beacon/index.js.map +1 -1
  11. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  12. package/lib/api/impl/beacon/pool/index.js +5 -2
  13. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  14. package/lib/api/impl/beacon/state/utils.d.ts +1 -1
  15. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  16. package/lib/api/impl/validator/index.d.ts.map +1 -1
  17. package/lib/api/impl/validator/index.js +4 -1
  18. package/lib/api/impl/validator/index.js.map +1 -1
  19. package/lib/api/options.d.ts +2 -0
  20. package/lib/api/options.d.ts.map +1 -1
  21. package/lib/api/options.js +1 -0
  22. package/lib/api/options.js.map +1 -1
  23. package/lib/chain/GetBlobsTracker.d.ts +11 -0
  24. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  25. package/lib/chain/GetBlobsTracker.js +85 -27
  26. package/lib/chain/GetBlobsTracker.js.map +1 -1
  27. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  28. package/lib/chain/archiveStore/archiveStore.js +1 -0
  29. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  30. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +4 -0
  31. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  32. package/lib/chain/archiveStore/utils/archiveBlocks.js +61 -97
  33. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  34. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  35. package/lib/chain/blocks/importBlock.js +6 -5
  36. package/lib/chain/blocks/importBlock.js.map +1 -1
  37. package/lib/chain/blocks/importExecutionPayload.d.ts +6 -11
  38. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  39. package/lib/chain/blocks/importExecutionPayload.js +8 -15
  40. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  41. package/lib/chain/blocks/index.js +2 -2
  42. package/lib/chain/blocks/index.js.map +1 -1
  43. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +12 -9
  44. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  45. package/lib/chain/blocks/payloadEnvelopeProcessor.js +24 -19
  46. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  47. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  48. package/lib/chain/blocks/verifyBlock.js +1 -1
  49. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
  51. package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
  52. package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
  53. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +3 -3
  54. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  55. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +11 -6
  56. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  57. package/lib/chain/bls/multithread/index.js +5 -5
  58. package/lib/chain/bls/multithread/index.js.map +1 -1
  59. package/lib/chain/bls/multithread/types.d.ts +1 -1
  60. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  61. package/lib/chain/bls/multithread/worker.js +1 -1
  62. package/lib/chain/bls/multithread/worker.js.map +1 -1
  63. package/lib/chain/bls/singleThread.js +1 -1
  64. package/lib/chain/bls/singleThread.js.map +1 -1
  65. package/lib/chain/bls/utils.js +1 -1
  66. package/lib/chain/bls/utils.js.map +1 -1
  67. package/lib/chain/chain.d.ts +1 -1
  68. package/lib/chain/chain.d.ts.map +1 -1
  69. package/lib/chain/chain.js +4 -4
  70. package/lib/chain/chain.js.map +1 -1
  71. package/lib/chain/errors/blockError.d.ts +1 -1
  72. package/lib/chain/errors/blockError.d.ts.map +1 -1
  73. package/lib/chain/errors/blockError.js +1 -1
  74. package/lib/chain/errors/blockError.js.map +1 -1
  75. package/lib/chain/interface.d.ts +2 -3
  76. package/lib/chain/interface.d.ts.map +1 -1
  77. package/lib/chain/interface.js.map +1 -1
  78. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  79. package/lib/chain/opPools/aggregatedAttestationPool.js +23 -10
  80. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  81. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  82. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  83. package/lib/chain/opPools/attestationPool.js +15 -4
  84. package/lib/chain/opPools/attestationPool.js.map +1 -1
  85. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  86. package/lib/chain/opPools/payloadAttestationPool.js +17 -7
  87. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  88. package/lib/chain/opPools/syncCommitteeMessagePool.d.ts.map +1 -1
  89. package/lib/chain/opPools/syncCommitteeMessagePool.js +9 -3
  90. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  91. package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
  92. package/lib/chain/opPools/syncContributionAndProofPool.js +11 -3
  93. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  94. package/lib/chain/opPools/utils.d.ts +1 -1
  95. package/lib/chain/opPools/utils.d.ts.map +1 -1
  96. package/lib/chain/opPools/utils.js +1 -1
  97. package/lib/chain/opPools/utils.js.map +1 -1
  98. package/lib/chain/options.d.ts +0 -1
  99. package/lib/chain/options.d.ts.map +1 -1
  100. package/lib/chain/options.js +0 -1
  101. package/lib/chain/options.js.map +1 -1
  102. package/lib/chain/regen/interface.d.ts +0 -1
  103. package/lib/chain/regen/interface.d.ts.map +1 -1
  104. package/lib/chain/regen/interface.js +0 -1
  105. package/lib/chain/regen/interface.js.map +1 -1
  106. package/lib/chain/validation/executionPayloadBid.d.ts +0 -15
  107. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  108. package/lib/chain/validation/executionPayloadBid.js +13 -166
  109. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  110. package/lib/db/beacon.d.ts +7 -0
  111. package/lib/db/beacon.d.ts.map +1 -1
  112. package/lib/db/beacon.js +34 -0
  113. package/lib/db/beacon.js.map +1 -1
  114. package/lib/db/dataColumnStore.d.ts +1 -1
  115. package/lib/db/dataColumnStore.d.ts.map +1 -1
  116. package/lib/db/dataColumnStore.js +1 -4
  117. package/lib/db/dataColumnStore.js.map +1 -1
  118. package/lib/db/flatFileStore/flatFileStore.js +5 -5
  119. package/lib/db/flatFileStore/flatFileStore.js.map +1 -1
  120. package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -1
  121. package/lib/db/flatFileStore/slotIndex.js +2 -2
  122. package/lib/db/flatFileStore/slotIndex.js.map +1 -1
  123. package/lib/db/interface.d.ts +1 -0
  124. package/lib/db/interface.d.ts.map +1 -1
  125. package/lib/db/repositories/dataColumnSidecarArchive.d.ts +6 -0
  126. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  127. package/lib/db/repositories/dataColumnSidecarArchive.js +19 -0
  128. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  129. package/lib/execution/engine/index.d.ts +1 -1
  130. package/lib/execution/engine/index.d.ts.map +1 -1
  131. package/lib/execution/engine/index.js +1 -1
  132. package/lib/execution/engine/index.js.map +1 -1
  133. package/lib/execution/engine/interface.d.ts +1 -1
  134. package/lib/execution/engine/interface.d.ts.map +1 -1
  135. package/lib/execution/engine/interface.js.map +1 -1
  136. package/lib/execution/engine/types.d.ts.map +1 -1
  137. package/lib/execution/engine/types.js +2 -2
  138. package/lib/execution/engine/types.js.map +1 -1
  139. package/lib/index.d.ts +1 -0
  140. package/lib/index.d.ts.map +1 -1
  141. package/lib/index.js +2 -0
  142. package/lib/index.js.map +1 -1
  143. package/lib/metrics/metrics/lodestar.d.ts +6 -0
  144. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  145. package/lib/metrics/metrics/lodestar.js +10 -0
  146. package/lib/metrics/metrics/lodestar.js.map +1 -1
  147. package/lib/monitoring/service.js +1 -1
  148. package/lib/monitoring/service.js.map +1 -1
  149. package/lib/network/core/networkCore.d.ts +2 -0
  150. package/lib/network/core/networkCore.d.ts.map +1 -1
  151. package/lib/network/core/networkCore.js +3 -0
  152. package/lib/network/core/networkCore.js.map +1 -1
  153. package/lib/network/core/networkCoreWorker.js +1 -0
  154. package/lib/network/core/networkCoreWorker.js.map +1 -1
  155. package/lib/network/core/networkCoreWorkerHandler.d.ts +2 -0
  156. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  157. package/lib/network/core/networkCoreWorkerHandler.js +3 -0
  158. package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
  159. package/lib/network/core/types.d.ts +2 -0
  160. package/lib/network/core/types.d.ts.map +1 -1
  161. package/lib/network/interface.d.ts +2 -0
  162. package/lib/network/interface.d.ts.map +1 -1
  163. package/lib/network/network.d.ts +2 -0
  164. package/lib/network/network.d.ts.map +1 -1
  165. package/lib/network/network.js +6 -1
  166. package/lib/network/network.js.map +1 -1
  167. package/lib/network/peers/peerManager.d.ts +2 -1
  168. package/lib/network/peers/peerManager.d.ts.map +1 -1
  169. package/lib/network/peers/peerManager.js.map +1 -1
  170. package/lib/network/peers/utils/assertPeerRelevance.d.ts +9 -1
  171. package/lib/network/peers/utils/assertPeerRelevance.d.ts.map +1 -1
  172. package/lib/network/peers/utils/assertPeerRelevance.js +32 -21
  173. package/lib/network/peers/utils/assertPeerRelevance.js.map +1 -1
  174. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  175. package/lib/network/processor/gossipHandlers.js +13 -10
  176. package/lib/network/processor/gossipHandlers.js.map +1 -1
  177. package/lib/node/nodejs.d.ts +1 -1
  178. package/lib/node/nodejs.d.ts.map +1 -1
  179. package/lib/node/nodejs.js +10 -2
  180. package/lib/node/nodejs.js.map +1 -1
  181. package/lib/node/options.d.ts +1 -1
  182. package/lib/node/options.d.ts.map +1 -1
  183. package/lib/node/options.js +1 -1
  184. package/lib/node/options.js.map +1 -1
  185. package/lib/sync/interface.d.ts.map +1 -1
  186. package/lib/sync/interface.js.map +1 -1
  187. package/lib/sync/sync.d.ts +7 -0
  188. package/lib/sync/sync.d.ts.map +1 -1
  189. package/lib/sync/sync.js +61 -3
  190. package/lib/sync/sync.js.map +1 -1
  191. package/lib/util/file.d.ts.map +1 -1
  192. package/lib/util/file.js +8 -9
  193. package/lib/util/file.js.map +1 -1
  194. package/lib/util/queue/itemQueue.js +1 -1
  195. package/lib/util/queue/itemQueue.js.map +1 -1
  196. package/lib/util/sszBytes.js +2 -2
  197. package/lib/util/sszBytes.js.map +1 -1
  198. package/package.json +16 -17
  199. package/src/api/impl/api.ts +1 -1
  200. package/src/api/impl/beacon/blocks/index.ts +57 -62
  201. package/src/api/impl/beacon/index.ts +3 -1
  202. package/src/api/impl/beacon/pool/index.ts +5 -1
  203. package/src/api/impl/beacon/state/utils.ts +1 -1
  204. package/src/api/impl/validator/index.ts +4 -1
  205. package/src/api/options.ts +3 -0
  206. package/src/chain/GetBlobsTracker.ts +97 -38
  207. package/src/chain/archiveStore/archiveStore.ts +1 -0
  208. package/src/chain/archiveStore/utils/archiveBlocks.ts +76 -130
  209. package/src/chain/blocks/importBlock.ts +8 -7
  210. package/src/chain/blocks/importExecutionPayload.ts +13 -21
  211. package/src/chain/blocks/index.ts +6 -2
  212. package/src/chain/blocks/payloadEnvelopeProcessor.ts +35 -24
  213. package/src/chain/blocks/verifyBlock.ts +1 -0
  214. package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -1
  215. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +14 -6
  216. package/src/chain/bls/multithread/index.ts +5 -5
  217. package/src/chain/bls/multithread/types.ts +1 -1
  218. package/src/chain/bls/multithread/worker.ts +1 -5
  219. package/src/chain/bls/singleThread.ts +1 -1
  220. package/src/chain/bls/utils.ts +1 -1
  221. package/src/chain/chain.ts +5 -5
  222. package/src/chain/errors/blockError.ts +1 -1
  223. package/src/chain/interface.ts +2 -3
  224. package/src/chain/opPools/aggregatedAttestationPool.ts +25 -9
  225. package/src/chain/opPools/attestationPool.ts +16 -4
  226. package/src/chain/opPools/payloadAttestationPool.ts +18 -7
  227. package/src/chain/opPools/syncCommitteeMessagePool.ts +10 -3
  228. package/src/chain/opPools/syncContributionAndProofPool.ts +13 -3
  229. package/src/chain/opPools/utils.ts +1 -1
  230. package/src/chain/options.ts +0 -2
  231. package/src/chain/regen/interface.ts +0 -1
  232. package/src/chain/validation/executionPayloadBid.ts +14 -193
  233. package/src/db/beacon.ts +44 -0
  234. package/src/db/dataColumnStore.ts +2 -4
  235. package/src/db/flatFileStore/flatFileStore.ts +7 -7
  236. package/src/db/flatFileStore/slotIndex.ts +4 -3
  237. package/src/db/interface.ts +2 -0
  238. package/src/db/repositories/dataColumnSidecarArchive.ts +20 -0
  239. package/src/execution/engine/index.ts +1 -1
  240. package/src/execution/engine/interface.ts +1 -1
  241. package/src/execution/engine/types.ts +3 -1
  242. package/src/index.ts +2 -0
  243. package/src/metrics/metrics/lodestar.ts +10 -0
  244. package/src/monitoring/service.ts +1 -1
  245. package/src/network/core/networkCore.ts +5 -0
  246. package/src/network/core/networkCoreWorker.ts +1 -0
  247. package/src/network/core/networkCoreWorkerHandler.ts +4 -0
  248. package/src/network/core/types.ts +2 -0
  249. package/src/network/interface.ts +2 -0
  250. package/src/network/network.ts +8 -1
  251. package/src/network/peers/peerManager.ts +1 -1
  252. package/src/network/peers/utils/assertPeerRelevance.ts +39 -23
  253. package/src/network/processor/gossipHandlers.ts +16 -9
  254. package/src/node/nodejs.ts +24 -7
  255. package/src/node/options.ts +4 -5
  256. package/src/sync/interface.ts +1 -0
  257. package/src/sync/sync.ts +65 -4
  258. package/src/util/file.ts +8 -9
  259. package/src/util/queue/itemQueue.ts +1 -1
  260. package/src/util/sszBytes.ts +2 -2
@@ -1,5 +1,6 @@
1
- import {ForkName, isForkPostFulu} from "@lodestar/params";
2
- import {ForkDigest, Root, Slot, Status, fulu, ssz} from "@lodestar/types";
1
+ import {ForkName, GENESIS_EPOCH, isForkPostFulu} from "@lodestar/params";
2
+ import {computeEpochAtSlot} from "@lodestar/state-transition";
3
+ import {Epoch, ForkDigest, Root, Slot, Status, fulu, ssz} from "@lodestar/types";
3
4
  import {toHex, toRootHex} from "@lodestar/utils";
4
5
 
5
6
  // TODO: Why this value? (From Lighthouse)
@@ -9,6 +10,8 @@ export enum IrrelevantPeerCode {
9
10
  INCOMPATIBLE_FORKS = "IRRELEVANT_PEER_INCOMPATIBLE_FORKS",
10
11
  DIFFERENT_CLOCKS = "IRRELEVANT_PEER_DIFFERENT_CLOCKS",
11
12
  DIFFERENT_FINALIZED = "IRRELEVANT_PEER_DIFFERENT_FINALIZED",
13
+ FINALIZED_EPOCH_TOO_HIGH = "IRRELEVANT_PEER_FINALIZED_EPOCH_TOO_HIGH",
14
+ INVALID_FINALIZED_ROOT = "IRRELEVANT_PEER_INVALID_FINALIZED_ROOT",
12
15
  NO_EARLIEST_AVAILABLE_SLOT = "NO_EARLIEST_AVAILABLE_SLOT",
13
16
  }
14
17
 
@@ -16,6 +19,8 @@ type IrrelevantPeerType =
16
19
  | {code: IrrelevantPeerCode.INCOMPATIBLE_FORKS; ours: ForkDigest; theirs: ForkDigest}
17
20
  | {code: IrrelevantPeerCode.DIFFERENT_CLOCKS; slotDiff: number}
18
21
  | {code: IrrelevantPeerCode.NO_EARLIEST_AVAILABLE_SLOT}
22
+ | {code: IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH; finalizedEpoch: Epoch; maxFinalizedEpoch: Epoch}
23
+ | {code: IrrelevantPeerCode.INVALID_FINALIZED_ROOT}
19
24
  | {code: IrrelevantPeerCode.DIFFERENT_FINALIZED; expectedRoot: Root; remoteRoot: Root};
20
25
 
21
26
  /**
@@ -45,29 +50,35 @@ export function assertPeerRelevance(
45
50
  return {code: IrrelevantPeerCode.DIFFERENT_CLOCKS, slotDiff};
46
51
  }
47
52
 
48
- // The remote's finalized epoch is less than or equal to ours, but the block root is
49
- // different to the one in our chain. Therefore, the node is on a different chain and we
50
- // should not communicate with them.
53
+ // A checkpoint can be finalized at the earliest at the start of epoch + 2
54
+ const maxFinalizedEpoch = Math.max(
55
+ GENESIS_EPOCH,
56
+ computeEpochAtSlot(Math.max(currentSlot, 0) + FUTURE_SLOT_TOLERANCE) - 2
57
+ );
58
+ if (remote.finalizedEpoch > maxFinalizedEpoch) {
59
+ return {
60
+ code: IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH,
61
+ finalizedEpoch: remote.finalizedEpoch,
62
+ maxFinalizedEpoch,
63
+ };
64
+ }
65
+
66
+ if (remote.finalizedEpoch > GENESIS_EPOCH && isZeroRoot(remote.finalizedRoot)) {
67
+ return {code: IrrelevantPeerCode.INVALID_FINALIZED_ROOT};
68
+ }
51
69
 
70
+ // The remote's finalized epoch is equal to ours, but the block root is different to the one in our chain.
71
+ // Therefore, the node is on a different chain and we should not communicate with them.
52
72
  if (
53
- remote.finalizedEpoch <= local.finalizedEpoch &&
54
- !isZeroRoot(remote.finalizedRoot) &&
55
- !isZeroRoot(local.finalizedRoot)
73
+ remote.finalizedEpoch === local.finalizedEpoch &&
74
+ !isZeroRoot(local.finalizedRoot) &&
75
+ !ssz.Root.equals(remote.finalizedRoot, local.finalizedRoot)
56
76
  ) {
57
- // NOTE: due to preferring to not access chain state here, we can't check the finalized root against our history.
58
- // The impact of not doing check is low: peers that are behind us we can't confirm they are in the same chain as us.
59
- // In the worst case they will attempt to sync from us, fail and disconnect. The ENR fork check should be sufficient
60
- // to differentiate most peers in normal network conditions.
61
- const remoteRoot = remote.finalizedRoot;
62
- const expectedRoot = remote.finalizedEpoch === local.finalizedEpoch ? local.finalizedRoot : null;
63
-
64
- if (expectedRoot !== null && !ssz.Root.equals(remoteRoot, expectedRoot)) {
65
- return {
66
- code: IrrelevantPeerCode.DIFFERENT_FINALIZED,
67
- expectedRoot: expectedRoot, // forkChoice returns Tree BranchNode which the logger prints as {}
68
- remoteRoot: remoteRoot,
69
- };
70
- }
77
+ return {
78
+ code: IrrelevantPeerCode.DIFFERENT_FINALIZED,
79
+ expectedRoot: local.finalizedRoot,
80
+ remoteRoot: remote.finalizedRoot,
81
+ };
71
82
  }
72
83
 
73
84
  if (isForkPostFulu(forkName) && (remote as fulu.Status).earliestAvailableSlot === undefined) {
@@ -76,7 +87,8 @@ export function assertPeerRelevance(
76
87
  };
77
88
  }
78
89
 
79
- // Note: Accept request status finalized checkpoint in the future, we do not know if it is a true finalized root
90
+ // Note: for a behind finalized checkpoint, we validate it more on the main thread against our history,
91
+ // see BeaconSync.verifyPastFinalizedCheckpoint
80
92
  return null;
81
93
  }
82
94
 
@@ -93,6 +105,10 @@ export function renderIrrelevantPeerType(type: IrrelevantPeerType): string {
93
105
  return `DIFFERENT_CLOCKS slotDiff: ${type.slotDiff}`;
94
106
  case IrrelevantPeerCode.DIFFERENT_FINALIZED:
95
107
  return `DIFFERENT_FINALIZED root: ${toRootHex(type.remoteRoot)} expected: ${toRootHex(type.expectedRoot)}`;
108
+ case IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH:
109
+ return `FINALIZED_EPOCH_TOO_HIGH finalizedEpoch: ${type.finalizedEpoch} max: ${type.maxFinalizedEpoch}`;
110
+ case IrrelevantPeerCode.INVALID_FINALIZED_ROOT:
111
+ return "INVALID_FINALIZED_ROOT zero root for a non-genesis finalized epoch";
96
112
  case IrrelevantPeerCode.NO_EARLIEST_AVAILABLE_SLOT:
97
113
  return "No earliestAvailableSlot announced via peer Status";
98
114
  }
@@ -24,6 +24,7 @@ import {
24
24
  deneb,
25
25
  fulu,
26
26
  gloas,
27
+ isGloasBeaconBlock,
27
28
  isGloasDataColumnSidecar,
28
29
  ssz,
29
30
  sszTypesFor,
@@ -704,10 +705,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
704
705
 
705
706
  // Immediately attempt fetch of data columns from execution engine as the bid contains kzg commitments
706
707
  // which is all the information we need so there is no reason to delay until execution payload arrives
707
- // TODO GLOAS: If we want EL retries after this initial attempt, add an explicit retry policy here
708
- // (for example later in the slot). Do not couple retries to incoming gossip columns.
709
- // Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
710
- // in-flight importExecutionPayload. No processExecutionPayload trigger needed from this path.
708
+ // Columns fetched here feed payloadInput.addColumn, which resolves the waitForAllData of a
709
+ // pending payload import. No processExecutionPayload trigger needed from this path.
711
710
  chain.getBlobsTracker.triggerGetBlobs(payloadInput);
712
711
  }
713
712
  })
@@ -717,11 +716,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
717
716
 
718
717
  if (e instanceof BlockError) {
719
718
  switch (e.type.code) {
720
- case BlockErrorCode.DATA_UNAVAILABLE: {
721
- // Error is quite frequent and not critical
719
+ case BlockErrorCode.DATA_UNAVAILABLE:
720
+ // Data did not arrive in time, BlockInputSync keeps pulling it and retries the import
722
721
  logLevel = LogLevel.debug;
723
722
  break;
724
- }
725
723
  // ALREADY_KNOWN should not happen with ignoreIfKnown=true above
726
724
  // PARENT_BLOCK_UNKNOWN should not happen, we handled this in validateBeaconBlock() function above
727
725
  case BlockErrorCode.ALREADY_KNOWN:
@@ -789,7 +787,12 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
789
787
  // roots per proposer and slot, which bounds full imports over gossip to one alternate
790
788
  chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root) &&
791
789
  // A sibling with an unknown parent cannot be imported, sync fetches it if its branch becomes relevant
792
- chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null
790
+ chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null &&
791
+ (!isGloasBeaconBlock(signedBlock.message) ||
792
+ chain.forkChoice.getBlockHexAndBlockHash(
793
+ toRootHex(signedBlock.message.parentRoot),
794
+ toRootHex(signedBlock.message.body.signedExecutionPayloadBid.message.parentBlockHash)
795
+ ) !== null)
793
796
  ) {
794
797
  const blockInput = cacheSignatureVerifiedBlock(
795
798
  signedBlock,
@@ -924,7 +927,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
924
927
  }
925
928
 
926
929
  // NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
927
- // envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
930
+ // envelope arrival (gossip or API). A pending payload import is awaiting
928
931
  // payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
929
932
 
930
933
  scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
@@ -1352,6 +1355,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1352
1355
 
1353
1356
  if (e instanceof PayloadError) {
1354
1357
  switch (e.type.code) {
1358
+ case PayloadErrorCode.DATA_UNAVAILABLE:
1359
+ // Columns did not arrive in time, BlockInputSync keeps pulling them and retries the import
1360
+ logLevel = LogLevel.debug;
1361
+ break;
1355
1362
  // BLOCK_NOT_IN_FORK_CHOICE should not happen, validateGossipExecutionPayloadEnvelope above
1356
1363
  // already verified the block is in fork choice
1357
1364
  case PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE:
@@ -1,23 +1,29 @@
1
1
  import {setMaxListeners} from "node:events";
2
2
  import {PrivateKey} from "@libp2p/interface";
3
3
  import {Registry} from "prom-client";
4
+ import {hasher} from "@chainsafe/persistent-merkle-tree";
5
+ import {BeaconApiMethods} from "@lodestar/api/beacon/server";
6
+ import {BeaconConfig} from "@lodestar/config";
7
+ import type {LoggerNode} from "@lodestar/logger/node";
4
8
  import {
5
9
  init as initNativeMetrics,
6
10
  registerLocalValidator as registerNativeLocalValidator,
7
11
  scrapeMetrics as scrapeNativeMetrics,
8
12
  unregisterLocalValidator as unregisterNativeLocalValidator,
9
- } from "@chainsafe/lodestar-z/metrics";
10
- import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
11
- import {hasher} from "@chainsafe/persistent-merkle-tree";
12
- import {BeaconApiMethods} from "@lodestar/api/beacon/server";
13
- import {BeaconConfig} from "@lodestar/config";
14
- import type {LoggerNode} from "@lodestar/logger/node";
13
+ } from "@lodestar/native/metrics";
14
+ import {type PubkeyCache} from "@lodestar/native/pubkeys";
15
15
  import {ZERO_HASH_HEX} from "@lodestar/params";
16
- import {IBeaconStateView, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
16
+ import {
17
+ IBeaconStateView,
18
+ computeStartSlotAtEpoch,
19
+ isStatePostBellatrix,
20
+ isStatePostGloas,
21
+ } from "@lodestar/state-transition";
17
22
  import {Slot} from "@lodestar/types";
18
23
  import {sleep, toRootHex} from "@lodestar/utils";
19
24
  import {ProcessShutdownCallback} from "@lodestar/validator";
20
25
  import {BeaconRestApiServer, getApi} from "../api/index.js";
26
+ import {getDataColumnSidecarsMinEpoch} from "../chain/archiveStore/utils/archiveBlocks.js";
21
27
  import {BeaconChain, IBeaconChain, initBeaconMetrics} from "../chain/index.js";
22
28
  import {ValidatorMonitor, createValidatorMonitor} from "../chain/validatorMonitor.js";
23
29
  import {IBeaconDb} from "../db/index.js";
@@ -212,6 +218,17 @@ export class BeaconNode {
212
218
 
213
219
  const clock = new Clock({config, genesisTime: anchorState.genesisTime, signal});
214
220
 
221
+ // Before any lookup into the legacy column buckets, which can be slow until compacted
222
+ const columnsMinEpoch =
223
+ opts.chain.archiveDataEpochs === Infinity
224
+ ? null
225
+ : getDataColumnSidecarsMinEpoch(config, clock.currentEpoch, opts.chain.archiveDataEpochs);
226
+ await db.compactLegacyDataColumns(
227
+ columnsMinEpoch !== null && columnsMinEpoch >= config.FULU_FORK_EPOCH
228
+ ? computeStartSlotAtEpoch(columnsMinEpoch)
229
+ : 0
230
+ );
231
+
215
232
  await db.init();
216
233
 
217
234
  // Prune hot db repos
@@ -19,16 +19,15 @@ import {SyncOptions, defaultSyncOptions} from "../sync/options.js";
19
19
 
20
20
  // Re-export so the CLI doesn't need to depend on lodestar-api
21
21
  export {allNamespaces} from "../api/rest/index.js";
22
-
22
+ export type {EngineApiMode};
23
23
  // Re-export to use as default values in CLI args
24
24
  export {
25
- defaultExecutionEngineHttpOpts,
26
- defaultExecutionBuilderHttpOpts,
27
- engineApiModes,
28
25
  ArchiveMode,
29
26
  DEFAULT_ARCHIVE_MODE,
27
+ defaultExecutionBuilderHttpOpts,
28
+ defaultExecutionEngineHttpOpts,
29
+ engineApiModes,
30
30
  };
31
- export type {EngineApiMode};
32
31
 
33
32
  export interface IBeaconNodeOptions {
34
33
  api: ApiOptions;
@@ -7,6 +7,7 @@ import {IBeaconDb} from "../db/index.js";
7
7
  import {Metrics} from "../metrics/index.js";
8
8
  import {INetwork} from "../network/index.js";
9
9
  import {SyncChainDebugState} from "./range/chain.js";
10
+
10
11
  export type {SyncChainDebugState};
11
12
 
12
13
  export type SyncingStatus = routes.node.SyncingStatus;
package/src/sync/sync.ts CHANGED
@@ -1,13 +1,17 @@
1
1
  import {SLOTS_PER_EPOCH} from "@lodestar/params";
2
- import {Slot} from "@lodestar/types";
2
+ import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
3
+ import {Slot, Status} from "@lodestar/types";
3
4
  import {Logger, toRootHex} from "@lodestar/utils";
4
5
  import {IBeaconChain} from "../chain/index.js";
5
- import {GENESIS_SLOT} from "../constants/constants.js";
6
+ import {GENESIS_EPOCH, GENESIS_SLOT} from "../constants/constants.js";
7
+ import {GoodByeReasonCode} from "../constants/index.js";
8
+ import {IBeaconDb} from "../db/index.js";
6
9
  import {ExecutionEngineState} from "../execution/index.js";
7
10
  import {Metrics} from "../metrics/index.js";
8
- import {INetwork, NetworkEvent, NetworkEventData} from "../network/index.js";
11
+ import {INetwork, NetworkEvent, NetworkEventData, PeerAction} from "../network/index.js";
9
12
  import {ClockEvent} from "../util/clock.js";
10
13
  import {isOptimisticBlock} from "../util/forkChoice.js";
14
+ import {PeerIdStr} from "../util/peerId.js";
11
15
  import {MIN_EPOCH_TO_START_GOSSIP} from "./constants.js";
12
16
  import {IBeaconSync, SyncChainDebugState, SyncModules, SyncState, SyncingStatus, syncStateMetric} from "./interface.js";
13
17
  import {SyncOptions} from "./options.js";
@@ -19,6 +23,7 @@ export class BeaconSync implements IBeaconSync {
19
23
  private readonly logger: Logger;
20
24
  private readonly network: INetwork;
21
25
  private readonly chain: IBeaconChain;
26
+ private readonly db: IBeaconDb;
22
27
  private readonly metrics: Metrics | null;
23
28
  private readonly opts: SyncOptions;
24
29
 
@@ -30,10 +35,11 @@ export class BeaconSync implements IBeaconSync {
30
35
  private readonly slotImportTolerance: Slot;
31
36
 
32
37
  constructor(opts: SyncOptions, modules: SyncModules) {
33
- const {config, chain, metrics, network, logger} = modules;
38
+ const {config, chain, db, metrics, network, logger} = modules;
34
39
  this.opts = opts;
35
40
  this.network = network;
36
41
  this.chain = chain;
42
+ this.db = db;
37
43
  this.metrics = metrics;
38
44
  this.logger = logger;
39
45
  this.rangeSync = new RangeSync(modules, opts);
@@ -192,6 +198,11 @@ export class BeaconSync implements IBeaconSync {
192
198
  */
193
199
  private addPeer = (data: NetworkEventData[NetworkEvent.peerConnected]): void => {
194
200
  const localStatus = this.chain.getStatus();
201
+ // Genesis and equal finalized epochs are already checked by assertPeerRelevance in the network worker
202
+ if (data.status.finalizedEpoch > GENESIS_EPOCH && data.status.finalizedEpoch < localStatus.finalizedEpoch) {
203
+ void this.verifyPastFinalizedCheckpoint(data.peer, data.status);
204
+ }
205
+
195
206
  const syncType = getPeerSyncType(localStatus, data.status, this.chain.forkChoice, this.slotImportTolerance);
196
207
  this.logger.verbose("Peer sync type classified", {
197
208
  peer: data.peer,
@@ -216,6 +227,56 @@ export class BeaconSync implements IBeaconSync {
216
227
  this.updateSyncState();
217
228
  };
218
229
 
230
+ /**
231
+ * A behind peer's finalized checkpoint must be the canonical block in effect at the start slot of its epoch
232
+ */
233
+ async verifyPastFinalizedCheckpoint(peer: PeerIdStr, remote: Status): Promise<void> {
234
+ const startSlot = computeStartSlotAtEpoch(remote.finalizedEpoch);
235
+ const root = toRootHex(remote.finalizedRoot);
236
+ try {
237
+ let reason: string | null = null;
238
+ // After a finality jump, finalized blocks stay in fork choice until the archiver migrates them.
239
+ // Fork choice is pruned only after archiving, so a miss here means the db already has this range.
240
+ const canonicalBlock = this.chain.forkChoice.getCanonicalBlockClosestLteSlot(startSlot);
241
+ if (canonicalBlock !== null) {
242
+ if (canonicalBlock.blockRoot === root) return;
243
+ reason = "finalized_root_not_canonical";
244
+ } else {
245
+ const slot = await this.db.blockArchive.getSlotByRoot(remote.finalizedRoot);
246
+ if (slot !== null && slot > startSlot) {
247
+ reason = "finalized_root_after_epoch_start";
248
+ } else if (slot !== startSlot) {
249
+ const childSlot = await this.db.blockArchive.getSlotByParentRoot(remote.finalizedRoot);
250
+ if (childSlot !== null) {
251
+ if (childSlot <= startSlot) reason = "finalized_root_not_in_effect_at_epoch_start";
252
+ } else if (slot === null && startSlot > this.chain.earliestAvailableSlot) {
253
+ // childSlot == null too, neither the root nor a child is canonical
254
+ // or they are canonical and both pruned but peer's finalized epoch starts after earliestAvailableSlot
255
+ reason = "unknown_finalized_root";
256
+ }
257
+ }
258
+ }
259
+
260
+ if (reason !== null) {
261
+ this.logger.debug("Peer finalized checkpoint not in our chain", {
262
+ peer,
263
+ finalizedEpoch: remote.finalizedEpoch,
264
+ root,
265
+ reason,
266
+ });
267
+ this.metrics?.syncPeerFinalizedCheckpointMismatch.inc({reason});
268
+ this.network.reportPeer(peer, PeerAction.Fatal, "PeerFinalizedCheckpointMismatch");
269
+ await this.network.goodbyeAndDisconnect(peer, GoodByeReasonCode.IRRELEVANT_NETWORK);
270
+ }
271
+ } catch (e) {
272
+ this.logger.debug(
273
+ "Error verifying peer finalized checkpoint",
274
+ {peer, finalizedEpoch: remote.finalizedEpoch, root},
275
+ e as Error
276
+ );
277
+ }
278
+ }
279
+
219
280
  /**
220
281
  * Must be called by libp2p when a peer is removed from the peer manager
221
282
  */
package/src/util/file.ts CHANGED
@@ -1,25 +1,24 @@
1
- import fs from "node:fs";
2
- import {promisify} from "node:util";
1
+ import {readFile as fsReadFile, mkdir, readdir, stat, unlink, writeFile} from "node:fs/promises";
3
2
 
4
3
  /** Ensure a directory exists */
5
4
  export async function ensureDir(path: string): Promise<void> {
6
5
  try {
7
- await promisify(fs.stat)(path);
6
+ await stat(path);
8
7
  } catch (_) {
9
8
  // not exists
10
- await promisify(fs.mkdir)(path, {recursive: true});
9
+ await mkdir(path, {recursive: true});
11
10
  }
12
11
  }
13
12
 
14
13
  /** Write data to a file if it does not exist */
15
14
  export async function writeIfNotExist(filepath: string, bytes: Uint8Array): Promise<boolean> {
16
15
  try {
17
- await promisify(fs.stat)(filepath);
16
+ await stat(filepath);
18
17
  return false;
19
18
  // file exists, do nothing
20
19
  } catch (_) {
21
20
  // not exists
22
- await promisify(fs.writeFile)(filepath, bytes);
21
+ await writeFile(filepath, bytes);
23
22
  return true;
24
23
  }
25
24
  }
@@ -27,7 +26,7 @@ export async function writeIfNotExist(filepath: string, bytes: Uint8Array): Prom
27
26
  /** Remove a file if it exists */
28
27
  export async function removeFile(path: string): Promise<boolean> {
29
28
  try {
30
- await promisify(fs.unlink)(path);
29
+ await unlink(path);
31
30
  return true;
32
31
  } catch (_) {
33
32
  // may not exists
@@ -37,7 +36,7 @@ export async function removeFile(path: string): Promise<boolean> {
37
36
 
38
37
  export async function readFile(path: string): Promise<Uint8Array | null> {
39
38
  try {
40
- return await fs.promises.readFile(path);
39
+ return await fsReadFile(path);
41
40
  } catch (_) {
42
41
  return null;
43
42
  }
@@ -45,7 +44,7 @@ export async function readFile(path: string): Promise<Uint8Array | null> {
45
44
 
46
45
  export async function readFileNames(folderPath: string): Promise<string[]> {
47
46
  try {
48
- return await fs.promises.readdir(folderPath);
47
+ return await readdir(folderPath);
49
48
  } catch (_) {
50
49
  return [];
51
50
  }
@@ -69,7 +69,7 @@ export class JobItemQueue<Args extends any[], R> {
69
69
  if (this.jobs.length === 1 && this.opts.noYieldIfOneItem) {
70
70
  void this.runJob();
71
71
  } else if (this.runningJobs < this.opts.maxConcurrency) {
72
- callInNextEventLoop(this.runJob);
72
+ callInNextEventLoop(() => void this.runJob());
73
73
  }
74
74
  });
75
75
  }
@@ -854,7 +854,7 @@ export function getBlobKzgCommitmentsCountFromSignedBeaconBlockSerialized(
854
854
 
855
855
  const start = bidMsgStart + commitmentsRange.start;
856
856
  const end = bidMsgStart + commitmentsRange.end;
857
- return Math.round(((end > blockBytes.byteLength ? blockBytes.byteLength : end) - start) / commitmentSize);
857
+ return Math.round((Math.min(end, blockBytes.byteLength) - start) / commitmentSize);
858
858
  }
859
859
 
860
860
  const {SignedBeaconBlock, BeaconBlock, BeaconBlockBody, KZGCommitment} = ssz[forkName as ForkPostDeneb];
@@ -880,5 +880,5 @@ export function getBlobKzgCommitmentsCountFromSignedBeaconBlockSerialized(
880
880
  const end = messageRange.end + bodyRange.end + kzgCommitmentsRange.end;
881
881
  const start = messageRange.start + bodyRange.start + kzgCommitmentsRange.start;
882
882
 
883
- return Math.round(((end > blockBytes.byteLength ? blockBytes.byteLength : end) - start) / commitmentSize);
883
+ return Math.round((Math.min(end, blockBytes.byteLength) - start) / commitmentSize);
884
884
  }