@lodestar/beacon-node 1.51.0-dev.c99cf49add → 1.51.0-dev.d2b5232209

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 (297) 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 +12 -7
  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/state/index.d.ts.map +1 -1
  12. package/lib/api/impl/beacon/state/index.js +8 -2
  13. package/lib/api/impl/beacon/state/index.js.map +1 -1
  14. package/lib/api/impl/beacon/state/utils.d.ts +2 -1
  15. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  16. package/lib/api/impl/beacon/state/utils.js +17 -9
  17. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  18. package/lib/api/impl/debug/index.d.ts.map +1 -1
  19. package/lib/api/impl/debug/index.js +3 -0
  20. package/lib/api/impl/debug/index.js.map +1 -1
  21. package/lib/api/impl/validator/index.d.ts.map +1 -1
  22. package/lib/api/impl/validator/index.js +105 -10
  23. package/lib/api/impl/validator/index.js.map +1 -1
  24. package/lib/api/options.d.ts +2 -0
  25. package/lib/api/options.d.ts.map +1 -1
  26. package/lib/api/options.js +1 -0
  27. package/lib/api/options.js.map +1 -1
  28. package/lib/chain/ColumnReconstructionTracker.d.ts +11 -11
  29. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  30. package/lib/chain/ColumnReconstructionTracker.js +46 -40
  31. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  32. package/lib/chain/GetBlobsTracker.d.ts +11 -0
  33. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  34. package/lib/chain/GetBlobsTracker.js +83 -27
  35. package/lib/chain/GetBlobsTracker.js.map +1 -1
  36. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +4 -0
  37. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  38. package/lib/chain/archiveStore/utils/archiveBlocks.js +61 -97
  39. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  40. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  41. package/lib/chain/blocks/importBlock.js +9 -7
  42. package/lib/chain/blocks/importBlock.js.map +1 -1
  43. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  44. package/lib/chain/blocks/importExecutionPayload.js +51 -3
  45. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  46. package/lib/chain/blocks/index.js +2 -2
  47. package/lib/chain/blocks/index.js.map +1 -1
  48. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -5
  49. package/lib/chain/blocks/payloadEnvelopeProcessor.js +5 -5
  50. package/lib/chain/blocks/types.d.ts +4 -0
  51. package/lib/chain/blocks/types.d.ts.map +1 -1
  52. package/lib/chain/blocks/types.js +5 -0
  53. package/lib/chain/blocks/types.js.map +1 -1
  54. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  55. package/lib/chain/blocks/verifyBlock.js +1 -1
  56. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  57. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +3 -3
  58. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  59. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +6 -6
  60. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  61. package/lib/chain/chain.d.ts +2 -1
  62. package/lib/chain/chain.d.ts.map +1 -1
  63. package/lib/chain/chain.js +9 -5
  64. package/lib/chain/chain.js.map +1 -1
  65. package/lib/chain/errors/executionPayloadBid.d.ts +11 -1
  66. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  67. package/lib/chain/errors/executionPayloadBid.js +2 -0
  68. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  69. package/lib/chain/errors/inclusionList.d.ts +60 -0
  70. package/lib/chain/errors/inclusionList.d.ts.map +1 -0
  71. package/lib/chain/errors/inclusionList.js +19 -0
  72. package/lib/chain/errors/inclusionList.js.map +1 -0
  73. package/lib/chain/errors/index.d.ts +1 -0
  74. package/lib/chain/errors/index.d.ts.map +1 -1
  75. package/lib/chain/errors/index.js +1 -0
  76. package/lib/chain/errors/index.js.map +1 -1
  77. package/lib/chain/interface.d.ts +2 -1
  78. package/lib/chain/interface.d.ts.map +1 -1
  79. package/lib/chain/interface.js.map +1 -1
  80. package/lib/chain/opPools/inclusionListStore.d.ts +63 -0
  81. package/lib/chain/opPools/inclusionListStore.d.ts.map +1 -0
  82. package/lib/chain/opPools/inclusionListStore.js +171 -0
  83. package/lib/chain/opPools/inclusionListStore.js.map +1 -0
  84. package/lib/chain/opPools/index.d.ts +1 -0
  85. package/lib/chain/opPools/index.d.ts.map +1 -1
  86. package/lib/chain/opPools/index.js +1 -0
  87. package/lib/chain/opPools/index.js.map +1 -1
  88. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -1
  89. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  90. package/lib/chain/produceBlock/produceBlockBody.js +30 -10
  91. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  92. package/lib/chain/regen/interface.d.ts +1 -1
  93. package/lib/chain/regen/interface.d.ts.map +1 -1
  94. package/lib/chain/regen/interface.js +1 -1
  95. package/lib/chain/regen/interface.js.map +1 -1
  96. package/lib/chain/validation/executionPayloadBid.d.ts +0 -15
  97. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  98. package/lib/chain/validation/executionPayloadBid.js +24 -145
  99. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  100. package/lib/chain/validation/inclusionList.d.ts +14 -0
  101. package/lib/chain/validation/inclusionList.d.ts.map +1 -0
  102. package/lib/chain/validation/inclusionList.js +150 -0
  103. package/lib/chain/validation/inclusionList.js.map +1 -0
  104. package/lib/chain/validation/index.d.ts +1 -0
  105. package/lib/chain/validation/index.d.ts.map +1 -1
  106. package/lib/chain/validation/index.js +1 -0
  107. package/lib/chain/validation/index.js.map +1 -1
  108. package/lib/db/beacon.d.ts +7 -0
  109. package/lib/db/beacon.d.ts.map +1 -1
  110. package/lib/db/beacon.js +34 -0
  111. package/lib/db/beacon.js.map +1 -1
  112. package/lib/db/dataColumnStore.d.ts +1 -1
  113. package/lib/db/dataColumnStore.d.ts.map +1 -1
  114. package/lib/db/dataColumnStore.js +1 -4
  115. package/lib/db/dataColumnStore.js.map +1 -1
  116. package/lib/db/interface.d.ts +1 -0
  117. package/lib/db/interface.d.ts.map +1 -1
  118. package/lib/db/repositories/dataColumnSidecarArchive.d.ts +6 -0
  119. package/lib/db/repositories/dataColumnSidecarArchive.d.ts.map +1 -1
  120. package/lib/db/repositories/dataColumnSidecarArchive.js +19 -0
  121. package/lib/db/repositories/dataColumnSidecarArchive.js.map +1 -1
  122. package/lib/execution/builder/validateBid.d.ts.map +1 -1
  123. package/lib/execution/builder/validateBid.js +14 -1
  124. package/lib/execution/builder/validateBid.js.map +1 -1
  125. package/lib/execution/engine/blobVersionedHashes.d.ts +1 -1
  126. package/lib/execution/engine/blobVersionedHashes.d.ts.map +1 -1
  127. package/lib/execution/engine/blobVersionedHashes.js.map +1 -1
  128. package/lib/execution/engine/disabled.d.ts +1 -0
  129. package/lib/execution/engine/disabled.d.ts.map +1 -1
  130. package/lib/execution/engine/disabled.js +3 -0
  131. package/lib/execution/engine/disabled.js.map +1 -1
  132. package/lib/execution/engine/http.d.ts +8 -2
  133. package/lib/execution/engine/http.d.ts.map +1 -1
  134. package/lib/execution/engine/http.js +27 -4
  135. package/lib/execution/engine/http.js.map +1 -1
  136. package/lib/execution/engine/interface.d.ts +11 -2
  137. package/lib/execution/engine/interface.d.ts.map +1 -1
  138. package/lib/execution/engine/interface.js.map +1 -1
  139. package/lib/execution/engine/jsonRpcTransport.d.ts +3 -2
  140. package/lib/execution/engine/jsonRpcTransport.d.ts.map +1 -1
  141. package/lib/execution/engine/jsonRpcTransport.js +33 -9
  142. package/lib/execution/engine/jsonRpcTransport.js.map +1 -1
  143. package/lib/execution/engine/mock.d.ts +1 -0
  144. package/lib/execution/engine/mock.d.ts.map +1 -1
  145. package/lib/execution/engine/mock.js +31 -7
  146. package/lib/execution/engine/mock.js.map +1 -1
  147. package/lib/execution/engine/payloadIdCache.d.ts +5 -3
  148. package/lib/execution/engine/payloadIdCache.d.ts.map +1 -1
  149. package/lib/execution/engine/payloadIdCache.js +15 -4
  150. package/lib/execution/engine/payloadIdCache.js.map +1 -1
  151. package/lib/execution/engine/restTransport.d.ts +2 -1
  152. package/lib/execution/engine/restTransport.d.ts.map +1 -1
  153. package/lib/execution/engine/restTransport.js +3 -0
  154. package/lib/execution/engine/restTransport.js.map +1 -1
  155. package/lib/execution/engine/sszTypes.d.ts +38 -38
  156. package/lib/execution/engine/transport.d.ts +5 -2
  157. package/lib/execution/engine/transport.d.ts.map +1 -1
  158. package/lib/execution/engine/types.d.ts +25 -1
  159. package/lib/execution/engine/types.d.ts.map +1 -1
  160. package/lib/execution/engine/types.js +17 -4
  161. package/lib/execution/engine/types.js.map +1 -1
  162. package/lib/index.d.ts +1 -0
  163. package/lib/index.d.ts.map +1 -1
  164. package/lib/index.js +2 -0
  165. package/lib/index.js.map +1 -1
  166. package/lib/metrics/metrics/beacon.d.ts +16 -0
  167. package/lib/metrics/metrics/beacon.d.ts.map +1 -1
  168. package/lib/metrics/metrics/beacon.js +35 -0
  169. package/lib/metrics/metrics/beacon.js.map +1 -1
  170. package/lib/metrics/metrics/lodestar.d.ts +19 -0
  171. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  172. package/lib/metrics/metrics/lodestar.js +49 -0
  173. package/lib/metrics/metrics/lodestar.js.map +1 -1
  174. package/lib/network/gossip/interface.d.ts +8 -2
  175. package/lib/network/gossip/interface.d.ts.map +1 -1
  176. package/lib/network/gossip/interface.js +1 -0
  177. package/lib/network/gossip/interface.js.map +1 -1
  178. package/lib/network/gossip/topic.d.ts +13 -5
  179. package/lib/network/gossip/topic.d.ts.map +1 -1
  180. package/lib/network/gossip/topic.js +13 -1
  181. package/lib/network/gossip/topic.js.map +1 -1
  182. package/lib/network/interface.d.ts +2 -1
  183. package/lib/network/interface.d.ts.map +1 -1
  184. package/lib/network/network.d.ts +2 -1
  185. package/lib/network/network.d.ts.map +1 -1
  186. package/lib/network/network.js +5 -0
  187. package/lib/network/network.js.map +1 -1
  188. package/lib/network/peers/utils/enrSubnetsDeserialize.d.ts.map +1 -1
  189. package/lib/network/peers/utils/enrSubnetsDeserialize.js +5 -2
  190. package/lib/network/peers/utils/enrSubnetsDeserialize.js.map +1 -1
  191. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  192. package/lib/network/processor/gossipHandlers.js +67 -19
  193. package/lib/network/processor/gossipHandlers.js.map +1 -1
  194. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  195. package/lib/network/processor/gossipQueues/index.js +6 -0
  196. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  197. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  198. package/lib/network/processor/gossipValidatorFn.js +5 -1
  199. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  200. package/lib/network/processor/index.d.ts +5 -0
  201. package/lib/network/processor/index.d.ts.map +1 -1
  202. package/lib/network/processor/index.js +37 -26
  203. package/lib/network/processor/index.js.map +1 -1
  204. package/lib/network/reqresp/ReqRespBeaconNode.d.ts.map +1 -1
  205. package/lib/network/reqresp/ReqRespBeaconNode.js +6 -0
  206. package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
  207. package/lib/network/reqresp/handlers/inclusionListsByIndices.d.ts +10 -0
  208. package/lib/network/reqresp/handlers/inclusionListsByIndices.d.ts.map +1 -0
  209. package/lib/network/reqresp/handlers/inclusionListsByIndices.js +30 -0
  210. package/lib/network/reqresp/handlers/inclusionListsByIndices.js.map +1 -0
  211. package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
  212. package/lib/network/reqresp/handlers/index.js +5 -0
  213. package/lib/network/reqresp/handlers/index.js.map +1 -1
  214. package/lib/network/reqresp/protocols.d.ts +1 -0
  215. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  216. package/lib/network/reqresp/protocols.js +5 -0
  217. package/lib/network/reqresp/protocols.js.map +1 -1
  218. package/lib/network/reqresp/rateLimit.d.ts.map +1 -1
  219. package/lib/network/reqresp/rateLimit.js +4 -0
  220. package/lib/network/reqresp/rateLimit.js.map +1 -1
  221. package/lib/network/reqresp/types.d.ts +5 -2
  222. package/lib/network/reqresp/types.d.ts.map +1 -1
  223. package/lib/network/reqresp/types.js +3 -0
  224. package/lib/network/reqresp/types.js.map +1 -1
  225. package/lib/node/nodejs.d.ts.map +1 -1
  226. package/lib/node/nodejs.js +9 -1
  227. package/lib/node/nodejs.js.map +1 -1
  228. package/lib/sync/unknownBlock.d.ts.map +1 -1
  229. package/lib/sync/unknownBlock.js +42 -18
  230. package/lib/sync/unknownBlock.js.map +1 -1
  231. package/package.json +30 -30
  232. package/src/api/impl/api.ts +1 -1
  233. package/src/api/impl/beacon/blocks/index.ts +22 -17
  234. package/src/api/impl/beacon/index.ts +3 -1
  235. package/src/api/impl/beacon/state/index.ts +10 -1
  236. package/src/api/impl/beacon/state/utils.ts +19 -9
  237. package/src/api/impl/debug/index.ts +4 -0
  238. package/src/api/impl/validator/index.ts +135 -10
  239. package/src/api/options.ts +3 -0
  240. package/src/chain/ColumnReconstructionTracker.ts +60 -41
  241. package/src/chain/GetBlobsTracker.ts +95 -38
  242. package/src/chain/archiveStore/utils/archiveBlocks.ts +76 -130
  243. package/src/chain/blocks/importBlock.ts +11 -14
  244. package/src/chain/blocks/importExecutionPayload.ts +69 -3
  245. package/src/chain/blocks/index.ts +6 -2
  246. package/src/chain/blocks/payloadEnvelopeProcessor.ts +5 -5
  247. package/src/chain/blocks/types.ts +5 -0
  248. package/src/chain/blocks/verifyBlock.ts +1 -0
  249. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -6
  250. package/src/chain/chain.ts +9 -4
  251. package/src/chain/errors/executionPayloadBid.ts +12 -0
  252. package/src/chain/errors/inclusionList.ts +38 -0
  253. package/src/chain/errors/index.ts +1 -0
  254. package/src/chain/interface.ts +2 -0
  255. package/src/chain/opPools/inclusionListStore.ts +208 -0
  256. package/src/chain/opPools/index.ts +1 -0
  257. package/src/chain/produceBlock/produceBlockBody.ts +60 -19
  258. package/src/chain/regen/interface.ts +1 -1
  259. package/src/chain/validation/executionPayloadBid.ts +40 -170
  260. package/src/chain/validation/inclusionList.ts +192 -0
  261. package/src/chain/validation/index.ts +1 -0
  262. package/src/db/beacon.ts +44 -0
  263. package/src/db/dataColumnStore.ts +2 -4
  264. package/src/db/interface.ts +2 -0
  265. package/src/db/repositories/dataColumnSidecarArchive.ts +20 -0
  266. package/src/execution/builder/validateBid.ts +23 -2
  267. package/src/execution/engine/blobVersionedHashes.ts +1 -1
  268. package/src/execution/engine/disabled.ts +4 -0
  269. package/src/execution/engine/http.ts +40 -5
  270. package/src/execution/engine/interface.ts +27 -3
  271. package/src/execution/engine/jsonRpcTransport.ts +46 -9
  272. package/src/execution/engine/mock.ts +32 -7
  273. package/src/execution/engine/payloadIdCache.ts +24 -6
  274. package/src/execution/engine/restTransport.ts +15 -1
  275. package/src/execution/engine/transport.ts +7 -2
  276. package/src/execution/engine/types.ts +41 -6
  277. package/src/index.ts +2 -0
  278. package/src/metrics/metrics/beacon.ts +37 -0
  279. package/src/metrics/metrics/lodestar.ts +51 -0
  280. package/src/network/gossip/interface.ts +5 -0
  281. package/src/network/gossip/topic.ts +14 -0
  282. package/src/network/interface.ts +2 -0
  283. package/src/network/network.ts +11 -0
  284. package/src/network/peers/utils/enrSubnetsDeserialize.ts +5 -2
  285. package/src/network/processor/gossipHandlers.ts +87 -21
  286. package/src/network/processor/gossipQueues/index.ts +6 -0
  287. package/src/network/processor/gossipValidatorFn.ts +5 -0
  288. package/src/network/processor/index.ts +33 -24
  289. package/src/network/processor/types.ts +1 -1
  290. package/src/network/reqresp/ReqRespBeaconNode.ts +7 -0
  291. package/src/network/reqresp/handlers/inclusionListsByIndices.ts +44 -0
  292. package/src/network/reqresp/handlers/index.ts +5 -0
  293. package/src/network/reqresp/protocols.ts +6 -0
  294. package/src/network/reqresp/rateLimit.ts +4 -0
  295. package/src/network/reqresp/types.ts +6 -0
  296. package/src/node/nodejs.ts +18 -1
  297. package/src/sync/unknownBlock.ts +47 -28
