@lodestar/beacon-node 1.48.0-dev.f22c5ce63e → 1.48.0-rc.0

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 (296) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +4 -11
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/state/utils.js +14 -0
  6. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  7. package/lib/api/impl/config/index.d.ts.map +1 -1
  8. package/lib/api/impl/config/index.js +4 -1
  9. package/lib/api/impl/config/index.js.map +1 -1
  10. package/lib/api/impl/validator/index.d.ts.map +1 -1
  11. package/lib/api/impl/validator/index.js +39 -39
  12. package/lib/api/impl/validator/index.js.map +1 -1
  13. package/lib/chain/archiveStore/archiveStore.d.ts +1 -0
  14. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  15. package/lib/chain/archiveStore/archiveStore.js +5 -1
  16. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  17. package/lib/chain/archiveStore/historicalState/historicalStateRegen.d.ts.map +1 -1
  18. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -0
  19. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
  20. package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
  21. package/lib/chain/archiveStore/historicalState/metrics.js +12 -1
  22. package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
  23. package/lib/chain/archiveStore/historicalState/types.d.ts +2 -0
  24. package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
  25. package/lib/chain/archiveStore/historicalState/types.js.map +1 -1
  26. package/lib/chain/archiveStore/historicalState/worker.js +4 -1
  27. package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
  28. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +9 -1
  29. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  30. package/lib/chain/archiveStore/utils/archiveBlocks.js +68 -38
  31. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  32. package/lib/chain/blocks/importBlock.d.ts +5 -1
  33. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  34. package/lib/chain/blocks/importBlock.js +12 -18
  35. package/lib/chain/blocks/importBlock.js.map +1 -1
  36. package/lib/chain/blocks/index.d.ts +8 -4
  37. package/lib/chain/blocks/index.d.ts.map +1 -1
  38. package/lib/chain/blocks/index.js +83 -17
  39. package/lib/chain/blocks/index.js.map +1 -1
  40. package/lib/chain/blocks/types.d.ts +8 -0
  41. package/lib/chain/blocks/types.d.ts.map +1 -1
  42. package/lib/chain/blocks/types.js.map +1 -1
  43. package/lib/chain/blocks/utils/chainSegment.d.ts +1 -1
  44. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  45. package/lib/chain/blocks/utils/chainSegment.js +26 -11
  46. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  47. package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
  48. package/lib/chain/blocks/writeBlockInputToDb.js +9 -16
  49. package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
  50. package/lib/chain/chain.d.ts +11 -5
  51. package/lib/chain/chain.d.ts.map +1 -1
  52. package/lib/chain/chain.js +129 -75
  53. package/lib/chain/chain.js.map +1 -1
  54. package/lib/chain/emitter.d.ts +1 -1
  55. package/lib/chain/emitter.js +1 -1
  56. package/lib/chain/errors/blockError.d.ts +19 -7
  57. package/lib/chain/errors/blockError.d.ts.map +1 -1
  58. package/lib/chain/errors/blockError.js +2 -2
  59. package/lib/chain/errors/blockError.js.map +1 -1
  60. package/lib/chain/errors/dataColumnSidecarError.d.ts +15 -2
  61. package/lib/chain/errors/dataColumnSidecarError.d.ts.map +1 -1
  62. package/lib/chain/errors/dataColumnSidecarError.js.map +1 -1
  63. package/lib/chain/errors/executionPayloadBid.d.ts +4 -0
  64. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  65. package/lib/chain/errors/executionPayloadBid.js +1 -0
  66. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  67. package/lib/chain/errors/executionPayloadEnvelope.d.ts +10 -11
  68. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  69. package/lib/chain/errors/executionPayloadEnvelope.js +0 -2
  70. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  71. package/lib/chain/errors/gossipValidation.d.ts +2 -1
  72. package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
  73. package/lib/chain/errors/gossipValidation.js +1 -0
  74. package/lib/chain/errors/gossipValidation.js.map +1 -1
  75. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  76. package/lib/chain/forkChoice/index.js +2 -0
  77. package/lib/chain/forkChoice/index.js.map +1 -1
  78. package/lib/chain/interface.d.ts +4 -4
  79. package/lib/chain/interface.d.ts.map +1 -1
  80. package/lib/chain/lightClient/index.d.ts +3 -3
  81. package/lib/chain/lightClient/index.d.ts.map +1 -1
  82. package/lib/chain/lightClient/index.js +21 -23
  83. package/lib/chain/lightClient/index.js.map +1 -1
  84. package/lib/chain/lightClient/proofs.d.ts +2 -1
  85. package/lib/chain/lightClient/proofs.d.ts.map +1 -1
  86. package/lib/chain/lightClient/proofs.js +5 -1
  87. package/lib/chain/lightClient/proofs.js.map +1 -1
  88. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  89. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  90. package/lib/chain/prepareNextSlot.js +13 -13
  91. package/lib/chain/prepareNextSlot.js.map +1 -1
  92. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  93. package/lib/chain/produceBlock/produceBlockBody.js +46 -64
  94. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  95. package/lib/chain/validation/block.d.ts.map +1 -1
  96. package/lib/chain/validation/block.js +35 -54
  97. package/lib/chain/validation/block.js.map +1 -1
  98. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  99. package/lib/chain/validation/dataColumnSidecar.js +38 -13
  100. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  101. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  102. package/lib/chain/validation/executionPayloadBid.js +56 -40
  103. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  104. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  105. package/lib/chain/validation/executionPayloadEnvelope.js +10 -29
  106. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  107. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  108. package/lib/chain/validation/payloadAttestationMessage.js +5 -6
  109. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  110. package/lib/chain/validatorMonitor.d.ts +7 -1
  111. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  112. package/lib/chain/validatorMonitor.js +22 -5
  113. package/lib/chain/validatorMonitor.js.map +1 -1
  114. package/lib/db/beacon.d.ts +14 -5
  115. package/lib/db/beacon.d.ts.map +1 -1
  116. package/lib/db/beacon.js +17 -3
  117. package/lib/db/beacon.js.map +1 -1
  118. package/lib/db/dataColumnStore.d.ts +39 -0
  119. package/lib/db/dataColumnStore.d.ts.map +1 -0
  120. package/lib/db/dataColumnStore.js +81 -0
  121. package/lib/db/dataColumnStore.js.map +1 -0
  122. package/lib/db/flatFileStore/atomicWrite.d.ts +8 -0
  123. package/lib/db/flatFileStore/atomicWrite.d.ts.map +1 -0
  124. package/lib/db/flatFileStore/atomicWrite.js +61 -0
  125. package/lib/db/flatFileStore/atomicWrite.js.map +1 -0
  126. package/lib/db/flatFileStore/dcolFormat.d.ts +90 -0
  127. package/lib/db/flatFileStore/dcolFormat.d.ts.map +1 -0
  128. package/lib/db/flatFileStore/dcolFormat.js +286 -0
  129. package/lib/db/flatFileStore/dcolFormat.js.map +1 -0
  130. package/lib/db/flatFileStore/errors.d.ts +82 -0
  131. package/lib/db/flatFileStore/errors.d.ts.map +1 -0
  132. package/lib/db/flatFileStore/errors.js +32 -0
  133. package/lib/db/flatFileStore/errors.js.map +1 -0
  134. package/lib/db/flatFileStore/flatFileStore.d.ts +41 -0
  135. package/lib/db/flatFileStore/flatFileStore.d.ts.map +1 -0
  136. package/lib/db/flatFileStore/flatFileStore.js +251 -0
  137. package/lib/db/flatFileStore/flatFileStore.js.map +1 -0
  138. package/lib/db/flatFileStore/index.d.ts +4 -0
  139. package/lib/db/flatFileStore/index.d.ts.map +1 -0
  140. package/lib/db/flatFileStore/index.js +2 -0
  141. package/lib/db/flatFileStore/index.js.map +1 -0
  142. package/lib/db/flatFileStore/interface.d.ts +25 -0
  143. package/lib/db/flatFileStore/interface.d.ts.map +1 -0
  144. package/lib/db/flatFileStore/interface.js +2 -0
  145. package/lib/db/flatFileStore/interface.js.map +1 -0
  146. package/lib/db/flatFileStore/metrics.d.ts +24 -0
  147. package/lib/db/flatFileStore/metrics.d.ts.map +1 -0
  148. package/lib/db/flatFileStore/metrics.js +25 -0
  149. package/lib/db/flatFileStore/metrics.js.map +1 -0
  150. package/lib/db/flatFileStore/path.d.ts +9 -0
  151. package/lib/db/flatFileStore/path.d.ts.map +1 -0
  152. package/lib/db/flatFileStore/path.js +21 -0
  153. package/lib/db/flatFileStore/path.js.map +1 -0
  154. package/lib/db/flatFileStore/slotIndex.d.ts +14 -0
  155. package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -0
  156. package/lib/db/flatFileStore/slotIndex.js +46 -0
  157. package/lib/db/flatFileStore/slotIndex.js.map +1 -0
  158. package/lib/db/flatFileStore/snappy.d.ts +3 -0
  159. package/lib/db/flatFileStore/snappy.d.ts.map +1 -0
  160. package/lib/db/flatFileStore/snappy.js +12 -0
  161. package/lib/db/flatFileStore/snappy.js.map +1 -0
  162. package/lib/db/index.d.ts +1 -0
  163. package/lib/db/index.d.ts.map +1 -1
  164. package/lib/db/interface.d.ts +8 -1
  165. package/lib/db/interface.d.ts.map +1 -1
  166. package/lib/db/repositories/blockArchive.d.ts +8 -1
  167. package/lib/db/repositories/blockArchive.d.ts.map +1 -1
  168. package/lib/db/repositories/blockArchive.js +65 -28
  169. package/lib/db/repositories/blockArchive.js.map +1 -1
  170. package/lib/db/repositories/blockArchiveIndex.d.ts +1 -2
  171. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  172. package/lib/db/repositories/blockArchiveIndex.js +3 -7
  173. package/lib/db/repositories/blockArchiveIndex.js.map +1 -1
  174. package/lib/execution/builder/validateBid.d.ts.map +1 -1
  175. package/lib/execution/builder/validateBid.js +8 -5
  176. package/lib/execution/builder/validateBid.js.map +1 -1
  177. package/lib/execution/engine/mock.d.ts.map +1 -1
  178. package/lib/execution/engine/mock.js +4 -1
  179. package/lib/execution/engine/mock.js.map +1 -1
  180. package/lib/metrics/metrics/lodestar.d.ts +22 -3
  181. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  182. package/lib/metrics/metrics/lodestar.js +60 -6
  183. package/lib/metrics/metrics/lodestar.js.map +1 -1
  184. package/lib/monitoring/clientStats.js +1 -1
  185. package/lib/monitoring/clientStats.js.map +1 -1
  186. package/lib/network/gossip/encoding.d.ts.map +1 -1
  187. package/lib/network/gossip/encoding.js +0 -7
  188. package/lib/network/gossip/encoding.js.map +1 -1
  189. package/lib/network/gossip/topic.d.ts +2 -1
  190. package/lib/network/gossip/topic.d.ts.map +1 -1
  191. package/lib/network/gossip/topic.js +4 -20
  192. package/lib/network/gossip/topic.js.map +1 -1
  193. package/lib/network/network.js +2 -2
  194. package/lib/network/network.js.map +1 -1
  195. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  196. package/lib/network/processor/gossipHandlers.js +388 -285
  197. package/lib/network/processor/gossipHandlers.js.map +1 -1
  198. package/lib/network/processor/index.d.ts +49 -3
  199. package/lib/network/processor/index.d.ts.map +1 -1
  200. package/lib/network/processor/index.js +254 -114
  201. package/lib/network/processor/index.js.map +1 -1
  202. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  203. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +112 -91
  204. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  205. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts.map +1 -1
  206. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +2 -0
  207. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
  208. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  209. package/lib/network/reqresp/protocols.js +6 -22
  210. package/lib/network/reqresp/protocols.js.map +1 -1
  211. package/lib/network/reqresp/rateLimit.js +2 -1
  212. package/lib/network/reqresp/rateLimit.js.map +1 -1
  213. package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts +2 -1
  214. package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
  215. package/lib/network/reqresp/utils/dataColumnResponseValidation.js +14 -9
  216. package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
  217. package/lib/node/nodejs.d.ts +2 -1
  218. package/lib/node/nodejs.d.ts.map +1 -1
  219. package/lib/node/nodejs.js +4 -2
  220. package/lib/node/nodejs.js.map +1 -1
  221. package/lib/sync/range/range.d.ts.map +1 -1
  222. package/lib/sync/range/range.js +24 -1
  223. package/lib/sync/range/range.js.map +1 -1
  224. package/lib/util/sszBytes.d.ts +6 -0
  225. package/lib/util/sszBytes.d.ts.map +1 -1
  226. package/lib/util/sszBytes.js +1 -1
  227. package/lib/util/sszBytes.js.map +1 -1
  228. package/package.json +18 -19
  229. package/src/api/impl/beacon/blocks/index.ts +8 -14
  230. package/src/api/impl/beacon/state/utils.ts +15 -0
  231. package/src/api/impl/config/index.ts +4 -1
  232. package/src/api/impl/validator/index.ts +44 -43
  233. package/src/chain/archiveStore/archiveStore.ts +12 -1
  234. package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -0
  235. package/src/chain/archiveStore/historicalState/metrics.ts +14 -1
  236. package/src/chain/archiveStore/historicalState/types.ts +2 -0
  237. package/src/chain/archiveStore/historicalState/worker.ts +4 -1
  238. package/src/chain/archiveStore/utils/archiveBlocks.ts +73 -42
  239. package/src/chain/blocks/importBlock.ts +25 -20
  240. package/src/chain/blocks/index.ts +120 -23
  241. package/src/chain/blocks/types.ts +9 -0
  242. package/src/chain/blocks/utils/chainSegment.ts +26 -12
  243. package/src/chain/blocks/writeBlockInputToDb.ts +10 -17
  244. package/src/chain/chain.ts +153 -84
  245. package/src/chain/emitter.ts +1 -1
  246. package/src/chain/errors/blockError.ts +22 -10
  247. package/src/chain/errors/dataColumnSidecarError.ts +24 -8
  248. package/src/chain/errors/executionPayloadBid.ts +2 -0
  249. package/src/chain/errors/executionPayloadEnvelope.ts +14 -11
  250. package/src/chain/errors/gossipValidation.ts +1 -0
  251. package/src/chain/forkChoice/index.ts +2 -0
  252. package/src/chain/interface.ts +4 -4
  253. package/src/chain/lightClient/index.ts +32 -36
  254. package/src/chain/lightClient/proofs.ts +10 -0
  255. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  256. package/src/chain/prepareNextSlot.ts +16 -16
  257. package/src/chain/produceBlock/produceBlockBody.ts +50 -71
  258. package/src/chain/validation/block.ts +35 -70
  259. package/src/chain/validation/dataColumnSidecar.ts +47 -14
  260. package/src/chain/validation/executionPayloadBid.ts +62 -44
  261. package/src/chain/validation/executionPayloadEnvelope.ts +10 -37
  262. package/src/chain/validation/payloadAttestationMessage.ts +8 -9
  263. package/src/chain/validatorMonitor.ts +24 -7
  264. package/src/db/beacon.ts +33 -6
  265. package/src/db/dataColumnStore.ts +113 -0
  266. package/src/db/flatFileStore/atomicWrite.ts +65 -0
  267. package/src/db/flatFileStore/dcolFormat.ts +389 -0
  268. package/src/db/flatFileStore/errors.ts +53 -0
  269. package/src/db/flatFileStore/flatFileStore.ts +310 -0
  270. package/src/db/flatFileStore/index.ts +3 -0
  271. package/src/db/flatFileStore/interface.ts +21 -0
  272. package/src/db/flatFileStore/metrics.ts +48 -0
  273. package/src/db/flatFileStore/path.ts +32 -0
  274. package/src/db/flatFileStore/slotIndex.ts +56 -0
  275. package/src/db/flatFileStore/snappy.ts +14 -0
  276. package/src/db/index.ts +1 -0
  277. package/src/db/interface.ts +9 -1
  278. package/src/db/repositories/blockArchive.ts +89 -30
  279. package/src/db/repositories/blockArchiveIndex.ts +4 -9
  280. package/src/execution/builder/validateBid.ts +10 -6
  281. package/src/execution/engine/mock.ts +4 -1
  282. package/src/metrics/metrics/lodestar.ts +63 -6
  283. package/src/monitoring/clientStats.ts +1 -1
  284. package/src/network/gossip/encoding.ts +0 -7
  285. package/src/network/gossip/topic.ts +3 -25
  286. package/src/network/network.ts +2 -2
  287. package/src/network/processor/gossipHandlers.ts +500 -355
  288. package/src/network/processor/index.ts +287 -165
  289. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +139 -105
  290. package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +2 -0
  291. package/src/network/reqresp/protocols.ts +7 -24
  292. package/src/network/reqresp/rateLimit.ts +2 -1
  293. package/src/network/reqresp/utils/dataColumnResponseValidation.ts +15 -7
  294. package/src/node/nodejs.ts +6 -1
  295. package/src/sync/range/range.ts +23 -1
  296. package/src/util/sszBytes.ts +1 -1
