@lodestar/beacon-node 1.44.0-dev.f507c14622 → 1.44.0-dev.f6b2af6879

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 (175) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +20 -29
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +1 -26
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/config/constants.d.ts +1 -0
  8. package/lib/api/impl/config/constants.d.ts.map +1 -1
  9. package/lib/api/impl/config/constants.js +2 -1
  10. package/lib/api/impl/config/constants.js.map +1 -1
  11. package/lib/api/impl/debug/index.d.ts.map +1 -1
  12. package/lib/api/impl/debug/index.js +69 -12
  13. package/lib/api/impl/debug/index.js.map +1 -1
  14. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  15. package/lib/api/impl/lodestar/index.js +28 -0
  16. package/lib/api/impl/lodestar/index.js.map +1 -1
  17. package/lib/api/impl/validator/index.d.ts.map +1 -1
  18. package/lib/api/impl/validator/index.js +41 -36
  19. package/lib/api/impl/validator/index.js.map +1 -1
  20. package/lib/chain/archiveStore/archiveStore.d.ts +0 -1
  21. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  22. package/lib/chain/archiveStore/archiveStore.js +0 -4
  23. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  24. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  25. package/lib/chain/blocks/importBlock.js +1 -1
  26. package/lib/chain/blocks/importBlock.js.map +1 -1
  27. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  28. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  29. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  30. package/lib/chain/chain.d.ts.map +1 -1
  31. package/lib/chain/chain.js +8 -1
  32. package/lib/chain/chain.js.map +1 -1
  33. package/lib/chain/emitter.d.ts +2 -1
  34. package/lib/chain/emitter.d.ts.map +1 -1
  35. package/lib/chain/emitter.js.map +1 -1
  36. package/lib/chain/errors/blockError.d.ts +0 -7
  37. package/lib/chain/errors/blockError.d.ts.map +1 -1
  38. package/lib/chain/errors/blockError.js +0 -3
  39. package/lib/chain/errors/blockError.js.map +1 -1
  40. package/lib/chain/errors/executionPayloadBid.d.ts +6 -0
  41. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  42. package/lib/chain/errors/executionPayloadBid.js +1 -0
  43. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  44. package/lib/chain/errors/payloadAttestation.d.ts +6 -0
  45. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
  46. package/lib/chain/errors/payloadAttestation.js +1 -0
  47. package/lib/chain/errors/payloadAttestation.js.map +1 -1
  48. package/lib/chain/forkChoice/index.d.ts +4 -4
  49. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  50. package/lib/chain/forkChoice/index.js +10 -7
  51. package/lib/chain/forkChoice/index.js.map +1 -1
  52. package/lib/chain/options.d.ts.map +1 -1
  53. package/lib/chain/options.js +1 -0
  54. package/lib/chain/options.js.map +1 -1
  55. package/lib/chain/prepareNextSlot.js +1 -1
  56. package/lib/chain/prepareNextSlot.js.map +1 -1
  57. package/lib/chain/produceBlock/produceBlockBody.js +4 -4
  58. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  59. package/lib/chain/regen/interface.d.ts +1 -1
  60. package/lib/chain/regen/interface.d.ts.map +1 -1
  61. package/lib/chain/regen/interface.js +1 -0
  62. package/lib/chain/regen/interface.js.map +1 -1
  63. package/lib/chain/regen/queued.d.ts +0 -1
  64. package/lib/chain/regen/queued.d.ts.map +1 -1
  65. package/lib/chain/regen/queued.js +0 -4
  66. package/lib/chain/regen/queued.js.map +1 -1
  67. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +0 -5
  68. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  69. package/lib/chain/stateCache/fifoBlockStateCache.js +0 -5
  70. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  71. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -4
  72. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  73. package/lib/chain/stateCache/persistentCheckpointsCache.js +5 -2
  74. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  75. package/lib/chain/stateCache/types.d.ts +0 -2
  76. package/lib/chain/stateCache/types.d.ts.map +1 -1
  77. package/lib/chain/stateCache/types.js.map +1 -1
  78. package/lib/chain/validation/block.d.ts +5 -1
  79. package/lib/chain/validation/block.d.ts.map +1 -1
  80. package/lib/chain/validation/block.js +4 -14
  81. package/lib/chain/validation/block.js.map +1 -1
  82. package/lib/chain/validation/executionPayloadBid.js +34 -6
  83. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  84. package/lib/chain/validation/executionPayloadEnvelope.js +0 -2
  85. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  86. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  87. package/lib/chain/validation/payloadAttestationMessage.js +24 -4
  88. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  89. package/lib/metrics/metrics/lodestar.d.ts +4 -0
  90. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  91. package/lib/metrics/metrics/lodestar.js +10 -0
  92. package/lib/metrics/metrics/lodestar.js.map +1 -1
  93. package/lib/network/gossip/topic.d.ts +750 -3
  94. package/lib/network/gossip/topic.d.ts.map +1 -1
  95. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  96. package/lib/network/processor/gossipHandlers.js +10 -3
  97. package/lib/network/processor/gossipHandlers.js.map +1 -1
  98. package/lib/network/processor/index.d.ts +2 -2
  99. package/lib/network/processor/index.d.ts.map +1 -1
  100. package/lib/network/processor/index.js +25 -23
  101. package/lib/network/processor/index.js.map +1 -1
  102. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  103. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +9 -5
  104. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  105. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  106. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +13 -3
  107. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  108. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -1
  109. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
  110. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts +2 -1
  111. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  112. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +16 -6
  113. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  114. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts +2 -1
  115. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  116. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +15 -1
  117. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  118. package/lib/network/reqresp/handlers/index.js +4 -4
  119. package/lib/network/reqresp/handlers/index.js.map +1 -1
  120. package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
  121. package/lib/network/reqresp/utils/dataColumnResponseValidation.js +22 -3
  122. package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
  123. package/lib/sync/types.d.ts +9 -1
  124. package/lib/sync/types.d.ts.map +1 -1
  125. package/lib/sync/types.js +9 -2
  126. package/lib/sync/types.js.map +1 -1
  127. package/lib/sync/unknownBlock.d.ts.map +1 -1
  128. package/lib/sync/unknownBlock.js +64 -30
  129. package/lib/sync/unknownBlock.js.map +1 -1
  130. package/lib/util/dataColumns.d.ts.map +1 -1
  131. package/lib/util/dataColumns.js +16 -11
  132. package/lib/util/dataColumns.js.map +1 -1
  133. package/lib/util/sszBytes.js +1 -1
  134. package/package.json +15 -17
  135. package/src/api/impl/beacon/blocks/index.ts +24 -38
  136. package/src/api/impl/beacon/pool/index.ts +2 -41
  137. package/src/api/impl/config/constants.ts +2 -0
  138. package/src/api/impl/debug/index.ts +73 -12
  139. package/src/api/impl/lodestar/index.ts +30 -0
  140. package/src/api/impl/validator/index.ts +52 -53
  141. package/src/chain/archiveStore/archiveStore.ts +0 -5
  142. package/src/chain/blocks/importBlock.ts +1 -0
  143. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +2 -4
  144. package/src/chain/chain.ts +10 -1
  145. package/src/chain/emitter.ts +3 -2
  146. package/src/chain/errors/blockError.ts +0 -4
  147. package/src/chain/errors/executionPayloadBid.ts +7 -0
  148. package/src/chain/errors/payloadAttestation.ts +2 -0
  149. package/src/chain/forkChoice/index.ts +13 -0
  150. package/src/chain/options.ts +1 -0
  151. package/src/chain/prepareNextSlot.ts +1 -1
  152. package/src/chain/produceBlock/produceBlockBody.ts +4 -4
  153. package/src/chain/regen/interface.ts +1 -1
  154. package/src/chain/regen/queued.ts +0 -5
  155. package/src/chain/stateCache/fifoBlockStateCache.ts +0 -6
  156. package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
  157. package/src/chain/stateCache/types.ts +0 -2
  158. package/src/chain/validation/block.ts +12 -16
  159. package/src/chain/validation/executionPayloadBid.ts +36 -6
  160. package/src/chain/validation/executionPayloadEnvelope.ts +0 -2
  161. package/src/chain/validation/payloadAttestationMessage.ts +26 -4
  162. package/src/metrics/metrics/lodestar.ts +11 -0
  163. package/src/network/processor/gossipHandlers.ts +10 -2
  164. package/src/network/processor/index.ts +27 -27
  165. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +12 -5
  166. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -3
  167. package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
  168. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +22 -6
  169. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +20 -1
  170. package/src/network/reqresp/handlers/index.ts +4 -4
  171. package/src/network/reqresp/utils/dataColumnResponseValidation.ts +21 -3
  172. package/src/sync/types.ts +11 -2
  173. package/src/sync/unknownBlock.ts +70 -31
  174. package/src/util/dataColumns.ts +17 -12
  175. package/src/util/sszBytes.ts +1 -1
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/ChainSafe/lodestar/issues"
13
13
  },
