@lodestar/beacon-node 1.51.0-dev.5e25b73306 → 1.51.0-dev.6afc3c19f6

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 (289) 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 +11 -6
  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 +4 -1
  38. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  39. package/lib/chain/blocks/importExecutionPayload.js +9 -3
  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 +5 -5
  44. package/lib/chain/blocks/payloadEnvelopeProcessor.js +7 -7
  45. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  46. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  47. package/lib/chain/blocks/verifyBlock.js +1 -1
  48. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  49. package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
  51. package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
  52. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +3 -3
  53. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +13 -6
  55. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  56. package/lib/chain/bls/multithread/index.js +5 -5
  57. package/lib/chain/bls/multithread/index.js.map +1 -1
  58. package/lib/chain/bls/multithread/types.d.ts +1 -1
  59. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  60. package/lib/chain/bls/multithread/worker.js +1 -1
  61. package/lib/chain/bls/multithread/worker.js.map +1 -1
  62. package/lib/chain/bls/singleThread.js +1 -1
  63. package/lib/chain/bls/singleThread.js.map +1 -1
  64. package/lib/chain/bls/utils.js +1 -1
  65. package/lib/chain/bls/utils.js.map +1 -1
  66. package/lib/chain/chain.d.ts +1 -1
  67. package/lib/chain/chain.d.ts.map +1 -1
  68. package/lib/chain/chain.js +4 -4
  69. package/lib/chain/chain.js.map +1 -1
  70. package/lib/chain/errors/blockError.d.ts +1 -1
  71. package/lib/chain/errors/blockError.d.ts.map +1 -1
  72. package/lib/chain/errors/blockError.js +1 -1
  73. package/lib/chain/errors/blockError.js.map +1 -1
  74. package/lib/chain/interface.d.ts +2 -3
  75. package/lib/chain/interface.d.ts.map +1 -1
  76. package/lib/chain/interface.js.map +1 -1
  77. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  78. package/lib/chain/opPools/aggregatedAttestationPool.js +23 -10
  79. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  80. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  81. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  82. package/lib/chain/opPools/attestationPool.js +15 -4
  83. package/lib/chain/opPools/attestationPool.js.map +1 -1
  84. package/lib/chain/opPools/inclusionListStore.d.ts.map +1 -1
  85. package/lib/chain/opPools/inclusionListStore.js +2 -2
  86. package/lib/chain/opPools/inclusionListStore.js.map +1 -1
  87. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  88. package/lib/chain/opPools/payloadAttestationPool.js +17 -7
  89. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  90. package/lib/chain/opPools/syncCommitteeMessagePool.d.ts.map +1 -1
  91. package/lib/chain/opPools/syncCommitteeMessagePool.js +9 -3
  92. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  93. package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
  94. package/lib/chain/opPools/syncContributionAndProofPool.js +11 -3
  95. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  96. package/lib/chain/opPools/utils.d.ts +1 -1
  97. package/lib/chain/opPools/utils.d.ts.map +1 -1
  98. package/lib/chain/opPools/utils.js +1 -1
  99. package/lib/chain/opPools/utils.js.map +1 -1
  100. package/lib/chain/options.d.ts +0 -1
  101. package/lib/chain/options.d.ts.map +1 -1
  102. package/lib/chain/options.js +0 -1
  103. package/lib/chain/options.js.map +1 -1
  104. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  105. package/lib/chain/produceBlock/produceBlockBody.js +0 -1
  106. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  107. package/lib/chain/regen/interface.d.ts +0 -1
  108. package/lib/chain/regen/interface.d.ts.map +1 -1
  109. package/lib/chain/regen/interface.js +0 -1
  110. package/lib/chain/regen/interface.js.map +1 -1
  111. package/lib/chain/validation/executionPayloadBid.d.ts +0 -15
  112. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  113. package/lib/chain/validation/executionPayloadBid.js +13 -166
  114. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  115. package/lib/chain/validation/inclusionList.d.ts.map +1 -1
  116. package/lib/chain/validation/inclusionList.js +11 -2
  117. package/lib/chain/validation/inclusionList.js.map +1 -1
  118. package/lib/db/beacon.d.ts +7 -0
  119. package/lib/db/beacon.d.ts.map +1 -1
  120. package/lib/db/beacon.js +34 -0
  121. package/lib/db/beacon.js.map +1 -1
  122. package/lib/db/dataColumnStore.d.ts +1 -1
  123. package/lib/db/dataColumnStore.d.ts.map +1 -1
  124. package/lib/db/dataColumnStore.js +1 -4
  125. package/lib/db/dataColumnStore.js.map +1 -1
  126. package/lib/db/interface.d.ts +1 -0
  127. package/lib/db/interface.d.ts.map +1 -1
  128. package/lib/db/repositories/dataColumnSidecarArchive.d.ts +6 -0
  129. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  130. package/lib/db/repositories/dataColumnSidecarArchive.js +19 -0
  131. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  132. package/lib/execution/engine/blobVersionedHashes.d.ts +1 -1
  133. package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -1
  134. package/lib/execution/engine/blobVersionedHashes.js.map +1 -1
  135. package/lib/execution/engine/http.d.ts.map +1 -1
  136. package/lib/execution/engine/http.js +0 -1
  137. package/lib/execution/engine/http.js.map +1 -1
  138. package/lib/execution/engine/index.d.ts +1 -1
  139. package/lib/execution/engine/index.d.ts.map +1 -1
  140. package/lib/execution/engine/index.js +1 -1
  141. package/lib/execution/engine/index.js.map +1 -1
  142. package/lib/execution/engine/interface.d.ts +1 -1
  143. package/lib/execution/engine/interface.d.ts.map +1 -1
  144. package/lib/execution/engine/interface.js.map +1 -1
  145. package/lib/execution/engine/mock.d.ts.map +1 -1
  146. package/lib/execution/engine/mock.js +6 -4
  147. package/lib/execution/engine/mock.js.map +1 -1
  148. package/lib/execution/engine/payloadIdCache.d.ts +1 -2
  149. package/lib/execution/engine/payloadIdCache.d.ts.map +1 -1
  150. package/lib/execution/engine/payloadIdCache.js +3 -3
  151. package/lib/execution/engine/payloadIdCache.js.map +1 -1
  152. package/lib/execution/engine/sszTypes.d.ts +38 -38
  153. package/lib/execution/engine/types.d.ts +1 -1
  154. package/lib/execution/engine/types.d.ts.map +1 -1
  155. package/lib/execution/engine/types.js +9 -8
  156. package/lib/execution/engine/types.js.map +1 -1
  157. package/lib/index.d.ts +1 -0
  158. package/lib/index.d.ts.map +1 -1
  159. package/lib/index.js +2 -0
  160. package/lib/index.js.map +1 -1
  161. package/lib/metrics/metrics/lodestar.d.ts +6 -0
  162. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  163. package/lib/metrics/metrics/lodestar.js +10 -0
  164. package/lib/metrics/metrics/lodestar.js.map +1 -1
  165. package/lib/monitoring/service.js +1 -1
  166. package/lib/monitoring/service.js.map +1 -1
  167. package/lib/network/core/networkCore.d.ts +2 -0
  168. package/lib/network/core/networkCore.d.ts.map +1 -1
  169. package/lib/network/core/networkCore.js +3 -0
  170. package/lib/network/core/networkCore.js.map +1 -1
  171. package/lib/network/core/networkCoreWorker.js +1 -0
  172. package/lib/network/core/networkCoreWorker.js.map +1 -1
  173. package/lib/network/core/networkCoreWorkerHandler.d.ts +2 -0
  174. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  175. package/lib/network/core/networkCoreWorkerHandler.js +3 -0
  176. package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
  177. package/lib/network/core/types.d.ts +2 -0
  178. package/lib/network/core/types.d.ts.map +1 -1
  179. package/lib/network/gossip/topic.d.ts +6 -6
  180. package/lib/network/interface.d.ts +2 -0
  181. package/lib/network/interface.d.ts.map +1 -1
  182. package/lib/network/network.d.ts +2 -0
  183. package/lib/network/network.d.ts.map +1 -1
  184. package/lib/network/network.js +6 -1
  185. package/lib/network/network.js.map +1 -1
  186. package/lib/network/peers/peerManager.d.ts +2 -1
  187. package/lib/network/peers/peerManager.d.ts.map +1 -1
  188. package/lib/network/peers/peerManager.js.map +1 -1
  189. package/lib/network/peers/utils/assertPeerRelevance.d.ts +9 -1
  190. package/lib/network/peers/utils/assertPeerRelevance.d.ts.map +1 -1
  191. package/lib/network/peers/utils/assertPeerRelevance.js +32 -21
  192. package/lib/network/peers/utils/assertPeerRelevance.js.map +1 -1
  193. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  194. package/lib/network/processor/gossipHandlers.js +33 -23
  195. package/lib/network/processor/gossipHandlers.js.map +1 -1
  196. package/lib/network/processor/index.d.ts.map +1 -1
  197. package/lib/network/processor/index.js +26 -25
  198. package/lib/network/processor/index.js.map +1 -1
  199. package/lib/node/nodejs.d.ts +1 -1
  200. package/lib/node/nodejs.d.ts.map +1 -1
  201. package/lib/node/nodejs.js +10 -2
  202. package/lib/node/nodejs.js.map +1 -1
  203. package/lib/node/options.d.ts +1 -1
  204. package/lib/node/options.d.ts.map +1 -1
  205. package/lib/node/options.js +1 -1
  206. package/lib/node/options.js.map +1 -1
  207. package/lib/sync/interface.d.ts.map +1 -1
  208. package/lib/sync/interface.js.map +1 -1
  209. package/lib/sync/sync.d.ts +7 -0
  210. package/lib/sync/sync.d.ts.map +1 -1
  211. package/lib/sync/sync.js +61 -3
  212. package/lib/sync/sync.js.map +1 -1
  213. package/lib/sync/unknownBlock.d.ts.map +1 -1
  214. package/lib/sync/unknownBlock.js +42 -18
  215. package/lib/sync/unknownBlock.js.map +1 -1
  216. package/lib/util/queue/itemQueue.js +1 -1
  217. package/lib/util/queue/itemQueue.js.map +1 -1
  218. package/lib/util/sszBytes.js +2 -2
  219. package/lib/util/sszBytes.js.map +1 -1
  220. package/package.json +31 -32
  221. package/src/api/impl/api.ts +1 -1
  222. package/src/api/impl/beacon/blocks/index.ts +57 -62
  223. package/src/api/impl/beacon/index.ts +3 -1
  224. package/src/api/impl/beacon/pool/index.ts +5 -1
  225. package/src/api/impl/beacon/state/utils.ts +1 -1
  226. package/src/api/impl/validator/index.ts +11 -8
  227. package/src/api/options.ts +3 -0
  228. package/src/chain/GetBlobsTracker.ts +97 -38
  229. package/src/chain/archiveStore/archiveStore.ts +1 -0
  230. package/src/chain/archiveStore/utils/archiveBlocks.ts +76 -130
  231. package/src/chain/blocks/importBlock.ts +8 -7
  232. package/src/chain/blocks/importExecutionPayload.ts +14 -3
  233. package/src/chain/blocks/index.ts +6 -2
  234. package/src/chain/blocks/payloadEnvelopeProcessor.ts +7 -7
  235. package/src/chain/blocks/verifyBlock.ts +1 -0
  236. package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -1
  237. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +16 -6
  238. package/src/chain/bls/multithread/index.ts +5 -5
  239. package/src/chain/bls/multithread/types.ts +1 -1
  240. package/src/chain/bls/multithread/worker.ts +1 -5
  241. package/src/chain/bls/singleThread.ts +1 -1
  242. package/src/chain/bls/utils.ts +1 -1
  243. package/src/chain/chain.ts +5 -5
  244. package/src/chain/errors/blockError.ts +1 -1
  245. package/src/chain/interface.ts +2 -3
  246. package/src/chain/opPools/aggregatedAttestationPool.ts +25 -9
  247. package/src/chain/opPools/attestationPool.ts +16 -4
  248. package/src/chain/opPools/inclusionListStore.ts +3 -3
  249. package/src/chain/opPools/payloadAttestationPool.ts +18 -7
  250. package/src/chain/opPools/syncCommitteeMessagePool.ts +10 -3
  251. package/src/chain/opPools/syncContributionAndProofPool.ts +13 -3
  252. package/src/chain/opPools/utils.ts +1 -1
  253. package/src/chain/options.ts +0 -2
  254. package/src/chain/produceBlock/produceBlockBody.ts +0 -1
  255. package/src/chain/regen/interface.ts +0 -1
  256. package/src/chain/validation/executionPayloadBid.ts +14 -193
  257. package/src/chain/validation/inclusionList.ts +11 -2
  258. package/src/db/beacon.ts +44 -0
  259. package/src/db/dataColumnStore.ts +2 -4
  260. package/src/db/interface.ts +2 -0
  261. package/src/db/repositories/dataColumnSidecarArchive.ts +20 -0
  262. package/src/execution/engine/blobVersionedHashes.ts +1 -1
  263. package/src/execution/engine/http.ts +0 -1
  264. package/src/execution/engine/index.ts +1 -1
  265. package/src/execution/engine/interface.ts +1 -1
  266. package/src/execution/engine/mock.ts +6 -4
  267. package/src/execution/engine/payloadIdCache.ts +6 -7
  268. package/src/execution/engine/types.ts +11 -9
  269. package/src/index.ts +2 -0
  270. package/src/metrics/metrics/lodestar.ts +10 -0
  271. package/src/monitoring/service.ts +1 -1
  272. package/src/network/core/networkCore.ts +5 -0
  273. package/src/network/core/networkCoreWorker.ts +1 -0
  274. package/src/network/core/networkCoreWorkerHandler.ts +4 -0
  275. package/src/network/core/types.ts +2 -0
  276. package/src/network/interface.ts +2 -0
  277. package/src/network/network.ts +8 -1
  278. package/src/network/peers/peerManager.ts +1 -1
  279. package/src/network/peers/utils/assertPeerRelevance.ts +39 -23
  280. package/src/network/processor/gossipHandlers.ts +41 -25
  281. package/src/network/processor/index.ts +22 -23
  282. package/src/network/processor/types.ts +1 -1
  283. package/src/node/nodejs.ts +24 -7
  284. package/src/node/options.ts +4 -5
  285. package/src/sync/interface.ts +1 -0
  286. package/src/sync/sync.ts +65 -4
  287. package/src/sync/unknownBlock.ts +47 -28
  288. package/src/util/queue/itemQueue.ts +1 -1
  289. package/src/util/sszBytes.ts +2 -2