@@ -133,40 +133,37 @@ type BidCandidate = {
133
133
  };
134
134
 
135
135
  /**
136
- * Return the best bid by boosted total payment. A candidate with the max boost factor is
137
- * preferred over any other regardless of value, ties prefer a builder api bid over the
138
- * p2p bid, and the earlier received bid between builder api bids.
136
+ * Ranking value of a bid, the boosted total payment scaled by 100 as `boostFactor` is a percentage.
137
+ * Kept scaled so bids that differ by less than a percent are not truncated into a tie.
139
138
  */
140
- function selectBestBid(candidates: BidCandidate[]): BidCandidate | null {
141
- const boostedValue = ({totalGwei, boostFactor}: BidCandidate): bigint => boostFactor * totalGwei;
142
- let best: BidCandidate | null = null;
143
- for (const candidate of candidates) {
144
- if (best === null) {
145
- best = candidate;
146
- continue;
147
- }
148
- // Preserve max boost preference before comparing bid values
149
- const candidateIsMaxBoost = candidate.boostFactor === MAX_BUILDER_BOOST_FACTOR;
150
- const bestIsMaxBoost = best.boostFactor === MAX_BUILDER_BOOST_FACTOR;
151
- if (candidateIsMaxBoost !== bestIsMaxBoost) {
152
- if (candidateIsMaxBoost) {
153
- best = candidate;
154
- }
155
- continue;
156
- }
157
- const candidateValue = boostedValue(candidate);
158
- const bestValue = boostedValue(best);
159
- if (candidateValue > bestValue) {
160
- best = candidate;
161
- } else if (
162
- candidateValue === bestValue &&
163
- // A tie prefers a builder api bid over the p2p bid, and the earlier received bid otherwise
164
- (best.url === undefined || (candidate.url !== undefined && candidate.receivedMs < best.receivedMs))
165
- ) {
166
- best = candidate;
167
- }
139
+ function getBoostedTotalScaled({totalGwei, boostFactor}: BidCandidate): bigint {
140
+ return boostFactor * totalGwei;
141
+ }
142
+
143
+ /** Order bid candidates by preference, best first, used to select a bid and to log the ranking */
144
+ function compareBidCandidates(a: BidCandidate, b: BidCandidate): number {
145
+ // Preserve max boost preference before comparing bid values
146
+ const aIsMaxBoost = a.boostFactor === MAX_BUILDER_BOOST_FACTOR;
147
+ const bIsMaxBoost = b.boostFactor === MAX_BUILDER_BOOST_FACTOR;
148
+ if (aIsMaxBoost !== bIsMaxBoost) {
149
+ return aIsMaxBoost ? -1 : 1;
168
150
  }
169
- return best;
151
+
152
+ const aBoostedTotal = getBoostedTotalScaled(a);
153
+ const bBoostedTotal = getBoostedTotalScaled(b);
154
+ if (aBoostedTotal !== bBoostedTotal) {
155
+ return aBoostedTotal > bBoostedTotal ? -1 : 1;
156
+ }
157
+
158
+ // A tie prefers a builder api bid over the p2p bid
159
+ const aIsBuilderApi = a.url !== undefined;
160
+ const bIsBuilderApi = b.url !== undefined;
161
+ if (aIsBuilderApi !== bIsBuilderApi) {
162
+ return aIsBuilderApi ? -1 : 1;
163
+ }
164
+
165
+ // and the earlier received bid between builder api bids
166
+ return a.receivedMs - b.receivedMs;
170
167
  }
171
168
 
172
169
  type ProduceBlockContentsRes = {executionPayloadValue: Wei; consensusBlockValue: Wei} & {
@@ -1049,20 +1046,24 @@ export function getValidatorApi(
1049
1046
  });
1050
1047
  }
1051
1048
 
1052
- const best = selectBestBid(candidates);
1053
- if (candidates.length > 0) {
1054
- logger.debug("Ranked builder bid candidates", {
1049
+ if (candidates.length === 0) {
1050
+ return null;
1051
+ }
1052
+
1053
+ const rankedCandidates = candidates.toSorted(compareBidCandidates);
1054
+ for (const [index, candidate] of rankedCandidates.entries()) {
1055
+ logger.debug("Builder bid candidate", {
1055
1056
  slot,
1056
- candidates: candidates
1057
- .map(
1058
- (candidate) =>
1059
- `${candidate.url ?? "p2p"}:total=${prettyGweiToEth(candidate.totalGwei)}:boost=${candidate.boostFactor}:received=${candidate.receivedMs}ms`
1060
- )
1061
- .join(","),
1062
- bidSource: best?.url ?? "p2p",
1057
+ rank: index + 1,
1058
+ source: candidate.url !== undefined ? toPrintableUrl(candidate.url) : "p2p",
1059
+ builder: candidate.signedBid.message.builderIndex,
1060
+ total: prettyGweiToEth(candidate.totalGwei),
1061
+ boost: candidate.boostFactor,
1062
+ boosted: prettyGweiToEth(getBoostedTotalScaled(candidate) / 100n),
1063
+ receivedMs: candidate.receivedMs,
1063
1064
  });
1064
1065
  }
1065
- return best;
1066
+ return rankedCandidates[0];
1066
1067
  })();
1067
1068
 
1068
1069
  const commonBlockBodyPromise = chain.produceCommonBlockBody({
@@ -1,5 +1,6 @@
1
1
  import {CheckpointWithHex} from "@lodestar/fork-choice";
2
2
  import {LoggerNode} from "@lodestar/logger/node";
3
+ import {SLOTS_PER_EPOCH} from "@lodestar/params";
3
4
  import {Checkpoint} from "@lodestar/types/phase0";
4
5
  import {callFnWhenAwait} from "@lodestar/utils";
5
6
  import {IBeaconDb} from "../../db/index.js";
@@ -24,7 +25,11 @@ type ArchiveStoreModules = {
24
25
  metrics: Metrics | null;
25
26
  };
26
27
 
27
- type ArchiveStoreInitOpts = ArchiveStoreOpts & {dbName: string; anchorState: {finalizedCheckpoint: Checkpoint}};
28
+ type ArchiveStoreInitOpts = ArchiveStoreOpts & {
29
+ dbName: string;
30
+ dataColumnDir: string;
31
+ anchorState: {finalizedCheckpoint: Checkpoint};
32
+ };
28
33
 
29
34
  export enum ArchiveStoreTask {
30
35
  ArchiveBlocks = "archive_blocks",
@@ -120,6 +125,7 @@ export class ArchiveStore {
120
125
  opts: {
121
126
  genesisTime: this.chain.clock.genesisTime,
122
127
  dbLocation: this.opts.dbName,
128
+ dataColumnDir: this.opts.dataColumnDir,
123
129
  nativeStateView: this.opts.nativeStateView ?? false,
124
130
  },
125
131
  config: this.chain.config,
@@ -208,6 +214,9 @@ export class ArchiveStore {
208
214
  const finalizedEpoch = finalized.epoch;
209
215
  this.logger.verbose("Start processing finalized checkpoint", {epoch: finalizedEpoch, rootHex: finalized.rootHex});
210
216
 
217
+ // we want to track late imported canonical blocks, but it's not nice to do it at syncig time
218
+ const isNodeSynced = this.chain.clock.currentSlot - this.chain.forkChoice.getHead().slot <= SLOTS_PER_EPOCH;
219
+
211
220
  let timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
212
221
  await archiveBlocks(
213
222
  this.chain.config,
@@ -217,6 +226,8 @@ export class ArchiveStore {
217
226
  this.logger,
218
227
  finalized,
219
228
  this.chain.clock.currentEpoch,
229
+ this.metrics,
230
+ isNodeSynced,
220
231
  this.archiveDataEpochs,
221
232
  this.chain.opts.persistOrphanedBlocks,
222
233
  this.chain.opts.persistOrphanedBlocksDir
@@ -33,6 +33,7 @@ export class HistoricalStateRegen implements HistoricalStateWorkerApi {
33
33
  maxConcurrency: 1,
34
34
  maxLength: 50,
35
35
  dbLocation: modules.opts.dbLocation,
36
+ dataColumnDir: modules.opts.dataColumnDir,
36
37
  metricsEnabled: Boolean(modules.metrics),
37
38
  loggerOpts: modules.logger.toOpts(),
38
39
  nativeStateView: modules.opts.nativeStateView,
@@ -1,7 +1,9 @@
1
1
  import {ForkName} from "@lodestar/params";
2
2
  import {
3
3
  BeaconStateTransitionMetrics,
4
+ BlockProcessStep,
4
5
  EpochTransitionStep,
6
+ ProcessOperationsStep,
5
7
  ProposerRewardType,
6
8
  StateCloneSource,
7
9
  StateHashTreeRootSource,
@@ -70,10 +72,21 @@ export function createHistoricalStateTransitionMetrics(
70
72
  processBlockTime: metricsRegister.histogram({
71
73
  name: "lodestar_historical_state_stfn_process_block_seconds",
72
74
  help: "Time to process a single block in seconds",
73
- // TODO: Add metrics for each step
74
75
  // Block processing can take 5-40ms, 100ms max
75
76
  buckets: [0.005, 0.01, 0.02, 0.05, 0.1, 1],
76
77
  }),
78
+ processBlockStepTime: metricsRegister.histogram<{step: BlockProcessStep}>({
79
+ name: "lodestar_historical_state_stfn_process_block_step_seconds",
80
+ help: "Time to call each step of process block in seconds",
81
+ labelNames: ["step"],
82
+ buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1],
83
+ }),
84
+ processOperationsStepTime: metricsRegister.histogram<{step: ProcessOperationsStep}>({
85
+ name: "lodestar_historical_state_stfn_process_operations_step_seconds",
86
+ help: "Time to call each step of process operations in seconds",
87
+ labelNames: ["step"],
88
+ buckets: [0.001, 0.005, 0.01, 0.025, 0.05, 0.1],
89
+ }),
77
90
  processBlockCommitTime: metricsRegister.histogram({
78
91
  name: "lodestar_historical_state_stfn_process_block_commit_seconds",
79
92
  help: "Time to call commit after process a single block in seconds",
@@ -7,6 +7,7 @@ export type HistoricalStateRegenInitModules = {
7
7
  opts: {
8
8
  genesisTime: number;
9
9
  dbLocation: string;
10
+ dataColumnDir: string;
10
11
  nativeStateView: boolean;
11
12
  };
12
13
  config: BeaconConfig;
@@ -25,6 +26,7 @@ export type HistoricalStateWorkerData = {
25
26
  maxConcurrency: number;
26
27
  maxLength: number;
27
28
  dbLocation: string;
29
+ dataColumnDir: string;
28
30
  metricsEnabled: boolean;
29
31
  loggerOpts: LoggerNodeOpts;
30
32
  nativeStateView: boolean;
@@ -25,7 +25,10 @@ logger.info("Historical state worker started");
25
25
 
26
26
  const config = createBeaconConfig(chainConfigFromJson(workerData.chainConfigJson), workerData.genesisValidatorsRoot);
27
27
 
28
- const db = new BeaconDb(config, await LevelDbController.create({name: workerData.dbLocation}, {logger}));
28
+ const db = new BeaconDb(config, await LevelDbController.create({name: workerData.dbLocation}, {logger}), {
29
+ dataColumnDir: workerData.dataColumnDir,
30
+ logger,
31
+ });
29
32
 
30
33
  const abortController = new AbortController();
31
34
 
@@ -8,6 +8,7 @@ import {Epoch, Slot} from "@lodestar/types";
8
8
  import {Logger, fromAsync, fromHex, prettyPrintIndices, toRootHex} from "@lodestar/utils";
9
9
  import {IBeaconDb} from "../../../db/index.js";
10
10
  import {BlockArchiveBatchPutBinaryItem} from "../../../db/repositories/index.js";
11
+ import {Metrics} from "../../../metrics/metrics.js";
11
12
  import {ensureDir, writeIfNotExist} from "../../../util/file.js";
12
13
  import {BlockRootHex} from "../../../util/sszBytes.js";
13
14
  import {LightClientServer} from "../../lightClient/index.js";
@@ -20,6 +21,16 @@ const BLOB_SIDECAR_BATCH_SIZE = 32;
20
21
 
21
22
  type BlockRootSlot = {slot: Slot; root: Uint8Array};
22
23
 
24
+ /**
25
+ * Why a finalized-canonical block was imported after the attestation cutoff.
26
+ */
27
+ export enum LateCanonicalBlockReason {
28
+ // received on time, but finished importing after the attestation cutoff
29
+ SlowImport = "slow_import",
30
+ // block reached this node late on the network thread
31
+ LateReceive = "late_receive",
32
+ }
33
+
23
34
  /**
24
35
  * Persist orphaned block to disk
25
36
  */
@@ -54,6 +65,8 @@ export async function archiveBlocks(
54
65
  logger: Logger,
55
66
  finalizedCheckpoint: CheckpointWithHex,
56
67
  currentEpoch: Epoch,
68
+ metrics: Metrics | null,
69
+ isNodeSynced: boolean,
57
70
  archiveDataEpochs?: number,
58
71
  persistOrphanedBlocks?: boolean,
59
72
  persistOrphanedBlocksDir?: string
@@ -76,6 +89,29 @@ export async function archiveBlocks(
76
89
 
77
90
  const logCtx = {currentEpoch, finalizedEpoch: finalizedCheckpoint.epoch, finalizedRoot: finalizedCheckpoint.rootHex};
78
91
 
92
+ // `finalizedCanonicalBlocks` is newest -> oldest; its LAST element is the previous-finalized
93
+ // boundary block, already audited on the prior run, so exclude it to avoid double counting.
94
+ if (isNodeSynced && finalizedCanonicalBlocks.length > 1) {
95
+ const lateBlocks = finalizedCanonicalBlocks.slice(0, -1).filter((block) => !block.importedTimely);
96
+ if (lateBlocks.length > 0) {
97
+ let slowImport = 0;
98
+ for (const block of lateBlocks) {
99
+ // received late => late_receive; otherwise we had it on time but were slow to import => slow_import
100
+ const reason = block.timeliness ? LateCanonicalBlockReason.SlowImport : LateCanonicalBlockReason.LateReceive;
101
+ if (block.timeliness) slowImport++;
102
+ metrics?.importBlock.lateCanonicalBlock.inc({reason});
103
+ }
104
+ const lateSlots = lateBlocks.map((block) => block.slot).sort((a, b) => a - b);
105
+ logger.verbose("Late imported canonical blocks", {
106
+ ...logCtx,
107
+ count: lateBlocks.length,
108
+ slowImport,
109
+ lateReceive: lateBlocks.length - slowImport,
110
+ slotRange: prettyPrintIndices(lateSlots),
111
+ });
112
+ }
113
+ }
114
+
79
115
  if (finalizedCanonicalBlockRoots.length > 0) {
80
116
  const migratedSlots = await migrateBlocksFromHotToColdDb(db, logger, finalizedCanonicalBlockRoots);
81
117
  logger.verbose("Migrated blocks from hot DB to cold DB", {
@@ -98,6 +134,8 @@ export async function archiveBlocks(
98
134
  logger.verbose("Migrated blobSidecars from hot DB to cold DB", {...logCtx, migratedEntries});
99
135
  }
100
136
 
137
+ // Keep the normal LevelDB hot-to-cold flow for legacy columns. New columns are written
138
+ // directly to flat files, so this only moves fallback data left by older versions.
101
139
  if (finalizedPostFulu) {
102
140
  const migratedSlots = await migrateDataColumnSidecarsFromHotToColdDb(
103
141
  config,
@@ -106,7 +144,7 @@ export async function archiveBlocks(
106
144
  finalizedCanonicalBlocks,
107
145
  currentEpoch
108
146
  );
109
- logger.verbose("Migrated dataColumnSidecars from hot DB to cold DB", {
147
+ logger.verbose("Migrated legacy dataColumnSidecars from hot DB to cold DB", {
110
148
  ...logCtx,
111
149
  migratedEntries: migratedSlots.length,
112
150
  slotRange: prettyPrintIndices(migratedSlots),
@@ -159,6 +197,23 @@ export async function archiveBlocks(
159
197
  slotRange: prettyPrintIndices(nonCanonicalSlots),
160
198
  };
161
199
 
200
+ const columnItems = finalizedNonCanonicalBlocks
201
+ // Gloas EMPTY and FULL variants share a block root. EMPTY has no sidecars, so deleting by its root could
202
+ // remove the canonical FULL variant's columns. Pre-Gloas blocks are always FULL.
203
+ .filter(
204
+ (summary) => config.getForkSeq(summary.slot) >= ForkSeq.fulu && summary.payloadStatus === PayloadStatus.FULL
205
+ )
206
+ .map((summary) => ({slot: summary.slot, blockRoot: summary.blockRoot}));
207
+ if (columnItems.length > 0) {
208
+ // Delete sidecars first so their block roots remain available to retry cleanup after a failure or crash.
209
+ await db.dataColumns.deleteMany(columnItems);
210
+ logger.verbose("Deleted non canonical data columns of blocks", {
211
+ ...logCtx,
212
+ blocks: columnItems.length,
213
+ slotRange: prettyPrintIndices(columnItems.map(({slot}) => slot).sort((a, b) => a - b)),
214
+ });
215
+ }
216
+
162
217
  await db.block.batchDelete(nonCanonicalBlockRoots);
163
218
  logger.verbose("Deleted non canonical blocks from hot DB", nonCanonicalLogCtx);
164
219
 
@@ -167,11 +222,6 @@ export async function archiveBlocks(
167
222
  logger.verbose("Deleted non canonical blobSidecars from hot DB", nonCanonicalLogCtx);
168
223
  }
169
224
 
170
- if (finalizedPostFulu) {
171
- await db.dataColumnSidecar.deleteMany(nonCanonicalBlockRoots);
172
- logger.verbose("Deleted non canonical dataColumnSidecars from hot DB", nonCanonicalLogCtx);
173
- }
174
-
175
225
  if (finalizedPostGloas) {
176
226
  await db.executionPayloadEnvelope.batchDelete(nonCanonicalBlockRoots);
177
227
  logger.verbose("Deleted non canonical executionPayloadEnvelopes from hot DB", nonCanonicalLogCtx);
@@ -209,23 +259,16 @@ export async function archiveBlocks(
209
259
  );
210
260
  const dataColumnSidecarsMinEpoch = currentEpoch - dataColumnSidecarsArchiveWindow;
211
261
  if (dataColumnSidecarsMinEpoch >= config.FULU_FORK_EPOCH) {
212
- const prefixedKeys = await db.dataColumnSidecarArchive.keys({
213
- // The `id` value `0` refers to the column index. So we want to fetch all sidecars less than zero column of `dataColumnSidecarsMinEpoch`
214
- lt: {prefix: computeStartSlotAtEpoch(dataColumnSidecarsMinEpoch), id: 0},
215
- });
216
- // for each slot there could be multiple dataColumnSidecar, so we need to deduplicate it
217
- const slotsToDelete = [...new Set(prefixedKeys.map(({prefix}) => prefix))].sort((a, b) => a - b);
218
-
219
- if (slotsToDelete.length > 0) {
220
- await db.dataColumnSidecarArchive.deleteMany(slotsToDelete);
262
+ const columnsPruneSlot = computeStartSlotAtEpoch(dataColumnSidecarsMinEpoch);
263
+ const prunedColumnSlots = await db.dataColumns.pruneBefore(columnsPruneSlot);
264
+ if (prunedColumnSlots.length > 0) {
221
265
  logger.verbose("dataColumnSidecars prune", {
222
266
  ...logCtx,
223
- slotRange: prettyPrintIndices(slotsToDelete),
224
- numOfSlots: slotsToDelete.length,
225
- totalNumOfSidecars: prefixedKeys.length,
267
+ slotRange: prettyPrintIndices(prunedColumnSlots),
268
+ numOfSlots: prunedColumnSlots.length,
226
269
  });
227
270
  } else {
228
- logger.verbose(`dataColumnSidecars prune: no entries before epoch ${dataColumnSidecarsMinEpoch}`, logCtx);
271
+ logger.verbose("dataColumnSidecars prune: no entries before slot", {...logCtx, slot: columnsPruneSlot});
229
272
  }
230
273
  } else {
231
274
  logger.verbose(
@@ -298,7 +341,7 @@ async function migrateBlocksFromHotToColdDb(db: IBeaconDb, logger: Logger, block
298
341
  ]);
299
342
  for (const entry of canonicalBlockEntries) migratedSlots.push(entry.slot);
300
343
  }
301
- // Ancestor walk is newest → oldest; sort ascending so `prettyPrintIndices` renders cleanly.
344
+ // Ancestor walk is newest to oldest; sort ascending so `prettyPrintIndices` renders cleanly.
302
345
  return migratedSlots.sort((a, b) => a - b);
303
346
  }
304
347
 
@@ -353,7 +396,6 @@ async function migrateBlobSidecarsFromHotToColdDb(
353
396
  )
354
397
  ).filter((e): e is KeyValue<Slot, Uint8Array> => e !== null);
355
398
 
356
- // put to blockArchive db and delete block db
357
399
  await Promise.all([
358
400
  db.blobSidecarsArchive.batchPutBinary(canonicalBlobSidecarsEntries),
359
401
  db.blobSidecars.batchDelete(canonicalBlocks.map((block) => block.root)),
@@ -366,11 +408,9 @@ async function migrateBlobSidecarsFromHotToColdDb(
366
408
 
367
409
  // TODO: This function can be simplified further by reducing layers of promises in a loop
368
410
  /**
369
- * Post-gloas the data columns of a Gloas block are tied to its execution payload envelope —
370
- * columns only exist once the FULL variant of the block is in the proto-array. Pre-Gloas (Fulu)
371
- * blocks only have a FULL variant, so the `payloadStatus === FULL` filter passes them all.
372
- * Blocks whose canonical variant is PENDING/EMPTY are skipped here — their columns will be picked
373
- * up on a later run once the FULL variant appears in the ancestor walk.
411
+ * Post-gloas the data columns of a Gloas block are tied to its execution payload envelope.
412
+ * Columns only exist once the FULL variant of the block is in the proto-array. Pre-Gloas
413
+ * blocks only have a FULL variant, so the payload-status filter passes them all.
374
414
  */
375
415
  async function migrateDataColumnSidecarsFromHotToColdDb(
376
416
  config: ChainForkConfig,
@@ -392,32 +432,24 @@ async function migrateDataColumnSidecarsFromHotToColdDb(
392
432
  if (batch.length === 0) break;
393
433
 
394
434
  const promises: Promise<void>[] = [];
395
-
396
- // load Buffer instead of ssz deserialized to improve performance
397
435
  for (const block of batch) {
398
- const blockSlot = block.slot;
399
- const blockEpoch = computeEpochAtSlot(blockSlot);
400
-
436
+ const blockEpoch = computeEpochAtSlot(block.slot);
401
437
  if (
402
- config.getForkSeq(blockSlot) < ForkSeq.fulu ||
403
- // if block is out of ${config.MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS}, skip this step
438
+ config.getForkSeq(block.slot) < ForkSeq.fulu ||
404
439
  blockEpoch < currentEpoch - config.MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS
405
440
  ) {
406
441
  continue;
407
442
  }
408
443
 
409
- // Here we assume the data column sidecars are already in the hot db
410
444
  const dataColumnSidecarBytes = await fromAsync(db.dataColumnSidecar.valuesStreamBinary(block.root));
411
445
  if (dataColumnSidecarBytes.length === 0) {
412
- // Empty stream: either the block has no blobs, or columns were already archived on a
413
- // previous run (boundary block). Nothing to migrate.
414
446
  logger.debug("DataColumnSidecars in forkchoice but missing in hot db, could be already archived", {
415
447
  slot: block.slot,
416
448
  root: toRootHex(block.root),
417
449
  });
418
450
  continue;
419
451
  }
420
- logger.verbose("Migrated dataColumnSidecars for block", {
452
+ logger.verbose("Migrated legacy dataColumnSidecars for block", {
421
453
  currentEpoch,
422
454
  slot: block.slot,
423
455
  root: toRootHex(block.root),
@@ -426,18 +458,17 @@ async function migrateDataColumnSidecarsFromHotToColdDb(
426
458
  promises.push(
427
459
  db.dataColumnSidecarArchive.putManyBinary(
428
460
  block.slot,
429
- dataColumnSidecarBytes.map((p) => ({key: p.id, value: p.value}))
461
+ dataColumnSidecarBytes.map((entry) => ({key: entry.id, value: entry.value}))
430
462
  )
431
463
  );
432
464
  migratedSlots.push(block.slot);
433
465
  }
434
466
 
435
- promises.push(db.dataColumnSidecar.deleteMany(batch.map((block) => block.root)));
436
-
437
467
  await Promise.all(promises);
468
+ await db.dataColumnSidecar.deleteMany(batch.map((block) => block.root));
438
469
  }
439
470
 
440
- // Ancestor walk is newest → oldest; sort ascending so `prettyPrintIndices` renders cleanly.
471
+ // Ancestor walk is newest to oldest; sort ascending so `prettyPrintIndices` renders cleanly.
441
472
  return migratedSlots.sort((a, b) => a - b);
442
473
  }
443
474
 
@@ -485,7 +516,7 @@ async function migrateExecutionPayloadEnvelopesFromHotToColdDb(
485
516
  ]);
486
517
 
487
518
  // Slots are ascending in hot-db key order — sort to guarantee `prettyPrintIndices` output is clean
488
- // regardless of ancestor-walk order (newest → oldest).
519
+ // regardless of ancestor-walk order (newest to oldest).
489
520
  return envelopeEntries.map((entry) => entry.key).sort((a, b) => a - b);
490
521
  }
491
522
 
@@ -25,7 +25,17 @@ import {
25
25
  isStatePostAltair,
26
26
  isStatePostBellatrix,
27
27
  } from "@lodestar/state-transition";
28
- import {Attestation, BeaconBlock, altair, capella, electra, isGloasBeaconBlock, phase0, ssz} from "@lodestar/types";
28
+ import {
29
+ Attestation,
30
+ BeaconBlock,
31
+ Epoch,
32
+ altair,
33
+ capella,
34
+ electra,
35
+ isGloasBeaconBlock,
36
+ phase0,
37
+ ssz,
38
+ } from "@lodestar/types";
29
39
  import {isErrorAborted, toRootHex} from "@lodestar/utils";
30
40
  import {GENESIS_SLOT, ZERO_HASH_HEX} from "../../constants/index.js";
31
41
  import {callInNextEventLoop} from "../../util/eventLoop.js";
@@ -44,6 +54,15 @@ import {getCheckpointFromState} from "./utils/checkpoint.js";
44
54
  * Fork-choice allows to import attestations from current (0) or past (1) epoch.
45
55
  */
46
56
  const FORK_CHOICE_ATT_EPOCH_LIMIT = 1;
57
+ /**
58
+ * Whether the attestations of a block at `blockEpoch` are imported into fork choice
59
+ */
60
+ export function importsBlockAttestations(opts: ImportBlockOpts, blockEpoch: Epoch, currentEpoch: Epoch): boolean {
61
+ return (
62
+ opts.importAttestations === AttestationImportOpt.Force ||
63
+ (opts.importAttestations !== AttestationImportOpt.Skip && blockEpoch >= currentEpoch - FORK_CHOICE_ATT_EPOCH_LIMIT)
64
+ );
65
+ }
47
66
  /**
48
67
  * Emit eventstream events for block contents events only for blocks that are recent enough to clock
49
68
  */
@@ -85,7 +104,7 @@ export async function importBlock(
85
104
  const currentEpoch = computeEpochAtSlot(currentSlot);
86
105
  const blockEpoch = computeEpochAtSlot(blockSlot);
87
106
  const prevFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
88
- const blockDelaySec =
107
+ const receiveDelaySec =
89
108
  fullyVerifiedBlock.seenTimestampSec - computeTimeAtSlot(this.config, blockSlot, postState.genesisTime);
90
109
  const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000);
91
110
  const fork = this.config.getForkSeq(blockSlot);
@@ -122,10 +141,12 @@ export async function importBlock(
122
141
  executionStatus = parentBlock.executionStatus;
123
142
  }
124
143
 
144
+ const importDelaySec = this.clock.secFromSlot(blockSlot);
125
145
  const blockSummary = this.forkChoice.onBlock(
126
146
  block.message,
127
147
  postState,
128
- blockDelaySec,
148
+ receiveDelaySec,
149
+ importDelaySec,
129
150
  currentSlot,
130
151
  executionStatus,
131
152
  dataAvailabilityStatus
@@ -147,10 +168,7 @@ export async function importBlock(
147
168
  // Only process attestations of blocks with relevant attestations for the fork-choice:
148
169
  // If current epoch is N, and block is epoch X, block may include attestations for epoch X or X - 1.
149
170
  // The latest block that is useful is at epoch N - 1 which may include attestations for epoch N - 1 or N - 2.
150
- if (
151
- opts.importAttestations === AttestationImportOpt.Force ||
152
- (opts.importAttestations !== AttestationImportOpt.Skip && blockEpoch >= currentEpoch - FORK_CHOICE_ATT_EPOCH_LIMIT)
153
- ) {
171
+ if (importsBlockAttestations(opts, blockEpoch, currentEpoch)) {
154
172
  const attestations = block.message.body.attestations;
155
173
  const rootCache = new RootCache(postState);
156
174
  const invalidAttestationErrorsByCode = new Map<string, {error: Error; count: number}>();
@@ -506,19 +524,6 @@ export async function importBlock(
506
524
  this.metrics?.previousJustifiedEpoch.set(checkpointState.previousJustifiedCheckpoint.epoch);
507
525
  this.metrics?.currentJustifiedEpoch.set(justifiedCheckpoint.epoch);
508
526
  }
509
- const finalizedCheckpoint = checkpointState.finalizedCheckpoint;
510
- const finalizedEpoch = finalizedCheckpoint.epoch;
511
- const preFinalizedEpoch = parentBlockSummary.finalizedEpoch;
512
- if (finalizedEpoch > preFinalizedEpoch) {
513
- this.emitter.emit(routes.events.EventType.finalizedCheckpoint, {
514
- block: toRootHex(finalizedCheckpoint.root),
515
- epoch: finalizedCheckpoint.epoch,
516
- state: toRootHex(checkpointState.hashTreeRoot()),
517
- executionOptimistic: false,
518
- });
519
- this.logger.verbose("Checkpoint finalized", toCheckpointHex(finalizedCheckpoint));
520
- this.metrics?.finalizedEpoch.set(finalizedCheckpoint.epoch);
521
- }
522
527
  }
523
528
  }
524
529