@@ -1,5 +1,7 @@
1
+ import { NUMBER_OF_COLUMNS } from "@lodestar/params";
1
2
  import { sleep } from "@lodestar/utils";
2
3
  import { DataColumnReconstructionCode, recoverDataColumnSidecars } from "../util/dataColumns.js";
4
+ import { JobItemQueue } from "../util/queue/index.js";
3
5
  /**
4
6
  * Minimum time to wait before attempting reconstruction
5
7
  */
@@ -8,67 +10,71 @@ const RECONSTRUCTION_DELAY_MIN_BPS = 667;
8
10
  * Maximum time to wait before attempting reconstruction
9
11
  */
10
12
  const RECONSTRUCTION_DELAY_MAX_BPS = 1000;
13
+ const QUEUE_MAX_LENGTH = 16;
11
14
  /**
12
- * Tracks column reconstruction attempts to avoid duplicate and multiple in-flight calls
15
+ * Runs column reconstruction one block root at a time, in trigger order. A trigger for a root that is
16
+ * queued or in flight is a no-op. A root is removed once its attempt finishes so a later column can
17
+ * retry a failed attempt.
13
18
  */
14
19
  export class ColumnReconstructionTracker {
15
20
  logger;
16
21
  emitter;
17
22
  metrics;
18
23
  config;
19
- /**
20
- * Track last attempted block root
21
- *
22
- * This is sufficient to avoid duplicate calls since we only call this
23
- * function when we see a new data column sidecar from gossip.
24
- */
25
- lastBlockRootHex = null;
26
- /** Track if a reconstruction attempt is in-flight */
27
- running = false;
24
+ signal;
25
+ pending = new Set();
26
+ queue;
28
27
  constructor(init) {
29
28
  this.logger = init.logger;
30
29
  this.emitter = init.emitter;
31
30
  this.metrics = init.metrics;
32
31
  this.config = init.config;
32
+ this.signal = init.signal;
33
+ this.queue = new JobItemQueue(this.reconstruct, { maxLength: QUEUE_MAX_LENGTH, signal: init.signal }, init.metrics?.columnReconstructionQueue);
33
34
  }
34
35
  triggerColumnReconstruction(input) {
35
- if (this.running) {
36
+ if (this.pending.has(input.blockRootHex)) {
36
37
  return;
37
38
  }
38
- if (this.lastBlockRootHex === input.blockRootHex) {
39
+ if (input.getAllColumns().length < NUMBER_OF_COLUMNS / 2) {
39
40
  return;
40
41
  }
41
- // We don't care about the outcome of this call,
42
- // just that it has been triggered for this block root.
43
- this.running = true;
44
- this.lastBlockRootHex = input.blockRootHex;
42
+ this.pending.add(input.blockRootHex);
43
+ void this.enqueue(input);
44
+ }
45
+ async enqueue(input) {
46
+ try {
47
+ await this.queue.push(input, Date.now());
48
+ }
49
+ catch (e) {
50
+ this.logger.debug("Data column sidecar reconstruction dropped", { slot: input.slot, root: input.blockRootHex }, e);
51
+ }
52
+ finally {
53
+ this.pending.delete(input.blockRootHex);
54
+ }
55
+ }
56
+ reconstruct = async (input, queuedAtMs) => {
45
57
  const fork = this.config.getForkName(input.slot);
46
58
  const minDelayMs = this.config.getSlotComponentDurationMs(fork, RECONSTRUCTION_DELAY_MIN_BPS);
47
59
  const maxDelayMs = this.config.getSlotComponentDurationMs(fork, RECONSTRUCTION_DELAY_MAX_BPS);
48
60
  const delay = minDelayMs + Math.random() * (maxDelayMs - minDelayMs);
49
- sleep(delay)
50
- .then(() => {
51
- const logCtx = { slot: input.slot, root: input.blockRootHex };
52
- this.logger.debug("Attempting data column sidecar reconstruction", logCtx);
53
- recoverDataColumnSidecars(input, this.emitter, this.metrics)
54
- .then((result) => {
55
- this.metrics?.recoverDataColumnSidecars.reconstructionResult.inc({ result });
56
- this.logger.debug("Data column sidecar reconstruction complete", { ...logCtx, result });
57
- })
58
- .catch((e) => {
59
- this.metrics?.recoverDataColumnSidecars.reconstructionResult.inc({
60
- result: DataColumnReconstructionCode.Failed,
61
- });
62
- this.logger.debug("Error during data column sidecar reconstruction", logCtx, e);
63
- })
64
- .finally(() => {
65
- this.logger.debug("Data column sidecar reconstruction attempt finished", logCtx);
66
- this.running = false;
67
- });
68
- })
69
- .catch((err) => {
70
- this.logger.debug("ColumnReconstructionTracker unreachable error", {}, err);
71
- });
72
- }
61
+ // The delay gives gossip a chance to deliver the remaining columns, so time already spent in the
62
+ // queue behind another root counts towards it
63
+ await sleep(delay - (Date.now() - queuedAtMs), this.signal);
64
+ const logCtx = { slot: input.slot, root: input.blockRootHex };
65
+ this.logger.debug("Attempting data column sidecar reconstruction", logCtx);
66
+ try {
67
+ const result = await recoverDataColumnSidecars(input, this.emitter, this.metrics);
68
+ this.metrics?.recoverDataColumnSidecars.reconstructionResult.inc({ result });
69
+ this.logger.debug("Data column sidecar reconstruction complete", { ...logCtx, result });
70
+ }
71
+ catch (e) {
72
+ this.metrics?.recoverDataColumnSidecars.reconstructionResult.inc({ result: DataColumnReconstructionCode.Failed });
73
+ this.logger.debug("Error during data column sidecar reconstruction", logCtx, e);
74
+ }
75
+ finally {
76
+ this.logger.debug("Data column sidecar reconstruction attempt finished", logCtx);
77
+ }
78
+ };
73
79
  }
74
80
  //# sourceMappingURL=ColumnReconstructionTracker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ColumnReconstructionTracker.js","sourceRoot":"","sources":["../../src/chain/ColumnReconstructionTracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ColumnReconstructionTracker.js","sourceRoot":"","sources":["../../src/chain/ColumnReconstructionTracker.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,9 @@ import { Metrics } from "../metrics/metrics.js";
5
5
  import { IBlockInput } from "./blocks/blockInput/index.js";
6
6
  import { PayloadEnvelopeInput } from "./blocks/payloadEnvelopeInput/index.js";
7
7
  import { ChainEventEmitter } from "./emitter.js";
8
+ /** A `null` answer only changes if the EL receives the transactions later, so retries are few and spaced out */
9
+ export declare const MAX_GET_BLOBS_ATTEMPTS = 3;
10
+ export declare const GET_BLOBS_RETRY_INTERVAL_MS = 1000;
8
11
  export type GetBlobsTrackerInit = {
9
12
  logger: Logger;
10
13
  executionEngine: IExecutionEngine;
@@ -22,11 +25,19 @@ export declare class GetBlobsTracker {
22
25
  metrics: Metrics | null;
23
26
  config: ChainForkConfig;
24
27
  activeReconstructions: Set<string>;
28
+ failedAttempts: Map<string, {
29
+ count: number;
30
+ lastAttemptMs: number;
31
+ retryTimer?: NodeJS.Timeout;
32
+ }>;
33
+ pendingTriggers: Set<string>;
25
34
  blobsAndProofsBuffers: {
26
35
  buffers: Uint8Array[];
27
36
  inUse: boolean;
28
37
  }[];
29
38
  constructor(init: GetBlobsTrackerInit);
30
39
  triggerGetBlobs(input: IBlockInput | PayloadEnvelopeInput): void;
40
+ private retryPendingTrigger;
41
+ private recordFailedAttempt;
31
42
  }
32
43
  //# sourceMappingURL=GetBlobsTracker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GetBlobsTracker.d.ts","sourceRoot":"","sources":["../../src/chain/GetBlobsTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAC,MAAM,EAAC,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAoB,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAC,iBAAiB,EAAC,MAAM,cAAc,CAAC;AAE/C,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,qBAAa,eAAe;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,qBAAqB,cAAqB;IAG1C,qBAAqB,EAAE;QAAC,OAAO,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAC,EAAE,CAAM;IAEtE,YAAY,IAAI,EAAE,mBAAmB,EAMpC;IAED,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,oBAAoB,GAAG,IAAI,CAoE/D;CACF"}
1
+ {"version":3,"file":"GetBlobsTracker.d.ts","sourceRoot":"","sources":["../../src/chain/GetBlobsTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAC,MAAM,EAAgB,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAM9C,OAAO,EAAC,WAAW,EAAoB,MAAM,8BAA8B,CAAC;AAC5E,OAAO,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAC,iBAAiB,EAAC,MAAM,cAAc,CAAC;AAE/C,gHAAgH;AAChH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AACxC,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAGhD,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,qBAAa,eAAe;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,qBAAqB,cAAqB;IAC1C,cAAc;eAA2B,MAAM;uBAAiB,MAAM;qBAAe,MAAM,CAAC,OAAO;OAAK;IACxG,eAAe,cAAqB;IAGpC,qBAAqB,EAAE;QAAC,OAAO,EAAE,UAAU,EAAE,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAC,EAAE,CAAM;IAEtE,YAAY,IAAI,EAAE,mBAAmB,EAMpC;IAED,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,oBAAoB,GAAG,IAAI,CAwG/D;IAED,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,mBAAmB;CAM5B"}
@@ -1,9 +1,13 @@
1
1
  import { computeEpochAtSlot } from "@lodestar/state-transition";
2
+ import { pruneSetToMax } from "@lodestar/utils";
2
3
  import { BLOB_AND_PROOF_V2_RPC_BYTES } from "../execution/engine/types.js";
3
- import { callInNextEventLoop } from "../util/eventLoop.js";
4
4
  import { DataColumnEngineResult, getBlobSidecarsFromExecution, getDataColumnSidecarsFromExecution, } from "../util/execution.js";
5
5
  import { isBlockInputBlobs } from "./blocks/blockInput/index.js";
6
6
  import { PayloadEnvelopeInput } from "./blocks/payloadEnvelopeInput/index.js";
7
+ /** A `null` answer only changes if the EL receives the transactions later, so retries are few and spaced out */
8
+ export const MAX_GET_BLOBS_ATTEMPTS = 3;
9
+ export const GET_BLOBS_RETRY_INTERVAL_MS = 1000;
10
+ const MAX_TRACKED_BLOCK_ROOTS = 64;
7
11
  /**
8
12
  * Tracks getBlobsV2 calls to the execution engine to avoid duplicate and multiple in-flight calls
9
13
  */
@@ -14,6 +18,8 @@ export class GetBlobsTracker {
14
18
  metrics;
15
19
  config;
16
20
  activeReconstructions = new Set();
21
+ failedAttempts = new Map();
22
+ pendingTriggers = new Set();
17
23
  // Preallocate buffers for getBlobsV2 RPC calls
18
24
  // See https://github.com/ChainSafe/lodestar/pull/8282 for context
19
25
  blobsAndProofsBuffers = [];
@@ -26,19 +32,52 @@ export class GetBlobsTracker {
26
32
  }
27
33
  triggerGetBlobs(input) {
28
34
  if (this.activeReconstructions.has(input.blockRootHex)) {
35
+ this.pendingTriggers.add(input.blockRootHex);
29
36
  return;
30
37
  }
38
+ const failed = this.failedAttempts.get(input.blockRootHex);
39
+ if (failed) {
40
+ if (failed.count >= MAX_GET_BLOBS_ATTEMPTS) {
41
+ return;
42
+ }
43
+ const waitMs = GET_BLOBS_RETRY_INTERVAL_MS - (Date.now() - failed.lastAttemptMs);
44
+ if (waitMs > 0) {
45
+ // Columns tend to arrive in one burst, so keep a single trailing retry instead of relying on a later trigger
46
+ failed.retryTimer ??= setTimeout(() => {
47
+ failed.retryTimer = undefined;
48
+ if (this.failedAttempts.get(input.blockRootHex) === failed && !input.hasAllData()) {
49
+ this.triggerGetBlobs(input);
50
+ }
51
+ }, waitMs).unref();
52
+ return;
53
+ }
54
+ }
55
+ // The request is sent right away, before block processing issues newPayload: ELs that drop a
56
+ // transaction's blobs once the payload is validated can only answer a request that gets there first
31
57
  if (!(input instanceof PayloadEnvelopeInput) && isBlockInputBlobs(input)) {
32
58
  // there is not preallocation for blob sidecars like there is for columns sidecars so no need to
33
59
  // store the index for the preallocated buffers
34
60
  this.activeReconstructions.add(input.blockRootHex);
35
- callInNextEventLoop(() => {
36
- const logCtx = { slot: input.slot, root: input.blockRootHex };
37
- this.logger.verbose("Trigger getBlobsV1 for block", logCtx);
38
- getBlobSidecarsFromExecution(this.config, this.executionEngine, this.metrics, this.emitter, input).finally(() => {
39
- this.logger.verbose("Completed getBlobsV1 for block", logCtx);
40
- this.activeReconstructions.delete(input.blockRootHex);
41
- });
61
+ const logCtx = { slot: input.slot, root: input.blockRootHex };
62
+ this.logger.verbose("Trigger getBlobsV1 for block", logCtx);
63
+ let requestFailed = false;
64
+ getBlobSidecarsFromExecution(this.config, this.executionEngine, this.metrics, this.emitter, input)
65
+ .then(() => {
66
+ // EL errors and misses are handled inside the helper, blobs still missing means the attempt failed
67
+ if (!input.hasAllData()) {
68
+ requestFailed = true;
69
+ this.recordFailedAttempt(input.blockRootHex);
70
+ }
71
+ })
72
+ .catch((error) => {
73
+ this.logger.debug("Error during getBlobsV1 for block", logCtx, error);
74
+ requestFailed = true;
75
+ this.recordFailedAttempt(input.blockRootHex);
76
+ })
77
+ .finally(() => {
78
+ this.logger.verbose("Completed getBlobsV1 for block", logCtx);
79
+ this.activeReconstructions.delete(input.blockRootHex);
80
+ this.retryPendingTrigger(input, requestFailed);
42
81
  });
43
82
  return;
44
83
  }
@@ -56,28 +95,45 @@ export class GetBlobsTracker {
56
95
  }
57
96
  }
58
97
  timer?.();
59
- // We don't care about the outcome of this call,
60
- // just that it has been triggered for this block root.
61
98
  this.activeReconstructions.add(input.blockRootHex);
62
99
  this.blobsAndProofsBuffers[freeIndex].inUse = true;
63
- callInNextEventLoop(() => {
64
- const logCtx = { slot: input.slot, root: input.blockRootHex };
65
- this.logger.verbose("Trigger getBlobsV2 for block", logCtx);
66
- getDataColumnSidecarsFromExecution(this.config, this.executionEngine, this.emitter, input, this.metrics, this.blobsAndProofsBuffers[freeIndex].buffers)
67
- .then((result) => {
68
- this.logger.debug("getBlobsV2 result for block", { ...logCtx, result });
69
- this.metrics?.dataColumns.dataColumnEngineResult.inc({ result });
70
- })
71
- .catch((error) => {
72
- this.logger.debug("Error during getBlobsV2 for block", logCtx, error);
73
- this.metrics?.dataColumns.dataColumnEngineResult.inc({ result: DataColumnEngineResult.Failed });
74
- })
75
- .finally(() => {
76
- this.logger.verbose("Completed getBlobsV2 for block", logCtx);
77
- this.activeReconstructions.delete(input.blockRootHex);
78
- this.blobsAndProofsBuffers[freeIndex].inUse = false;
79
- });
100
+ const logCtx = { slot: input.slot, root: input.blockRootHex };
101
+ this.logger.verbose("Trigger getBlobsV2 for block", logCtx);
102
+ let requestFailed = false;
103
+ getDataColumnSidecarsFromExecution(this.config, this.executionEngine, this.emitter, input, this.metrics, this.blobsAndProofsBuffers[freeIndex].buffers)
104
+ .then((result) => {
105
+ this.logger.debug("getBlobsV2 result for block", { ...logCtx, result });
106
+ this.metrics?.dataColumns.dataColumnEngineResult.inc({ result });
107
+ if (result === DataColumnEngineResult.NullResponse) {
108
+ requestFailed = true;
109
+ this.recordFailedAttempt(input.blockRootHex);
110
+ }
111
+ })
112
+ .catch((error) => {
113
+ this.logger.debug("Error during getBlobsV2 for block", logCtx, error);
114
+ this.metrics?.dataColumns.dataColumnEngineResult.inc({ result: DataColumnEngineResult.Failed });
115
+ requestFailed = true;
116
+ this.recordFailedAttempt(input.blockRootHex);
117
+ })
118
+ .finally(() => {
119
+ this.logger.verbose("Completed getBlobsV2 for block", logCtx);
120
+ this.activeReconstructions.delete(input.blockRootHex);
121
+ this.blobsAndProofsBuffers[freeIndex].inUse = false;
122
+ this.retryPendingTrigger(input, requestFailed);
80
123
  });
81
124
  }
125
+ retryPendingTrigger(input, requestFailed) {
126
+ // Triggers dropped while the request was in flight re-enter once it failed, the attempt that was just
127
+ // recorded makes this arm the trailing retry instead of sending another request right away
128
+ if (this.pendingTriggers.delete(input.blockRootHex) && requestFailed) {
129
+ this.triggerGetBlobs(input);
130
+ }
131
+ }
132
+ recordFailedAttempt(blockRootHex) {
133
+ const failed = this.failedAttempts.get(blockRootHex);
134
+ clearTimeout(failed?.retryTimer);
135
+ this.failedAttempts.set(blockRootHex, { count: (failed?.count ?? 0) + 1, lastAttemptMs: Date.now() });
136
+ pruneSetToMax(this.failedAttempts, MAX_TRACKED_BLOCK_ROOTS);
137
+ }
82
138
  }
83
139
  //# sourceMappingURL=GetBlobsTracker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GetBlobsTracker.js","sourceRoot":"","sources":["../../src/chain/GetBlobsTracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GetBlobsTracker.js","sourceRoot":"","sources":["../../src/chain/GetBlobsTracker.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,10 @@ export declare enum LateCanonicalBlockReason {
12
12
  SlowImport = "slow_import",
13
13
  LateReceive = "late_receive"
14
14
  }
15
+ /**
16
+ * Oldest epoch for which data column sidecars are kept
17
+ */
18
+ export declare function getDataColumnSidecarsMinEpoch(config: ChainForkConfig, currentEpoch: Epoch, archiveDataEpochs?: number): Epoch;
15
19
  /**
16
20
  * Archives finalized blocks from active bucket to archive bucket.
17
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"archiveBlocks.d.ts","sourceRoot":"","sources":["../../../../src/chain/archiveStore/utils/archiveBlocks.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAC,iBAAiB,EAAmB,WAAW,EAAiB,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAGjH,OAAO,EAAC,KAAK,EAAE,IAAI,EAAC,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAC,MAAM,EAAoD,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EAAC,OAAO,EAAC,MAAM,6BAA6B,CAAC;AAIpD,OAAO,EAAC,iBAAiB,EAAC,MAAM,4BAA4B,CAAC;AAU7D;;GAEG;AACH,oBAAY,wBAAwB;IAElC,UAAU,gBAAgB;IAE1B,WAAW,iBAAiB;CAC7B;AAmBD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,eAAe,EACvB,EAAE,EAAE,SAAS,EACb,UAAU,EAAE,WAAW,EACvB,iBAAiB,EAAE,iBAAiB,GAAG,SAAS,EAChD,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,iBAAiB,EACtC,YAAY,EAAE,KAAK,EACnB,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,YAAY,EAAE,OAAO,EACrB,iBAAiB,CAAC,EAAE,MAAM,EAC1B,qBAAqB,CAAC,EAAE,OAAO,EAC/B,wBAAwB,CAAC,EAAE,MAAM,EACjC,cAAc,UAAO,GACpB,OAAO,CAAC,IAAI,CAAC,CAkOf;AAgLD;;;;;;;GAOG;AACH,wBAAsB,+CAA+C,CACnE,MAAM,EAAE,eAAe,EACvB,EAAE,EAAE,SAAS,EACb,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,UAAU,EAAE,EAC7B,cAAc,EAAE,OAAO,GACtB,OAAO,CAAC,IAAI,EAAE,CAAC,CAmDjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAE1E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAC,IAAI,EAAE,IAAI,CAAA;CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CA+C/E"}
1
+ {"version":3,"file":"archiveBlocks.d.ts","sourceRoot":"","sources":["../../../../src/chain/archiveStore/utils/archiveBlocks.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EACL,iBAAiB,EAEjB,WAAW,EAEX,UAAU,EAEX,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAC,KAAK,EAAE,IAAI,EAAC,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAC,MAAM,EAAyC,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EAAC,OAAO,EAAC,MAAM,6BAA6B,CAAC;AAIpD,OAAO,EAAC,iBAAiB,EAAC,MAAM,4BAA4B,CAAC;AAU7D;;GAEG;AACH,oBAAY,wBAAwB;IAElC,UAAU,gBAAgB;IAE1B,WAAW,iBAAiB;CAC7B;AAmBD;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,KAAK,EACnB,iBAAiB,CAAC,EAAE,MAAM,GACzB,KAAK,CAEP;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,eAAe,EACvB,EAAE,EAAE,SAAS,EACb,UAAU,EAAE,WAAW,EACvB,iBAAiB,EAAE,iBAAiB,GAAG,SAAS,EAChD,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,iBAAiB,EACtC,YAAY,EAAE,KAAK,EACnB,OAAO,EAAE,OAAO,GAAG,IAAI,EACvB,YAAY,EAAE,OAAO,EACrB,iBAAiB,CAAC,EAAE,MAAM,EAC1B,qBAAqB,CAAC,EAAE,OAAO,EAC/B,wBAAwB,CAAC,EAAE,MAAM,EACjC,cAAc,UAAO,GACpB,OAAO,CAAC,IAAI,CAAC,CA4Nf;AA8GD;;;;;;;GAOG;AACH,wBAAsB,+CAA+C,CACnE,MAAM,EAAE,eAAe,EACvB,EAAE,EAAE,SAAS,EACb,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,UAAU,EAAE,EAC7B,cAAc,EAAE,OAAO,GACtB,OAAO,CAAC,IAAI,EAAE,CAAC,CAmDjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAE1E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAC,IAAI,EAAE,IAAI,CAAA;CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CA+C/E"}
@@ -1,8 +1,8 @@
1
1
  import path from "node:path";
2
- import { ExecutionStatus, PayloadStatus } from "@lodestar/fork-choice";
2
+ import { ExecutionStatus, PayloadStatus, isGloasBlock, } from "@lodestar/fork-choice";
3
3
  import { ForkSeq, SLOTS_PER_EPOCH } from "@lodestar/params";
4
4
  import { computeEpochAtSlot, computeStartSlotAtEpoch, getBlobDataRetentionStartEpoch } from "@lodestar/state-transition";
5
- import { fromAsync, fromHex, prettyPrintIndices, toRootHex } from "@lodestar/utils";
5
+ import { fromHex, prettyPrintIndices, toRootHex } from "@lodestar/utils";
6
6
  import { encodeArchivedHeaderEnvelope } from "../../../db/repositories/index.js";
7
7
  import { ensureDir, writeIfNotExist } from "../../../util/file.js";
8
8
  import { toSignedHeaderEnvelope } from "../../../util/headerEnvelope.js";
@@ -30,6 +30,12 @@ async function persistOrphanedBlock(slot, blockRoot, bytes, opts) {
30
30
  await ensureDir(dirpath);
31
31
  await writeIfNotExist(filepath, bytes);
32
32
  }
33
+ /**
34
+ * Oldest epoch for which data column sidecars are kept
35
+ */
36
+ export function getDataColumnSidecarsMinEpoch(config, currentEpoch, archiveDataEpochs) {
37
+ return Math.min(getBlobDataRetentionStartEpoch(config, currentEpoch), currentEpoch - (archiveDataEpochs ?? 0));
38
+ }
33
39
  /**
34
40
  * Archives finalized blocks from active bucket to archive bucket.
35
41
  *
@@ -90,16 +96,6 @@ export async function archiveBlocks(config, db, forkChoice, lightclientServer, l
90
96
  const migratedEntries = await migrateBlobSidecarsFromHotToColdDb(config, db, logger, finalizedCanonicalBlockRoots, currentEpoch);
91
97
  logger.verbose("Migrated blobSidecars from hot DB to cold DB", { ...logCtx, migratedEntries });
92
98
  }
93
- // Keep the normal LevelDB hot-to-cold flow for legacy columns. New columns are written
94
- // directly to flat files, so this only moves fallback data left by older versions.
95
- if (finalizedPostFulu) {
96
- const migratedSlots = await migrateDataColumnSidecarsFromHotToColdDb(config, db, logger, finalizedCanonicalBlocks, currentEpoch);
97
- logger.verbose("Migrated legacy dataColumnSidecars from hot DB to cold DB", {
98
- ...logCtx,
99
- migratedEntries: migratedSlots.length,
100
- slotRange: prettyPrintIndices(migratedSlots),
101
- });
102
- }
103
99
  if (finalizedPostGloas) {
104
100
  const migratedSlots = await migrateExecutionPayloadEnvelopesFromHotToColdDb(config, db, logger, finalizedCanonicalBlocks, dedupePayloads);
105
101
  logger.verbose("Migrated executionPayloadEnvelopes from hot DB to cold DB", {
@@ -109,38 +105,31 @@ export async function archiveBlocks(config, db, forkChoice, lightclientServer, l
109
105
  });
110
106
  }
111
107
  }
112
- // deleteNonCanonicalBlocks
113
- // loop through forkchoice single time
114
- const nonCanonicalBlockRoots = finalizedNonCanonicalBlocks.map((summary) => fromHex(summary.blockRoot));
115
- if (nonCanonicalBlockRoots.length > 0) {
116
- if (persistOrphanedBlocks) {
117
- // Persist orphaned blocks to disk before deleting them from hot db
118
- await Promise.all(nonCanonicalBlockRoots.map(async (root, index) => {
119
- const block = finalizedNonCanonicalBlocks[index];
120
- const blockBytes = await db.block.getBinary(root);
121
- const blockLogCtx = { slot: block.slot, root: block.blockRoot };
122
- if (blockBytes) {
123
- await persistOrphanedBlock(block.slot, block.blockRoot, blockBytes, {
124
- persistOrphanedBlocksDir: persistOrphanedBlocksDir ?? "orphaned_blocks",
125
- });
126
- logger.verbose("Persisted orphaned block", { ...logCtx, ...blockLogCtx });
127
- }
128
- else {
129
- logger.warn("Tried to persist orphaned block but no block found", { ...logCtx, ...blockLogCtx });
130
- }
131
- }));
108
+ const canonicalRoots = new Set(finalizedCanonicalBlocks.map((block) => block.blockRoot));
109
+ const orphanedBlocks = [];
110
+ const orphanedPayloads = [];
111
+ for (const block of finalizedNonCanonicalBlocks) {
112
+ if (block.payloadStatus === PayloadStatus.FULL) {
113
+ orphanedPayloads.push(block);
114
+ }
115
+ // Every Gloas block gets EMPTY before FULL. If only FULL survives pruning, an earlier archive run
116
+ // already handled the root's block-level data.
117
+ const isBlockNode = !isGloasBlock(block) || block.payloadStatus === PayloadStatus.EMPTY;
118
+ if (isBlockNode && !canonicalRoots.has(block.blockRoot)) {
119
+ orphanedBlocks.push(block);
132
120
  }
133
- const nonCanonicalSlots = finalizedNonCanonicalBlocks.map((summary) => summary.slot).sort((a, b) => a - b);
134
- const nonCanonicalLogCtx = {
121
+ }
122
+ const orphanedBlockRoots = orphanedBlocks.map((block) => fromHex(block.blockRoot));
123
+ if (orphanedPayloads.length > 0) {
124
+ const orphanedPayloadRoots = orphanedPayloads.map((block) => fromHex(block.blockRoot));
125
+ const orphanedPayloadLogCtx = {
135
126
  ...logCtx,
136
- count: nonCanonicalBlockRoots.length,
137
- slotRange: prettyPrintIndices(nonCanonicalSlots),
127
+ count: orphanedPayloads.length,
128
+ slotRange: prettyPrintIndices(orphanedPayloads.map((block) => block.slot).sort((a, b) => a - b)),
138
129
  };
139
- const columnItems = finalizedNonCanonicalBlocks
140
- // Gloas EMPTY and FULL variants share a block root. EMPTY has no sidecars, so deleting by its root could
141
- // remove the canonical FULL variant's columns. Pre-Gloas blocks are always FULL.
142
- .filter((summary) => config.getForkSeq(summary.slot) >= ForkSeq.fulu && summary.payloadStatus === PayloadStatus.FULL)
143
- .map((summary) => ({ slot: summary.slot, blockRoot: summary.blockRoot }));
130
+ const columnItems = orphanedPayloads
131
+ .filter((block) => config.getForkSeq(block.slot) >= ForkSeq.fulu)
132
+ .map((block) => ({ slot: block.slot, blockRoot: block.blockRoot }));
144
133
  if (columnItems.length > 0) {
145
134
  // Delete sidecars first so their block roots remain available to retry cleanup after a failure or crash.
146
135
  await db.dataColumns.deleteMany(columnItems);
@@ -150,16 +139,38 @@ export async function archiveBlocks(config, db, forkChoice, lightclientServer, l
150
139
  slotRange: prettyPrintIndices(columnItems.map(({ slot }) => slot).sort((a, b) => a - b)),
151
140
  });
152
141
  }
153
- await db.block.batchDelete(nonCanonicalBlockRoots);
154
- logger.verbose("Deleted non canonical blocks from hot DB", nonCanonicalLogCtx);
155
142
  if (finalizedPostDeneb) {
156
- await db.blobSidecars.batchDelete(nonCanonicalBlockRoots);
157
- logger.verbose("Deleted non canonical blobSidecars from hot DB", nonCanonicalLogCtx);
143
+ await db.blobSidecars.batchDelete(orphanedPayloadRoots);
144
+ logger.verbose("Deleted non canonical blobSidecars from hot DB", orphanedPayloadLogCtx);
158
145
  }
159
146
  if (finalizedPostGloas) {
160
- await db.executionPayloadEnvelope.batchDelete(nonCanonicalBlockRoots);
161
- logger.verbose("Deleted non canonical executionPayloadEnvelopes from hot DB", nonCanonicalLogCtx);
147
+ await db.executionPayloadEnvelope.batchDelete(orphanedPayloadRoots);
148
+ logger.verbose("Deleted non canonical executionPayloadEnvelopes from hot DB", orphanedPayloadLogCtx);
149
+ }
150
+ }
151
+ if (orphanedBlocks.length > 0) {
152
+ if (persistOrphanedBlocks) {
153
+ // Persist orphaned blocks to disk before deleting them from hot db
154
+ await Promise.all(orphanedBlocks.map(async (block) => {
155
+ const blockBytes = await db.block.getBinary(fromHex(block.blockRoot));
156
+ const blockLogCtx = { slot: block.slot, root: block.blockRoot };
157
+ if (blockBytes) {
158
+ await persistOrphanedBlock(block.slot, block.blockRoot, blockBytes, {
159
+ persistOrphanedBlocksDir: persistOrphanedBlocksDir ?? "orphaned_blocks",
160
+ });
161
+ logger.verbose("Persisted orphaned block", { ...logCtx, ...blockLogCtx });
162
+ }
163
+ else {
164
+ logger.debug("Tried to persist orphaned block but no block found", { ...logCtx, ...blockLogCtx });
165
+ }
166
+ }));
162
167
  }
168
+ await db.block.batchDelete(orphanedBlockRoots);
169
+ logger.verbose("Deleted non canonical blocks from hot DB", {
170
+ ...logCtx,
171
+ count: orphanedBlocks.length,
172
+ slotRange: prettyPrintIndices(orphanedBlocks.map((block) => block.slot).sort((a, b) => a - b)),
173
+ });
163
174
  }
164
175
  // Delete expired blobs
165
176
  // Keep only `[current_epoch - max(MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS, archiveDataEpochs)]`
@@ -187,7 +198,7 @@ export async function archiveBlocks(config, db, forkChoice, lightclientServer, l
187
198
  // Keep only `[min(compute_blob_data_retention_start_epoch(current_epoch), current_epoch - archiveDataEpochs)]`
188
199
  if (finalizedPostFulu) {
189
200
  if (archiveDataEpochs !== Infinity) {
190
- const dataColumnSidecarsMinEpoch = Math.min(getBlobDataRetentionStartEpoch(config, currentEpoch), currentEpoch - (archiveDataEpochs ?? 0));
201
+ const dataColumnSidecarsMinEpoch = getDataColumnSidecarsMinEpoch(config, currentEpoch, archiveDataEpochs);
191
202
  if (dataColumnSidecarsMinEpoch >= config.FULU_FORK_EPOCH) {
192
203
  const columnsPruneSlot = computeStartSlotAtEpoch(dataColumnSidecarsMinEpoch);
193
204
  const prunedColumnSlots = await db.dataColumns.pruneBefore(columnsPruneSlot);
@@ -210,9 +221,9 @@ export async function archiveBlocks(config, db, forkChoice, lightclientServer, l
210
221
  logger.verbose("dataColumnSidecars pruning skipped: archiveDataEpochs set to Infinity", logCtx);
211
222
  }
212
223
  }
213
- // Prunning potential checkpoint data
224
+ // Pruning potential checkpoint data
214
225
  const finalizedCanonicalNonCheckpointBlocks = getNonCheckpointBlocks(finalizedCanonicalBlockRoots);
215
- const nonCheckpointBlockRoots = [...nonCanonicalBlockRoots];
226
+ const nonCheckpointBlockRoots = [...orphanedBlockRoots];
216
227
  for (const block of finalizedCanonicalNonCheckpointBlocks) {
217
228
  nonCheckpointBlockRoots.push(block.root);
218
229
  }
@@ -310,53 +321,6 @@ async function migrateBlobSidecarsFromHotToColdDb(config, db, logger, blocks, cu
310
321
  }
311
322
  return migratedWrappedBlobSidecars;
312
323
  }
313
- // TODO: This function can be simplified further by reducing layers of promises in a loop
314
- /**
315
- * Post-gloas the data columns of a Gloas block are tied to its execution payload envelope.
316
- * Columns only exist once the FULL variant of the block is in the proto-array. Pre-Gloas
317
- * blocks only have a FULL variant, so the payload-status filter passes them all.
318
- */
319
- async function migrateDataColumnSidecarsFromHotToColdDb(config, db, logger, canonicalBlocks, currentEpoch) {
320
- const columnBlocks = canonicalBlocks.filter((block) => config.getForkSeq(block.slot) < ForkSeq.gloas || block.payloadStatus === PayloadStatus.FULL);
321
- if (columnBlocks.length === 0)
322
- return [];
323
- const blocks = columnBlocks.map((block) => ({ slot: block.slot, root: fromHex(block.blockRoot) }));
324
- const migratedSlots = [];
325
- for (let i = 0; i < blocks.length; i += BLOB_SIDECAR_BATCH_SIZE) {
326
- const toIdx = Math.min(i + BLOB_SIDECAR_BATCH_SIZE, blocks.length);
327
- const batch = blocks.slice(i, toIdx);
328
- if (batch.length === 0)
329
- break;
330
- const promises = [];
331
- for (const block of batch) {
332
- const blockEpoch = computeEpochAtSlot(block.slot);
333
- if (config.getForkSeq(block.slot) < ForkSeq.fulu ||
334
- blockEpoch < getBlobDataRetentionStartEpoch(config, currentEpoch)) {
335
- continue;
336
- }
337
- const dataColumnSidecarBytes = await fromAsync(db.dataColumnSidecar.valuesStreamBinary(block.root));
338
- if (dataColumnSidecarBytes.length === 0) {
339
- logger.debug("DataColumnSidecars in forkchoice but missing in hot db, could be already archived", {
340
- slot: block.slot,
341
- root: toRootHex(block.root),
342
- });
343
- continue;
344
- }
345
- logger.verbose("Migrated legacy dataColumnSidecars for block", {
346
- currentEpoch,
347
- slot: block.slot,
348
- root: toRootHex(block.root),
349
- numSidecars: dataColumnSidecarBytes.length,
350
- });
351
- promises.push(db.dataColumnSidecarArchive.putManyBinary(block.slot, dataColumnSidecarBytes.map((entry) => ({ key: entry.id, value: entry.value }))));
352
- migratedSlots.push(block.slot);
353
- }
354
- await Promise.all(promises);
355
- await db.dataColumnSidecar.deleteMany(batch.map((block) => block.root));
356
- }
357
- // Ancestor walk is newest to oldest; sort ascending so `prettyPrintIndices` renders cleanly.
358
- return migratedSlots.sort((a, b) => a - b);
359
- }
360
324
  /**
361
325
  * Post-gloas given a finalized checkpoint at a block root, payload of that block root
362
326
  * is not considered finalized, hence they are archived in the next run.