@@ -15,6 +15,8 @@ const SLOT_BYTE_SIZE = 8;
15
15
  * Indexed data by `slot` + `columnIndex`
16
16
  */
17
17
  export class DataColumnSidecarArchiveRepository extends PrefixedRepository<Slot, ColumnIndex, DataColumnSidecar> {
18
+ private prunedBeforeSlot: Slot | null = null;
19
+
18
20
  constructor(config: ChainForkConfig, db: Db) {
19
21
  const bucket = Bucket.allForks_dataColumnSidecarsArchive;
20
22
  // Type won't be used since we select it dynamically based on fork
@@ -70,4 +72,22 @@ export class DataColumnSidecarArchiveRepository extends PrefixedRepository<Slot,
70
72
  encodeNumberForDbKey(0, COLUMN_INDEX_BYTE_SIZE),
71
73
  ]);
72
74
  }
75
+
76
+ /**
77
+ * Deletes all entries before `slot`. Prunes only delete from the start of the bucket, so the first prune
78
+ * compacts the range to drop tombstones of earlier runs and later prunes resume where the previous one ended.
79
+ */
80
+ async pruneBefore(slot: Slot): Promise<Slot[]> {
81
+ if (this.prunedBeforeSlot === null) {
82
+ await this.db.compactRange(this.wrapKey(this.getMinKeyRaw(0)), this.wrapKey(this.getMinKeyRaw(slot)));
83
+ } else if (slot <= this.prunedBeforeSlot) {
84
+ return [];
85
+ }
86
+
87
+ const keys = await this.keys({gte: {prefix: this.prunedBeforeSlot ?? 0, id: 0}, lt: {prefix: slot, id: 0}});
88
+ const slots = [...new Set(keys.map(({prefix}) => prefix))];
89
+ if (slots.length > 0) await this.deleteMany(slots);
90
+ this.prunedBeforeSlot = slot;
91
+ return slots;
92
+ }
73
93
  }