14
- "version": "1.44.0-dev.f507c14622",
14
+ "version": "1.44.0-dev.f6b2af6879",
15
15
  "type": "module",
16
16
  "exports": {
17
17
  ".": {
@@ -116,7 +116,6 @@
116
116
  "@chainsafe/libp2p-quic": "^2.0.1",
117
117
  "@chainsafe/persistent-merkle-tree": "^1.2.5",
118
118
  "@chainsafe/prometheus-gc-stats": "^1.0.0",
119
- "@chainsafe/pubkey-index-map": "^3.0.0",
120
119
  "@chainsafe/snappy-wasm": "^0.5.0",
121
120
  "@chainsafe/ssz": "^1.4.0",
122
121
  "@chainsafe/threads": "^1.11.3",
@@ -127,7 +126,7 @@
127
126
  "@fastify/swagger-ui": "^5.0.1",
128
127
  "@libp2p/bootstrap": "^12.0.14",
129
128
  "@libp2p/crypto": "^5.1.13",
130
- "@libp2p/gossipsub": "^15.0.15",
129
+ "@libp2p/gossipsub": "^16.0.2",
131
130
  "@libp2p/identify": "^4.0.13",
132
131
  "@libp2p/interface": "^3.1.0",
133
132
  "@libp2p/mdns": "^12.0.14",
@@ -135,17 +134,17 @@
135
134
  "@libp2p/peer-id": "^6.0.4",
136
135
  "@libp2p/prometheus-metrics": "^5.0.14",
137
136
  "@libp2p/tcp": "^11.0.13",
138
- "@lodestar/api": "^1.44.0-dev.f507c14622",
139
- "@lodestar/config": "^1.44.0-dev.f507c14622",
140
- "@lodestar/db": "^1.44.0-dev.f507c14622",
141
- "@lodestar/fork-choice": "^1.44.0-dev.f507c14622",
142
- "@lodestar/logger": "^1.44.0-dev.f507c14622",
143
- "@lodestar/params": "^1.44.0-dev.f507c14622",
144
- "@lodestar/reqresp": "^1.44.0-dev.f507c14622",
145
- "@lodestar/state-transition": "^1.44.0-dev.f507c14622",
146
- "@lodestar/types": "^1.44.0-dev.f507c14622",
147
- "@lodestar/utils": "^1.44.0-dev.f507c14622",
148
- "@lodestar/validator": "^1.44.0-dev.f507c14622",
137
+ "@lodestar/api": "^1.44.0-dev.f6b2af6879",
138
+ "@lodestar/config": "^1.44.0-dev.f6b2af6879",
139
+ "@lodestar/db": "^1.44.0-dev.f6b2af6879",
140
+ "@lodestar/fork-choice": "^1.44.0-dev.f6b2af6879",
141
+ "@lodestar/logger": "^1.44.0-dev.f6b2af6879",
142
+ "@lodestar/params": "^1.44.0-dev.f6b2af6879",
143
+ "@lodestar/reqresp": "^1.44.0-dev.f6b2af6879",
144
+ "@lodestar/state-transition": "^1.44.0-dev.f6b2af6879",
145
+ "@lodestar/types": "^1.44.0-dev.f6b2af6879",
146
+ "@lodestar/utils": "^1.44.0-dev.f6b2af6879",
147
+ "@lodestar/validator": "^1.44.0-dev.f6b2af6879",
149
148
  "@multiformats/multiaddr": "^13.0.1",
150
149
  "datastore-core": "^11.0.2",
151
150
  "datastore-fs": "^11.0.2",
@@ -168,13 +167,12 @@
168
167
  "@libp2p/interface-internal": "^3.0.13",
169
168
  "@libp2p/logger": "^6.2.2",
170
169
  "@libp2p/utils": "^7.0.13",
171
- "@lodestar/spec-test-util": "^1.44.0-dev.f507c14622",
170
+ "@lodestar/spec-test-util": "^1.44.0-dev.f6b2af6879",
172
171
  "@types/js-yaml": "^4.0.5",
173
172
  "@types/qs": "^6.9.7",
174
173
  "@types/tmp": "^0.2.3",
175
174
  "dotenv": "^16.4.5",
176
175
  "js-yaml": "^4.1.0",
177
- "rewiremock": "^3.14.5",
178
176
  "rimraf": "^4.4.1",
179
177
  "snappy": "^7.2.2",
180
178
  "snappyjs": "^0.7.0",
@@ -186,5 +184,5 @@
186
184
  "beacon",
187
185
  "blockchain"
188
186
  ],
189
- "gitHead": "059aad4148248818456383065c79122b6c0723b8"
187
+ "gitHead": "305bedad5c6a0415b3bf80f95545761b89fbec58"
190
188
  }
@@ -11,7 +11,6 @@ import {
11
11
  SLOTS_PER_HISTORICAL_ROOT,
12
12
  isForkPostBellatrix,
13
13
  isForkPostDeneb,
14
- isForkPostElectra,
15
14
  isForkPostFulu,
16
15
  isForkPostGloas,
17
16
  } from "@lodestar/params";
@@ -94,7 +93,7 @@ export function getBeaconBlockApi({
94
93
  ApiModules,
95
94
  "chain" | "config" | "metrics" | "network" | "db"
96
95
  >): ApplicationMethods<routes.beacon.block.Endpoints> {
97
- const publishBlock: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlockV2"] = async (
96
+ const publishBlockV2: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlockV2"] = async (
98
97
  {signedBlockContents, broadcastValidation},
99
98
  _context,
100
99
  opts: PublishBlockOpts = {}
@@ -205,11 +204,19 @@ export function getBeaconBlockApi({
205
204
  try {
206
205
  await validateGossipBlock(config, chain, signedBlock, fork);
207
206
  } catch (error) {
208
- if (error instanceof BlockGossipError && error.type.code === BlockErrorCode.ALREADY_KNOWN) {
209
- chain.logger.debug("Ignoring known block during publishing", valLogMeta);
210
- // Blocks might already be published by another node as part of a fallback setup or DVT cluster
211
- // and can reach our node by gossip before the api. The error can be ignored and should not result in a 500 response.
212
- return;
207
+ if (error instanceof BlockGossipError) {
208
+ switch (error.type.code) {
209
+ case BlockErrorCode.ALREADY_KNOWN:
210
+ // Block has already been seen, e.g. via gossip racing the publish API. Benign.
211
+ chain.logger.debug("Ignoring already-known block during publishing", valLogMeta);
212
+ return;
213
+ case BlockErrorCode.REPEAT_PROPOSAL:
214
+ // The proposer already produced a block for this slot. For a solo setup this is a
215
+ // notable signal (duplicate-proposal attempt). For fallback / DVT setups it is
216
+ // expected on every block where another node published first.
217
+ chain.logger.warn("Ignoring repeat-proposal block during publishing", valLogMeta);
218
+ return;
219
+ }
213
220
  }
214
221
 
215
222
  chain.logger.error("Gossip validations failed while publishing the block", valLogMeta, error as Error);
@@ -398,8 +405,8 @@ export function getBeaconBlockApi({
398
405
  }
399
406
  };
400
407
 
401
- const publishBlindedBlock: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlindedBlock"] = async (
402
- {signedBlindedBlock},
408
+ const publishBlindedBlockV2: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlindedBlockV2"] = async (
409
+ {signedBlindedBlock, broadcastValidation},
403
410
  context,
404
411
  opts: PublishBlockOpts = {}
405
412
  ) => {
@@ -429,7 +436,7 @@ export function getBeaconBlockApi({
429
436
  );
430
437
 
431
438
  chain.logger.info("Publishing assembled block", {slot, blockRoot, source});
432
- return publishBlock({signedBlockContents}, {...context, sszBytes: null}, opts);
439
+ return publishBlockV2({signedBlockContents, broadcastValidation}, {...context, sszBytes: null}, opts);
433
440
  }
434
441
 
435
442
  const source = ProducedBlockSource.builder;
@@ -455,7 +462,11 @@ export function getBeaconBlockApi({
455
462
  //
456
463
  // see: https://github.com/ChainSafe/lodestar/issues/5404
457
464
  chain.logger.info("Publishing assembled block", {slot, blockRoot, source});
458
- return publishBlock({signedBlockContents}, {...context, sszBytes: null}, {...opts, ignoreIfKnown: true});
465
+ return publishBlockV2(
466
+ {signedBlockContents, broadcastValidation},
467
+ {...context, sszBytes: null},
468
+ {...opts, ignoreIfKnown: true}
469
+ );
459
470
  }
460
471
  };
461
472
 
@@ -590,23 +601,6 @@ export function getBeaconBlockApi({
590
601
  };
591
602
  },
592
603
 
593
- async getBlockAttestations({blockId}) {
594
- const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
595
- const fork = config.getForkName(block.message.slot);
596
-
597
- if (isForkPostElectra(fork)) {
598
- throw new ApiError(
599
- 400,
600
- `Use getBlockAttestationsV2 to retrieve block attestations for post-electra fork=${fork}`
601
- );
602
- }
603
-
604
- return {
605
- data: block.message.body.attestations,
606
- meta: {executionOptimistic, finalized},
607
- };
608
- },
609
-
610
604
  async getBlockAttestationsV2({blockId}) {
611
605
  const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
612
606
  return {
@@ -654,16 +648,8 @@ export function getBeaconBlockApi({
654
648
  };
655
649
  },
656
650
 
657
- publishBlock,
658
- publishBlindedBlock,
659
-
660
- async publishBlindedBlockV2(args, context, opts) {
661
- await publishBlindedBlock(args, context, opts);
662
- },
663
-
664
- async publishBlockV2(args, context, opts) {
665
- await publishBlock(args, context, opts);
666
- },
651
+ publishBlockV2,
652
+ publishBlindedBlockV2,
667
653
 
668
654
  async publishExecutionPayloadEnvelope({signedExecutionPayloadEnvelope}) {
669
655
  const seenTimestampSec = Date.now() / 1000;
@@ -9,7 +9,7 @@ import {
9
9
  isForkPostGloas,
10
10
  } from "@lodestar/params";
11
11
  import {isStatePostAltair} from "@lodestar/state-transition";
12
- import {Attestation, Epoch, SingleAttestation, isElectraAttestation, ssz, sszTypesFor} from "@lodestar/types";
12
+ import {Epoch, SingleAttestation, isElectraAttestation, ssz, sszTypesFor} from "@lodestar/types";
13
13
  import {toRootHex} from "@lodestar/utils";
14
14
  import {
15
15
  AttestationError,
@@ -40,25 +40,6 @@ export function getBeaconPoolApi({
40
40
  network,
41
41
  }: Pick<ApiModules, "chain" | "logger" | "metrics" | "network">): ApplicationMethods<routes.beacon.pool.Endpoints> {
42
42
  return {
43
- async getPoolAttestations({slot, committeeIndex}) {
44
- // Already filtered by slot
45
- let attestations: Attestation[] = chain.aggregatedAttestationPool.getAll(slot);
46
- const fork = chain.config.getForkName(slot ?? chain.clock.currentSlot);
47
-
48
- if (isForkPostElectra(fork)) {
49
- throw new ApiError(
50
- 400,
51
- `Use getPoolAttestationsV2 to retrieve pool attestations for post-electra fork=${fork}`
52
- );
53
- }
54
-
55
- if (committeeIndex !== undefined) {
56
- attestations = attestations.filter((attestation) => committeeIndex === attestation.data.index);
57
- }
58
-
59
- return {data: attestations};
60
- },
61
-
62
43
  async getPoolAttestationsV2({slot, committeeIndex}) {
63
44
  // Already filtered by slot
64
45
  let attestations = chain.aggregatedAttestationPool.getAll(slot);
@@ -134,19 +115,6 @@ export function getBeaconPoolApi({
134
115
  }
135
116
  },
136
117
 
137
- async getPoolAttesterSlashings() {
138
- const fork = chain.config.getForkName(chain.clock.currentSlot);
139
-
140
- if (isForkPostElectra(fork)) {
141
- throw new ApiError(
142
- 400,
143
- `Use getPoolAttesterSlashingsV2 to retrieve pool attester slashings for post-electra fork=${fork}`
144
- );
145
- }
146
-
147
- return {data: chain.opPool.getAllAttesterSlashings()};
148
- },
149
-
150
118
  async getPoolAttesterSlashingsV2() {
151
119
  const fork = chain.config.getForkName(chain.clock.currentSlot);
152
120
  return {data: chain.opPool.getAllAttesterSlashings(), meta: {version: fork}};
@@ -164,10 +132,6 @@ export function getBeaconPoolApi({
164
132
  return {data: chain.opPool.getAllBlsToExecutionChanges().map(({data}) => data)};
165
133
  },
166
134
 
167
- async submitPoolAttestations({signedAttestations}) {
168
- await this.submitPoolAttestationsV2({signedAttestations});
169
- },
170
-
171
135
  async submitPoolAttestationsV2({signedAttestations}) {
172
136
  const fork = chain.config.getForkName(chain.clock.currentSlot);
173
137
  const seenTimestampSec = Date.now() / 1000;
@@ -247,10 +211,6 @@ export function getBeaconPoolApi({
247
211
  }
248
212
  },
249
213
 
250
- async submitPoolAttesterSlashings({attesterSlashing}) {
251
- await this.submitPoolAttesterSlashingsV2({attesterSlashing});
252
- },
253
-
254
214
  async submitPoolAttesterSlashingsV2({attesterSlashing}) {
255
215
  await validateApiAttesterSlashing(chain, attesterSlashing);
256
216
  const fork = chain.config.getForkName(Number(attesterSlashing.attestation1.data.slot));
@@ -328,6 +288,7 @@ export function getBeaconPoolApi({
328
288
 
329
289
  chain.forkChoice.notifyPtcMessages(
330
290
  toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
291
+ payloadAttestationMessage.data.slot,
331
292
  validatorCommitteeIndices,
332
293
  payloadAttestationMessage.data.payloadPresent,
333
294
  payloadAttestationMessage.data.blobDataAvailable
@@ -53,6 +53,7 @@ import {
53
53
  VERSIONED_HASH_VERSION_KZG,
54
54
  WEIGHT_DENOMINATOR,
55
55
  WITHDRAWAL_REQUEST_TYPE,
56
+ ZERO_HASH_HEX,
56
57
  } from "@lodestar/params";
57
58
 
58
59
  /**
@@ -69,6 +70,7 @@ export const specConstants = {
69
70
  DEPOSIT_CONTRACT_TREE_DEPTH,
70
71
  JUSTIFICATION_BITS_LENGTH,
71
72
  ENDIANNESS: "little",
73
+ EMPTY_BLOCK_HASH: ZERO_HASH_HEX,
72
74
  // ## Withdrawal prefixes
73
75
  BLS_WITHDRAWAL_PREFIX: toHexByte(BLS_WITHDRAWAL_PREFIX),
74
76
  ETH1_ADDRESS_WITHDRAWAL_PREFIX: toHexByte(ETH1_ADDRESS_WITHDRAWAL_PREFIX),
@@ -1,7 +1,8 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {ApplicationMethods} from "@lodestar/api/server";
3
- import {ExecutionStatus} from "@lodestar/fork-choice";
3
+ import {ExecutionStatus, PayloadStatus} from "@lodestar/fork-choice";
4
4
  import {ForkPostDeneb, ZERO_HASH_HEX, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
5
+ import {computeTimeAtSlot} from "@lodestar/state-transition";
5
6
  import {BeaconState, DataColumnSidecar, DataColumnSidecars, type SignedBeaconBlock, sszTypesFor} from "@lodestar/types";
6
7
  import {toRootHex} from "@lodestar/utils";
7
8
  import {getBlobKzgCommitments} from "../../../util/dataColumns.js";
@@ -12,6 +13,29 @@ import {getStateResponseWithRegen} from "../beacon/state/utils.js";
12
13
  import {ApiModules} from "../types.js";
13
14
  import {assertUniqueItems} from "../utils.js";
14
15
 
16
+ function toForkChoiceValidity(status: ExecutionStatus): "valid" | "invalid" | "optimistic" {
17
+ switch (status) {
18
+ case ExecutionStatus.Valid:
19
+ return "valid";
20
+ case ExecutionStatus.Invalid:
21
+ return "invalid";
22
+ case ExecutionStatus.Syncing:
23
+ case ExecutionStatus.PreMerge:
24
+ return "optimistic";
25
+ }
26
+ }
27
+
28
+ function toPayloadStatusName(status: PayloadStatus): "pending" | "empty" | "full" {
29
+ switch (status) {
30
+ case PayloadStatus.PENDING:
31
+ return "pending";
32
+ case PayloadStatus.EMPTY:
33
+ return "empty";
34
+ case PayloadStatus.FULL:
35
+ return "full";
36
+ }
37
+ }
38
+
15
39
  export function getDebugApi({
16
40
  chain,
17
41
  config,
@@ -40,23 +64,60 @@ export function getDebugApi({
40
64
  justifiedEpoch: node.justifiedEpoch,
41
65
  finalizedEpoch: node.finalizedEpoch,
42
66
  weight: node.weight,
43
- validity: (() => {
44
- switch (node.executionStatus) {
45
- case ExecutionStatus.Valid:
46
- return "valid";
47
- case ExecutionStatus.Invalid:
48
- return "invalid";
49
- case ExecutionStatus.Syncing:
50
- case ExecutionStatus.PreMerge:
51
- return "optimistic";
52
- }
53
- })(),
67
+ validity: toForkChoiceValidity(node.executionStatus),
54
68
  executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX,
55
69
  })),
56
70
  },
57
71
  };
58
72
  },
59
73
 
74
+ async getDebugForkChoiceV2() {
75
+ const {forkChoice} = chain;
76
+ return {
77
+ data: {
78
+ justifiedCheckpoint: forkChoice.getJustifiedCheckpoint(),
79
+ finalizedCheckpoint: forkChoice.getFinalizedCheckpoint(),
80
+ forkChoiceNodes: forkChoice.getAllNodes().map((node) => {
81
+ // Payload-specific fields apply only to a revealed Gloas payload = the FULL variant of a
82
+ // Gloas block
83
+ const ptc = node.payloadStatus === PayloadStatus.FULL ? forkChoice.getPTCVoteCounts(node.blockRoot) : null;
84
+ return {
85
+ payloadStatus: toPayloadStatusName(node.payloadStatus),
86
+ slot: node.slot,
87
+ blockRoot: node.blockRoot,
88
+ parentRoot: node.parentRoot,
89
+ weight: node.weight,
90
+ validity: toForkChoiceValidity(node.executionStatus),
91
+ executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX,
92
+ extraData: {
93
+ executionOptimistic: isOptimisticBlock(node),
94
+ timestamp: computeTimeAtSlot(config, node.slot, chain.genesisTime),
95
+ target: node.targetRoot,
96
+ justifiedEpoch: node.justifiedEpoch,
97
+ finalizedEpoch: node.finalizedEpoch,
98
+ unrealizedJustifiedEpoch: node.unrealizedJustifiedEpoch,
99
+ unrealizedFinalizedEpoch: node.unrealizedFinalizedEpoch,
100
+ payloadAttesterCount: ptc?.attesterCount ?? null,
101
+ payloadAvailabilityYesCount: ptc?.payloadPresentCount ?? null,
102
+ payloadDataAvailabilityYesCount: ptc?.dataAvailableCount ?? null,
103
+ gasLimit:
104
+ node.payloadStatus === PayloadStatus.FULL && "executionPayloadGasLimit" in node
105
+ ? node.executionPayloadGasLimit
106
+ : null,
107
+ },
108
+ };
109
+ }),
110
+ extraData: {
111
+ unrealizedJustifiedCheckpoint: forkChoice.getUnrealizedJustifiedCheckpoint(),
112
+ unrealizedFinalizedCheckpoint: forkChoice.getUnrealizedFinalizedCheckpoint(),
113
+ proposerBoostRoot: forkChoice.getProposerBoostRoot(),
114
+ previousProposerBoostRoot: forkChoice.getPreviousProposerBoostRoot(),
115
+ headRoot: forkChoice.getHeadRoot(),
116
+ },
117
+ },
118
+ };
119
+ },
120
+
60
121
  async getProtoArrayNodes() {
61
122
  const nodes = chain.forkChoice.getAllNodes().map((node) => ({
62
123
  // if node has executionPayloadNumber, it will overwrite the below default
@@ -280,6 +280,36 @@ export function getLodestarApi({
280
280
  };
281
281
  },
282
282
 
283
+ async getFastConfirmationInfo() {
284
+ const confirmedRoot = chain.forkChoice.getConfirmedRoot();
285
+ const confirmedBlock = chain.forkChoice.getConfirmedBlock();
286
+ const justifiedCheckpoint = chain.forkChoice.getJustifiedCheckpoint();
287
+ const finalizedCheckpoint = chain.forkChoice.getFinalizedCheckpoint();
288
+ const headRoot = chain.forkChoice.getHeadRoot();
289
+ const head = chain.forkChoice.getHead();
290
+
291
+ return {
292
+ data: {
293
+ confirmed: {
294
+ rootHex: confirmedRoot,
295
+ slot: confirmedBlock?.slot ?? null,
296
+ },
297
+ head: {
298
+ rootHex: headRoot,
299
+ slot: head.slot,
300
+ },
301
+ justifiedCheckpoint: {
302
+ rootHex: justifiedCheckpoint.rootHex,
303
+ epoch: justifiedCheckpoint.epoch,
304
+ },
305
+ finalizedCheckpoint: {
306
+ rootHex: finalizedCheckpoint.rootHex,
307
+ epoch: finalizedCheckpoint.epoch,
308
+ },
309
+ },
310
+ };
311
+ },
312
+
283
313
  async getAttesterSlashingsFromBlocks({signedBlocks}) {
284
314
  const attestations = new Map<Epoch, Attestation[]>();
285
315
 
@@ -927,11 +927,9 @@ export function getValidatorApi(
927
927
  // TODO GLOAS: respect builderSelection (MaxProfit, BuilderAlways, ExecutionAlways, etc.) to let
928
928
  // the user control bid source preferences and value comparison. Also add external builder api
929
929
  // support when it is implemented.
930
- const builderBid = chain.executionPayloadBidPool.getBestBid(
931
- slot,
932
- parentBlock.executionPayloadBlockHash,
933
- parentBlockRootHex
934
- );
930
+ const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
931
+ const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
932
+ const builderBid = chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
935
933
 
936
934
  const logCtx = {
937
935
  slot,
@@ -1112,23 +1110,34 @@ export function getValidatorApi(
1112
1110
  notWhileSyncing();
1113
1111
  await waitForSlot(slot);
1114
1112
 
1115
- const block = chain.forkChoice.getCanonicalBlockClosestLteSlot(slot);
1113
+ const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
1116
1114
  if (!block) {
1117
- throw new ApiError(404, `No canonical block found at or before slot=${slot}`);
1115
+ // No block is seen at slot. Return 404 so vc can skip casting payload attestation.
1116
+ throw new ApiError(404, `No canonical block found at slot=${slot}`);
1118
1117
  }
1119
1118
 
1120
- const blockIsForSlot = block.slot === slot;
1121
1119
  const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
1122
1120
  // Spec: set payload_present only if the envelope was seen before get_payload_due_ms()
1123
1121
  // into the slot. Use the envelope's own arrival time (getPayloadEnvelopeSource), not
1124
1122
  // the input's creation time.
1125
1123
  const payloadDueSec = config.getPayloadDueMs() / 1000;
1126
- const payloadPresent =
1127
- blockIsForSlot &&
1128
- payloadInput !== undefined &&
1129
- payloadInput.hasPayloadEnvelope() &&
1130
- chain.clock.secFromSlot(slot, payloadInput.getPayloadEnvelopeSource().seenTimestampSec) < payloadDueSec;
1131
- const blobDataAvailable = blockIsForSlot && (payloadInput?.hasAllData() ?? false);
1124
+ const payloadSeenSec =
1125
+ payloadInput?.hasPayloadEnvelope() === true
1126
+ ? chain.clock.secFromSlot(slot, payloadInput.getPayloadEnvelopeSource().seenTimestampSec)
1127
+ : null;
1128
+ const payloadPresent = payloadSeenSec !== null && payloadSeenSec < payloadDueSec;
1129
+ const blobDataAvailable = payloadInput?.hasAllData() === true;
1130
+
1131
+ logger.debug("Produced payload attestation data", {
1132
+ slot,
1133
+ blockRoot: block.blockRoot,
1134
+ blockSlot: block.slot,
1135
+ payloadPresent,
1136
+ blobDataAvailable,
1137
+ hasPayloadInput: payloadInput !== undefined,
1138
+ payloadSeenSec,
1139
+ payloadDueSec,
1140
+ });
1132
1141
 
1133
1142
  return {
1134
1143
  data: {
@@ -1198,7 +1207,10 @@ export function getValidatorApi(
1198
1207
  const isPostFulu = isForkPostFulu(config.getForkName(startSlot));
1199
1208
  const maxFutureEpoch = isPostFulu && nearNextEpoch && opts?.v2 ? nextEpoch + 1 : nextEpoch;
1200
1209
  if (currentEpoch >= 0 && epoch > maxFutureEpoch) {
1201
- throw new ApiError(400, `Requested epoch ${epoch} must not be more than one epoch in the future`);
1210
+ throw new ApiError(
1211
+ 400,
1212
+ `Requested epoch ${epoch} must not be more than ${maxFutureEpoch}, currentEpoch=${currentEpoch}, v2=${opts?.v2 ?? false}`
1213
+ );
1202
1214
  }
1203
1215
 
1204
1216
  const head = chain.forkChoice.getHead();
@@ -1282,17 +1294,35 @@ export function getValidatorApi(
1282
1294
  duties.push({slot: startSlot + i, validatorIndex: indexes[i], pubkey: pubkeys[i]});
1283
1295
  }
1284
1296
 
1285
- // Returns `null` on the one-off scenario where the genesis block decides its own shuffling.
1286
- // It should be set to the latest block applied to `self` or the genesis block root.
1287
- const dependentRoot =
1288
- // In v2 the dependent root is different after fulu due to deterministic proposer lookahead
1289
- proposerShufflingDecisionRoot(opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0, state, epoch) ||
1290
- (await getGenesisBlockRoot(state));
1297
+ // In v2 the dependent root is different after fulu due to deterministic proposer lookahead
1298
+ let dependentRoot = proposerShufflingDecisionRoot(
1299
+ opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0,
1300
+ state,
1301
+ epoch
1302
+ );
1303
+ const logCtx = {
1304
+ epoch,
1305
+ stateSlot: state.slot,
1306
+ stateEpoch: state.epoch,
1307
+ v2: opts?.v2 ?? false,
1308
+ };
1309
+ if (dependentRoot === null) {
1310
+ // fallback to get_proposer_duties() v1, also in lodestar v1.43
1311
+ logger.verbose("Proposer duties decision root not in state, falling back to state epoch", logCtx);
1312
+ dependentRoot = proposerShufflingDecisionRoot(ForkName.phase0, state, state.epoch);
1313
+ }
1314
+ if (dependentRoot === null) {
1315
+ logger.verbose("Proposer duties decision root not in state, falling back to genesis block root", logCtx);
1316
+ dependentRoot = await getGenesisBlockRoot(state);
1317
+ }
1318
+
1319
+ const dependentRootHex = toRootHex(dependentRoot);
1320
+ logger.verbose("Computed proposer duties decision root", {...logCtx, dependentRoot: dependentRootHex});
1291
1321
 
1292
1322
  return {
1293
1323
  data: duties,
1294
1324
  meta: {
1295
- dependentRoot: toRootHex(dependentRoot),
1325
+ dependentRoot: dependentRootHex,
1296
1326
  executionOptimistic: isOptimisticBlock(head),
1297
1327
  },
1298
1328
  };
@@ -1471,33 +1501,6 @@ export function getValidatorApi(
1471
1501
  };
1472
1502
  },
1473
1503
 
1474
- async getAggregatedAttestation({attestationDataRoot, slot}) {
1475
- notWhileSyncing();
1476
-
1477
- await waitForSlot(slot); // Must never request for a future slot > currentSlot
1478
-
1479
- const dataRootHex = toRootHex(attestationDataRoot);
1480
- const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex, null);
1481
- const fork = chain.config.getForkName(slot);
1482
-
1483
- if (isForkPostElectra(fork)) {
1484
- throw new ApiError(
1485
- 400,
1486
- `Use getAggregatedAttestationV2 to retrieve aggregated attestations for post-electra fork=${fork}`
1487
- );
1488
- }
1489
-
1490
- if (!aggregate) {
1491
- throw new ApiError(404, `No aggregated attestation for slot=${slot}, dataRoot=${dataRootHex}`);
1492
- }
1493
-
1494
- metrics?.production.producedAggregateParticipants.observe(aggregate.aggregationBits.getTrueBitIndexes().length);
1495
-
1496
- return {
1497
- data: aggregate,
1498
- };
1499
- },
1500
-
1501
1504
  async getAggregatedAttestationV2({attestationDataRoot, slot, committeeIndex}) {
1502
1505
  notWhileSyncing();
1503
1506
 
@@ -1521,10 +1524,6 @@ export function getValidatorApi(
1521
1524
  };
1522
1525
  },
1523
1526
 
1524
- async publishAggregateAndProofs({signedAggregateAndProofs}) {
1525
- await this.publishAggregateAndProofsV2({signedAggregateAndProofs});
1526
- },
1527
-
1528
1527
  async publishAggregateAndProofsV2({signedAggregateAndProofs}) {
1529
1528
  notWhileSyncing();
1530
1529
 
@@ -30,7 +30,6 @@ export enum ArchiveStoreTask {
30
30
  PruneHistory = "prune_history",
31
31
  OnFinalizedCheckpoint = "on_finalized_checkpoint",
32
32
  MaybeArchiveState = "maybe_archive_state",
33
- RegenPruneOnFinalized = "regen_prune_on_finalized",
34
33
  ForkchoicePrune = "forkchoice_prune",
35
34
  UpdateBackfillRange = "update_backfill_range",
36
35
  }
@@ -229,10 +228,6 @@ export class ArchiveStore {
229
228
  await this.statesArchiverStrategy.maybeArchiveState(finalized, this.metrics);
230
229
  timer?.({source: ArchiveStoreTask.MaybeArchiveState});
231
230
 
232
- timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
233
- this.chain.regen.pruneOnFinalized(finalizedEpoch);
234
- timer?.({source: ArchiveStoreTask.RegenPruneOnFinalized});
235
-
236
231
  // tasks rely on extended fork choice
237
232
  timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
238
233
  const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex);
@@ -263,6 +263,7 @@ export async function importBlock(
263
263
  if (ptcIndices.length > 0) {
264
264
  this.forkChoice.notifyPtcMessages(
265
265
  toRootHex(payloadAttestation.data.beaconBlockRoot),
266
+ payloadAttestation.data.slot,
266
267
  ptcIndices,
267
268
  payloadAttestation.data.payloadPresent,
268
269
  payloadAttestation.data.blobDataAvailable
@@ -61,10 +61,8 @@ export function verifyExecutionPayloadEnvelope(
61
61
  `Prev randao mismatch between bid and payload bid=${toHex(bid.prevRandao)} payload=${toHex(payload.prevRandao)}`
62
62
  );
63
63
  }
64
- if (Number(bid.gasLimit) !== payload.gasLimit) {
65
- throw new Error(
66
- `Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${Number(bid.gasLimit)}`
67
- );
64
+ if (bid.gasLimit !== payload.gasLimit) {
65
+ throw new Error(`Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${bid.gasLimit}`);
68
66
  }
69
67
  if (!byteArrayEquals(bid.blockHash, payload.blockHash)) {
70
68
  throw new Error(