@@ -7,7 +7,7 @@ import {VersionedHashes} from "./interface.js";
7
7
  * Skip unrelated fields without decoding or copying them, including untrusted nested access lists.
8
8
  * The EL remains responsible for the other transaction validity checks.
9
9
  */
10
- export function isValidBlobVersionedHashes(transactions: Uint8Array[], expected: VersionedHashes): boolean {
10
+ export function isValidBlobVersionedHashes(transactions: Iterable<Uint8Array>, expected: VersionedHashes): boolean {
11
11
  let index = 0;
12
12
  for (const transaction of transactions) {
13
13
  if (transaction.length === 0) return false;
@@ -367,7 +367,6 @@ export class ExecutionEngineHttp implements IExecutionEngine {
367
367
  this.payloadIdCache.add(
368
368
  {
369
369
  headBlockHash,
370
- finalizedBlockHash,
371
370
  ...payloadAttributesRpc,
372
371
  inclusionListTransactions: payloadAttributes.inclusionListTransactions,
373
372
  },
@@ -17,8 +17,8 @@ import {EngineRestHttpClient} from "./restHttpClient.js";
17
17
  import {RestEngineTransport, formatClientVersionHeader} from "./restTransport.js";
18
18
  import {ExecutionEngineMockJsonRpcClient, JsonRpcBackend} from "./utils.js";
19
19
 
20
- export {ExecutionEngineHttp, ExecutionEngineDisabled, defaultExecutionEngineHttpOpts, engineApiModes};
21
20
  export type {EngineApiMode};
21
+ export {ExecutionEngineDisabled, ExecutionEngineHttp, defaultExecutionEngineHttpOpts, engineApiModes};
22
22
 
23
23
  export type ExecutionEngineOpts =
24
24
  | ({mode?: "http"} & ExecutionEngineHttpOpts)
@@ -25,7 +25,7 @@ import {PayloadId, PayloadIdCache, WithdrawalV1} from "./payloadIdCache.js";
25
25
  import {ExecutionPayloadBodyV2} from "./types.js";
26
26
  import {DATA} from "./utils.js";
27
27
 
28
- export {PayloadIdCache, type PayloadId, type WithdrawalV1};
28
+ export {type PayloadId, PayloadIdCache, type WithdrawalV1};
29
29
  export type ClientVersion = routes.node.ClientVersion;
30
30
  export const ClientCode = routes.node.ClientCode;
31
31
 
@@ -1,4 +1,5 @@
1
1
  import crypto from "node:crypto";
2
+ import {SerializedList} from "@chainsafe/ssz";
2
3
  import {ChainConfig} from "@lodestar/config";
3
4
  import {
4
5
  BLOB_TX_TYPE,
@@ -352,14 +353,14 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
352
353
  executionPayload.gasUsed = Math.floor(0.5 * INTEROP_GAS_LIMIT);
353
354
  executionPayload.timestamp = payloadAttributes.timestamp;
354
355
  executionPayload.blockHash = crypto.randomBytes(32);
355
- executionPayload.transactions = [];
356
+ const transactions: Uint8Array[] = [];
356
357
 
357
358
  // Between 0 and 4 transactions for all forks
358
359
  const eip1559TxCount = Math.round(4 * Math.random());
359
360
  for (let i = 0; i < eip1559TxCount; i++) {
360
361
  const tx = crypto.randomBytes(512);
361
362
  tx[0] = TX_TYPE_EIP1559;
362
- executionPayload.transactions.push(tx);
363
+ transactions.push(tx);
363
364
  }
364
365
 
365
366
  const commitments: deneb.KZGCommitment[] = [];
@@ -373,7 +374,7 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
373
374
  const blob = generateRandomBlob();
374
375
  const commitment = kzg.blobToKzgCommitment(blob);
375
376
  const {proofs: cellProofs} = kzg.computeCellsAndKzgProofs(blob);
376
- executionPayload.transactions.push(transactionForKzgCommitment(commitment));
377
+ transactions.push(transactionForKzgCommitment(commitment));
377
378
  commitments.push(commitment);
378
379
  blobs.push(blob);
379
380
  proofs.push(...cellProofs);
@@ -385,12 +386,13 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
385
386
  const blob = generateRandomBlob();
386
387
  const commitment = kzg.blobToKzgCommitment(blob);
387
388
  const proof = kzg.computeBlobKzgProof(blob, commitment);
388
- executionPayload.transactions.push(transactionForKzgCommitment(commitment));
389
+ transactions.push(transactionForKzgCommitment(commitment));
389
390
  commitments.push(commitment);
390
391
  blobs.push(blob);
391
392
  proofs.push(proof);
392
393
  }
393
394
  }
395
+ executionPayload.transactions = SerializedList.fromArray(transactions);
394
396
 
395
397
  if (ForkSeq[fork] >= ForkSeq.capella) {
396
398
  (executionPayload as ExecutionPayload<ForkPostCapella>).withdrawals = ssz.capella.Withdrawals.defaultValue();
@@ -19,10 +19,9 @@ export type WithdrawalV1 = {
19
19
  amount: QUANTITY;
20
20
  };
21
21
 
22
- type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit<
23
- PayloadAttributesRpc,
24
- "withdrawals" | "inclusionListTransactions"
25
- > & {inclusionListTransactions?: bellatrix.Transactions};
22
+ type FcuAttributes = {headBlockHash: DATA} & Omit<PayloadAttributesRpc, "withdrawals" | "inclusionListTransactions"> & {
23
+ inclusionListTransactions?: bellatrix.Transactions;
24
+ };
26
25
 
27
26
  export class PayloadIdCache {
28
27
  private readonly payloadIdByFcuAttributes = new Map<
@@ -30,8 +29,8 @@ export class PayloadIdCache {
30
29
  {payloadId: PayloadId; fullKey: string; inclusionListTransactions?: bellatrix.Transactions}
31
30
  >();
32
31
 
33
- getFullKey({headBlockHash, finalizedBlockHash, timestamp, prevRandao, suggestedFeeRecipient}: FcuAttributes): string {
34
- return `${headBlockHash}-${finalizedBlockHash}-${timestamp}-${prevRandao}-${suggestedFeeRecipient}`;
32
+ getFullKey({headBlockHash, timestamp, prevRandao, suggestedFeeRecipient}: FcuAttributes): string {
33
+ return `${headBlockHash}-${timestamp}-${prevRandao}-${suggestedFeeRecipient}`;
35
34
  }
36
35
  getKey({timestamp}: Pick<FcuAttributes, "timestamp">): string {
37
36
  return timestamp;
@@ -69,5 +68,5 @@ function isSameInclusionList(a?: bellatrix.Transactions, b?: bellatrix.Transacti
69
68
  if (a === undefined || b === undefined) {
70
69
  return a === b;
71
70
  }
72
- return a.length === b.length && a.every((transaction, i) => byteArrayEquals(transaction, b[i]));
71
+ return byteArrayEquals(a.bytes, b.bytes);
73
72
  }
@@ -1,4 +1,4 @@
1
- import {Type} from "@chainsafe/ssz";
1
+ import {SerializedList, Type} from "@chainsafe/ssz";
2
2
  import {
3
3
  BUILDER_DEPOSIT_REQUEST_TYPE,
4
4
  BUILDER_EXIT_REQUEST_TYPE,
@@ -9,6 +9,7 @@ import {
9
9
  DEPOSIT_REQUEST_TYPE,
10
10
  FIELD_ELEMENTS_PER_BLOB,
11
11
  ForkName,
12
+ ForkPostElectra,
12
13
  ForkSeq,
13
14
  WITHDRAWAL_REQUEST_TYPE,
14
15
  } from "@lodestar/params";
@@ -23,6 +24,7 @@ import {
23
24
  deneb,
24
25
  gloas,
25
26
  ssz,
27
+ sszTypesFor,
26
28
  } from "@lodestar/types";
27
29
  import {BlobAndProof} from "@lodestar/types/deneb";
28
30
  import {BlobAndProofV2} from "@lodestar/types/fulu";
@@ -181,7 +183,7 @@ export type ExecutionPayloadBodyRpc = {
181
183
  };
182
184
 
183
185
  export type ExecutionPayloadBody = {
184
- transactions: bellatrix.Transaction[];
186
+ transactions: bellatrix.Transactions;
185
187
  withdrawals: capella.Withdrawals | null;
186
188
  };
187
189
 
@@ -316,7 +318,7 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload
316
318
  extraData: bytesToData(data.extraData),
317
319
  baseFeePerGas: numToQuantity(data.baseFeePerGas),
318
320
  blockHash: bytesToData(data.blockHash),
319
- transactions: data.transactions.map((tran) => bytesToData(tran)),
321
+ transactions: Array.from(data.transactions, (tran) => bytesToData(tran)),
320
322
  };
321
323
 
322
324
  // Capella adds withdrawals to the ExecutionPayload
@@ -400,7 +402,7 @@ export function parseExecutionPayload(
400
402
  extraData: dataToBytes(data.extraData, null),
401
403
  baseFeePerGas: quantityToBigint(data.baseFeePerGas),
402
404
  blockHash: dataToBytes(data.blockHash, 32),
403
- transactions: data.transactions.map((tran) => dataToBytes(tran, null)),
405
+ transactions: SerializedList.fromArray(data.transactions.map((tran) => dataToBytes(tran, null))),
404
406
  };
405
407
 
406
408
  if (ForkSeq[fork] >= ForkSeq.capella) {
@@ -474,11 +476,11 @@ export function serializeBeaconBlockRoot(data: Root): DATA {
474
476
  }
475
477
 
476
478
  export function serializeInclusionList(data: bellatrix.Transactions): InclusionListRpc {
477
- return data.map((transaction) => bytesToData(transaction));
479
+ return Array.from(data, (transaction) => bytesToData(transaction));
478
480
  }
479
481
 
480
482
  export function deserializeInclusionList(data: InclusionListRpc): bellatrix.Transactions {
481
- return data.map((transaction) => dataToBytes(transaction, null));
483
+ return SerializedList.fromArray(data.map((transaction) => dataToBytes(transaction, null)));
482
484
  }
483
485
 
484
486
  export function deserializePayloadAttributes(data: PayloadAttributesRpc): PayloadAttributes {
@@ -628,7 +630,7 @@ export function deserializeExecutionRequestsFromBytes(fork: ForkName, serialized
628
630
 
629
631
  switch (currentRequestType) {
630
632
  case DEPOSIT_REQUEST_TYPE: {
631
- result.deposits = ssz.electra.DepositRequests.deserialize(requests);
633
+ result.deposits = sszTypesFor(fork as ForkPostElectra).DepositRequests.deserialize(requests);
632
634
  break;
633
635
  }
634
636
  case WITHDRAWAL_REQUEST_TYPE: {
@@ -670,7 +672,7 @@ export function deserializeExecutionRequests(fork: ForkName, serialized: Executi
670
672
  export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null {
671
673
  return data
672
674
  ? {
673
- transactions: data.transactions.map((tran) => dataToBytes(tran, null)),
675
+ transactions: SerializedList.fromArray(data.transactions.map((tran) => dataToBytes(tran, null))),
674
676
  withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null,
675
677
  }
676
678
  : null;
@@ -693,7 +695,7 @@ export function serializeExecutionPayloadBodyV2(data: ExecutionPayloadBodyV2 | n
693
695
  export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null): ExecutionPayloadBodyRpc | null {
694
696
  return data
695
697
  ? {
696
- transactions: data.transactions.map((tran) => bytesToData(tran)),
698
+ transactions: Array.from(data.transactions, (tran) => bytesToData(tran)),
697
699
  withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null,
698
700
  }
699
701
  : null;
package/src/index.ts CHANGED
@@ -6,6 +6,8 @@ export {persistAnchorState} from "./chain/index.js";
6
6
  export {DbCPStateDatastore} from "./chain/stateCache/datastore/db.js";
7
7
  export {FileCPStateDatastore} from "./chain/stateCache/datastore/file.js";
8
8
  export {BeaconDb, type IBeaconDb} from "./db/index.js";
9
+ // Export execution engine to make it usable by builder
10
+ export {initializeExecutionEngine} from "./execution/index.js";
9
11
  // Export metrics utilities to de-duplicate validator metrics
10
12
  export {
11
13
  type HttpMetricsServer,
@@ -645,6 +645,11 @@ export function createLodestarMetrics(
645
645
  help: "Count of peers by sync type [FullySynced, Advanced, Behind]",
646
646
  labelNames: ["syncType"],
647
647
  }),
648
+ syncPeerFinalizedCheckpointMismatch: register.counter<{reason: string}>({
649
+ name: "lodestar_sync_peer_finalized_checkpoint_mismatch_total",
650
+ help: "Total behind peers whose Status finalized checkpoint is not in our chain, by reason",
651
+ labelNames: ["reason"],
652
+ }),
648
653
  syncSwitchGossipSubscriptions: register.gauge<{action: string}>({
649
654
  name: "lodestar_sync_switch_gossip_subscriptions",
650
655
  help: "Sync switched gossip subscriptions on/off",
@@ -1474,6 +1479,11 @@ export function createLodestarMetrics(
1474
1479
  help: "Total number of InsertOutcome as a result of adding an execution payload bid from gossip to the pool",
1475
1480
  labelNames: ["insertOutcome"],
1476
1481
  }),
1482
+ apiInsertOutcome: register.counter<{insertOutcome: InsertOutcome}>({
1483
+ name: "lodestar_oppool_execution_payload_bid_pool_api_insert_outcome_total",
1484
+ help: "Total number of InsertOutcome as a result of adding an execution payload bid from api to the pool",
1485
+ labelNames: ["insertOutcome"],
1486
+ }),
1477
1487
  apiValidationTime: register.histogram({
1478
1488
  name: "lodestar_api_execution_payload_bid_validation_time_seconds",
1479
1489
  help: "Time elapsed for signed execution payload bid validation - api path",
@@ -101,7 +101,7 @@ export class MonitoringService {
101
101
  if (this.monitoringInterval) {
102
102
  clearTimeout(this.monitoringInterval);
103
103
  }
104
- if (this.pendingRequest) {
104
+ if (this.pendingRequest !== undefined) {
105
105
  this.fetchAbortController?.abort(FetchAbortReason.Close);
106
106
  await this.pendingRequest;
107
107
  }
@@ -10,6 +10,7 @@ import {isForkPostFulu} from "@lodestar/params";
10
10
  import {ResponseIncoming} from "@lodestar/reqresp";
11
11
  import {Epoch, Status, fulu, sszTypesFor} from "@lodestar/types";
12
12
  import {formatNodePeer} from "../../api/impl/node/utils.js";
13
+ import {GoodByeReasonCode} from "../../constants/index.js";
13
14
  import {RegistryMetricCreator} from "../../metrics/index.js";
14
15
  import {ClockEvent, IClock} from "../../util/clock.js";
15
16
  import {CustodyConfig} from "../../util/dataColumns.js";
@@ -332,6 +333,10 @@ export class NetworkCore implements INetworkCore {
332
333
  this.peerManager.reStatusPeers(peers);
333
334
  }
334
335
 
336
+ async goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void> {
337
+ await this.peerManager.goodbyeAndDisconnect(peerIdFromString(peer), reason);
338
+ }
339
+
335
340
  /**
336
341
  * Request att subnets up `toSlot`. Network will ensure to mantain some peers for each
337
342
  */
@@ -138,6 +138,7 @@ const libp2pWorkerApi: NetworkWorkerApi = {
138
138
  prepareSyncCommitteeSubnets: (subscriptions) => core.prepareSyncCommitteeSubnets(subscriptions),
139
139
  reportPeer: (peer, action, actionName) => core.reportPeer(peer, action, actionName),
140
140
  reStatusPeers: (peers) => core.reStatusPeers(peers),
141
+ goodbyeAndDisconnect: (peer, reason) => core.goodbyeAndDisconnect(peer, reason),
141
142
  subscribeGossipCoreTopics: () => core.subscribeGossipCoreTopics(),
142
143
  unsubscribeGossipCoreTopics: () => core.unsubscribeGossipCoreTopics(),
143
144
 
@@ -11,6 +11,7 @@ import type {LoggerNode} from "@lodestar/logger/node";
11
11
  import {ResponseIncoming, ResponseOutgoing} from "@lodestar/reqresp";
12
12
  import {Status} from "@lodestar/types";
13
13
  import {withTimeout} from "@lodestar/utils";
14
+ import {GoodByeReasonCode} from "../../constants/index.js";
14
15
  import {Metrics} from "../../metrics/index.js";
15
16
  import {AsyncIterableBridgeCaller, AsyncIterableBridgeHandler} from "../../util/asyncIterableToEvents.js";
16
17
  import {PeerIdStr, peerIdFromString} from "../../util/peerId.js";
@@ -205,6 +206,9 @@ export class WorkerNetworkCore implements INetworkCore {
205
206
  reStatusPeers(peers: PeerIdStr[]): Promise<void> {
206
207
  return this.getApi().reStatusPeers(peers);
207
208
  }
209
+ goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void> {
210
+ return this.getApi().goodbyeAndDisconnect(peer, reason);
211
+ }
208
212
  reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): Promise<void> {
209
213
  return this.getApi().reportPeer(peer, action, actionName);
210
214
  }
@@ -5,6 +5,7 @@ import {SpecJson} from "@lodestar/config";
5
5
  import {LoggerNodeOpts} from "@lodestar/logger/node";
6
6
  import {ResponseIncoming} from "@lodestar/reqresp";
7
7
  import {Status} from "@lodestar/types";
8
+ import {GoodByeReasonCode} from "../../constants/index.js";
8
9
  import {PeerIdStr} from "../../util/peerId.js";
9
10
  import {NetworkOptions} from "../options.js";
10
11
  import {PeerAction, PeerScoreStats} from "../peers/index.js";
@@ -53,6 +54,7 @@ export interface INetworkCore extends INetworkCorePublic {
53
54
  // Sync method
54
55
  reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): void;
55
56
  reStatusPeers(peers: PeerIdStr[]): Promise<void>;
57
+ goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void>;
56
58
 
57
59
  // TODO: Duplicated methods with INetwork interface
58
60
  getConnectedPeers(): Promise<PeerIdStr[]>;
@@ -37,6 +37,7 @@ import {
37
37
  phase0,
38
38
  } from "@lodestar/types";
39
39
  import {BlockInputSource} from "../chain/blocks/blockInput/types.js";
40
+ import {GoodByeReasonCode} from "../constants/index.js";
40
41
  import {CustodyConfig} from "../util/dataColumns.js";
41
42
  import {PeerIdStr} from "../util/peerId.js";
42
43
  import {
@@ -74,6 +75,7 @@ export interface INetwork extends INetworkCorePublic {
74
75
  reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): void;
75
76
  shouldAggregate(subnet: SubnetID, slot: Slot): boolean;
76
77
  reStatusPeers(peers: PeerIdStr[]): Promise<void>;
78
+ goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void>;
77
79
  searchUnknownBlock(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void;
78
80
  searchUnknownEnvelope(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void;
79
81
  // ReqResp
@@ -34,6 +34,7 @@ import {prettyPrintIndices, sleep} from "@lodestar/utils";
34
34
  import {BlockInputSource} from "../chain/blocks/blockInput/types.js";
35
35
  import {ChainEvent, IBeaconChain} from "../chain/index.js";
36
36
  import {computeSubnetForDataColumnSidecar} from "../chain/validation/dataColumnSidecar.js";
37
+ import {GoodByeReasonCode} from "../constants/index.js";
37
38
  import {IBeaconDb} from "../db/interface.js";
38
39
  import {Metrics, RegistryMetricCreator} from "../metrics/index.js";
39
40
  import {IClock} from "../util/clock.js";
@@ -289,6 +290,10 @@ export class Network implements INetwork {
289
290
  return this.core.reStatusPeers(peers);
290
291
  }
291
292
 
293
+ async goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void> {
294
+ return this.core.goodbyeAndDisconnect(peer, reason);
295
+ }
296
+
292
297
  searchUnknownBlock(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
293
298
  this.networkProcessor.searchUnknownBlock(slotRoot, source, peer);
294
299
  }
@@ -855,7 +860,9 @@ export class Network implements INetwork {
855
860
  };
856
861
 
857
862
  private onTargetGroupCountUpdated = (count: number): void => {
858
- this.core.setTargetGroupCount(count);
863
+ this.core.setTargetGroupCount(count).catch((e) => {
864
+ this.logger.debug("Error setting target custody group count", {count}, e as Error);
865
+ });
859
866
  };
860
867
 
861
868
  private onPublishDataColumns = async (sidecars: DataColumnSidecar[]): Promise<void> => {
@@ -893,7 +893,7 @@ export class PeerManager {
893
893
  }
894
894
  }
895
895
 
896
- private async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
896
+ async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
897
897
  const reason = GOODBYE_KNOWN_CODES[goodbye.toString()] || "";
898
898
  const peerIdStr = peer.toString();
899
899
  try {
@@ -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,
@@ -150,6 +151,31 @@ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipH
150
151
  */
151
152
  function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): SequentialGossipHandlers {
152
153
  const {chain, config, metrics, logger, core} = modules;
154
+ const incompletePayloadWaits = new WeakSet<PayloadEnvelopeInput>();
155
+
156
+ function scheduleIncompletePayloadEnvelope(payloadInput: PayloadEnvelopeInput, peer: string): void {
157
+ if (payloadInput.isComplete() || incompletePayloadWaits.has(payloadInput)) {
158
+ return;
159
+ }
160
+ incompletePayloadWaits.add(payloadInput);
161
+
162
+ const fork = config.getForkName(payloadInput.slot);
163
+ const cutoffTimeMs = getCutoffTimeMs(chain, payloadInput.slot, config.getPayloadDueMs(fork));
164
+ payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch(() => {
165
+ if (
166
+ payloadInput.isComplete() ||
167
+ chain.seenPayloadEnvelopeInputCache.get(payloadInput.blockRootHex) !== payloadInput
168
+ ) {
169
+ return;
170
+ }
171
+ chain.logger.debug("Payload envelope incomplete at payload deadline", payloadInput.getLogMeta());
172
+ chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
173
+ payloadInput,
174
+ peer,
175
+ source: BlockInputSource.gossip,
176
+ });
177
+ });
178
+ }
153
179
 
154
180
  /**
155
181
  * Add a gossip block to the seen caches. The proposer signature of the block MUST be verified.
@@ -679,8 +705,6 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
679
705
 
680
706
  // Immediately attempt fetch of data columns from execution engine as the bid contains kzg commitments
681
707
  // which is all the information we need so there is no reason to delay until execution payload arrives
682
- // TODO GLOAS: If we want EL retries after this initial attempt, add an explicit retry policy here
683
- // (for example later in the slot). Do not couple retries to incoming gossip columns.
684
708
  // Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
685
709
  // in-flight importExecutionPayload. No processExecutionPayload trigger needed from this path.
686
710
  chain.getBlobsTracker.triggerGetBlobs(payloadInput);
@@ -692,11 +716,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
692
716
 
693
717
  if (e instanceof BlockError) {
694
718
  switch (e.type.code) {
695
- case BlockErrorCode.DATA_UNAVAILABLE: {
696
- // 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
697
721
  logLevel = LogLevel.debug;
698
722
  break;
699
- }
700
723
  // ALREADY_KNOWN should not happen with ignoreIfKnown=true above
701
724
  // PARENT_BLOCK_UNKNOWN should not happen, we handled this in validateBeaconBlock() function above
702
725
  case BlockErrorCode.ALREADY_KNOWN:
@@ -764,7 +787,12 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
764
787
  // roots per proposer and slot, which bounds full imports over gossip to one alternate
765
788
  chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root) &&
766
789
  // A sibling with an unknown parent cannot be imported, sync fetches it if its branch becomes relevant
767
- 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)
768
796
  ) {
769
797
  const blockInput = cacheSignatureVerifiedBlock(
770
798
  signedBlock,
@@ -902,25 +930,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
902
930
  // envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
903
931
  // payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
904
932
 
905
- if (!payloadInput.isComplete()) {
906
- const cutoffTimeMs = getCutoffTimeMs(chain, dataColumnSlot, BLOCK_AVAILABILITY_CUTOFF_MS);
907
- // do not await here to not delay gossip validation
908
- payloadInput.waitForEnvelopeAndAllData(cutoffTimeMs).catch((_e) => {
909
- chain.logger.debug(
910
- "Waited for envelope and data after receiving gossip column. Cut-off reached so emitting incompletePayloadEnvelope",
911
- {
912
- dataColumnIndex: index,
913
- ...payloadInputMeta,
914
- }
915
- );
916
- // TODO GLOAS: UnknownBlockSync to handle this event
917
- chain.emitter.emit(ChainEvent.incompletePayloadEnvelope, {
918
- payloadInput,
919
- peer: peerIdStr,
920
- source: BlockInputSource.gossip,
921
- });
922
- });
923
- }
933
+ scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
924
934
  } catch (e) {
925
935
  logger.debug(
926
936
  "Error handling gossip data column",
@@ -1330,6 +1340,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1330
1340
  peerIdStr,
1331
1341
  });
1332
1342
 
1343
+ scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
1344
+
1333
1345
  chain.emitter.emit(routes.events.EventType.executionPayloadGossip, {
1334
1346
  slot,
1335
1347
  builderIndex: envelope.builderIndex,
@@ -1343,6 +1355,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1343
1355
 
1344
1356
  if (e instanceof PayloadError) {
1345
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;
1346
1362
  // BLOCK_NOT_IN_FORK_CHOICE should not happen, validateGossipExecutionPayloadEnvelope above
1347
1363
  // already verified the block is in fork choice
1348
1364
  case PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE: