@lodestar/beacon-node 1.44.0-dev.481dde6669 → 1.44.0-dev.4b92b3a1bb

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 (31) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +1 -12
  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 +0 -25
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/validator/index.d.ts.map +1 -1
  8. package/lib/api/impl/validator/index.js +20 -27
  9. package/lib/api/impl/validator/index.js.map +1 -1
  10. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  11. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  12. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  13. package/lib/chain/errors/executionPayloadBid.d.ts +6 -0
  14. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  15. package/lib/chain/errors/executionPayloadBid.js +1 -0
  16. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  17. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  18. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  19. package/lib/chain/validation/executionPayloadBid.js +12 -1
  20. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  21. package/lib/network/gossip/topic.d.ts +2 -2
  22. package/lib/util/sszBytes.js +1 -1
  23. package/package.json +14 -14
  24. package/src/api/impl/beacon/blocks/index.ts +0 -18
  25. package/src/api/impl/beacon/pool/index.ts +1 -41
  26. package/src/api/impl/validator/index.ts +29 -39
  27. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +2 -4
  28. package/src/chain/errors/executionPayloadBid.ts +7 -0
  29. package/src/chain/produceBlock/produceBlockBody.ts +1 -1
  30. package/src/chain/validation/executionPayloadBid.ts +13 -1
  31. package/src/util/sszBytes.ts +1 -1
@@ -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";
@@ -598,23 +597,6 @@ export function getBeaconBlockApi({
598
597
  };
599
598
  },
600
599
 
601
- async getBlockAttestations({blockId}) {
602
- const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
603
- const fork = config.getForkName(block.message.slot);
604
-
605
- if (isForkPostElectra(fork)) {
606
- throw new ApiError(
607
- 400,
608
- `Use getBlockAttestationsV2 to retrieve block attestations for post-electra fork=${fork}`
609
- );
610
- }
611
-
612
- return {
613
- data: block.message.body.attestations,
614
- meta: {executionOptimistic, finalized},
615
- };
616
- },
617
-
618
600
  async getBlockAttestationsV2({blockId}) {
619
601
  const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
620
602
  return {
@@ -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));
@@ -1207,7 +1207,10 @@ export function getValidatorApi(
1207
1207
  const isPostFulu = isForkPostFulu(config.getForkName(startSlot));
1208
1208
  const maxFutureEpoch = isPostFulu && nearNextEpoch && opts?.v2 ? nextEpoch + 1 : nextEpoch;
1209
1209
  if (currentEpoch >= 0 && epoch > maxFutureEpoch) {
1210
- 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
+ );
1211
1214
  }
1212
1215
 
1213
1216
  const head = chain.forkChoice.getHead();
@@ -1291,17 +1294,35 @@ export function getValidatorApi(
1291
1294
  duties.push({slot: startSlot + i, validatorIndex: indexes[i], pubkey: pubkeys[i]});
1292
1295
  }
1293
1296
 
1294
- // Returns `null` on the one-off scenario where the genesis block decides its own shuffling.
1295
- // It should be set to the latest block applied to `self` or the genesis block root.
1296
- const dependentRoot =
1297
- // In v2 the dependent root is different after fulu due to deterministic proposer lookahead
1298
- proposerShufflingDecisionRoot(opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0, state, epoch) ||
1299
- (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});
1300
1321
 
1301
1322
  return {
1302
1323
  data: duties,
1303
1324
  meta: {
1304
- dependentRoot: toRootHex(dependentRoot),
1325
+ dependentRoot: dependentRootHex,
1305
1326
  executionOptimistic: isOptimisticBlock(head),
1306
1327
  },
1307
1328
  };
@@ -1480,33 +1501,6 @@ export function getValidatorApi(
1480
1501
  };
1481
1502
  },
1482
1503
 
1483
- async getAggregatedAttestation({attestationDataRoot, slot}) {
1484
- notWhileSyncing();
1485
-
1486
- await waitForSlot(slot); // Must never request for a future slot > currentSlot
1487
-
1488
- const dataRootHex = toRootHex(attestationDataRoot);
1489
- const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex, null);
1490
- const fork = chain.config.getForkName(slot);
1491
-
1492
- if (isForkPostElectra(fork)) {
1493
- throw new ApiError(
1494
- 400,
1495
- `Use getAggregatedAttestationV2 to retrieve aggregated attestations for post-electra fork=${fork}`
1496
- );
1497
- }
1498
-
1499
- if (!aggregate) {
1500
- throw new ApiError(404, `No aggregated attestation for slot=${slot}, dataRoot=${dataRootHex}`);
1501
- }
1502
-
1503
- metrics?.production.producedAggregateParticipants.observe(aggregate.aggregationBits.getTrueBitIndexes().length);
1504
-
1505
- return {
1506
- data: aggregate,
1507
- };
1508
- },
1509
-
1510
1504
  async getAggregatedAttestationV2({attestationDataRoot, slot, committeeIndex}) {
1511
1505
  notWhileSyncing();
1512
1506
 
@@ -1530,10 +1524,6 @@ export function getValidatorApi(
1530
1524
  };
1531
1525
  },
1532
1526
 
1533
- async publishAggregateAndProofs({signedAggregateAndProofs}) {
1534
- await this.publishAggregateAndProofsV2({signedAggregateAndProofs});
1535
- },
1536
-
1537
1527
  async publishAggregateAndProofsV2({signedAggregateAndProofs}) {
1538
1528
  notWhileSyncing();
1539
1529
 
@@ -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(
@@ -12,6 +12,7 @@ export enum ExecutionPayloadBidErrorCode {
12
12
  UNKNOWN_PARENT_BLOCK_HASH = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_PARENT_BLOCK_HASH",
13
13
  INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
14
14
  NOT_LATER_THAN_PARENT = "EXECUTION_PAYLOAD_BID_ERROR_NOT_LATER_THAN_PARENT",
15
+ INVALID_PREV_RANDAO = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_PREV_RANDAO",
15
16
  INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
16
17
  NO_MATCHING_PROPOSER_PREFERENCES = "EXECUTION_PAYLOAD_BID_ERROR_NO_MATCHING_PROPOSER_PREFERENCES",
17
18
  PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH = "EXECUTION_PAYLOAD_BID_ERROR_PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH",
@@ -43,6 +44,12 @@ export type ExecutionPayloadBidErrorType =
43
44
  | {code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH; parentBlockHash: RootHex}
44
45
  | {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
45
46
  | {code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
47
+ | {
48
+ code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO;
49
+ builderIndex: BuilderIndex;
50
+ bidPrevRandao: string;
51
+ expectedPrevRandao: string;
52
+ }
46
53
  | {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot}
47
54
  | {
48
55
  code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES;
@@ -344,7 +344,7 @@ export async function produceBlockBody<T extends BlockType>(
344
344
  blockHash: executionPayload.blockHash,
345
345
  prevRandao: currentState.getRandaoMix(currentState.epoch),
346
346
  feeRecipient: executionPayload.feeRecipient,
347
- gasLimit: BigInt(executionPayload.gasLimit),
347
+ gasLimit: executionPayload.gasLimit,
348
348
  builderIndex: BUILDER_INDEX_SELF_BUILD,
349
349
  slot: blockSlot,
350
350
  value: 0,
@@ -175,7 +175,7 @@ async function validateExecutionPayloadBid(
175
175
  // [IGNORE] `is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, target_gas_limit)`,
176
176
  // where `parent_gas_limit` is the `gas_limit` of the parent execution payload and
177
177
  // `target_gas_limit` is `proposer_preferences.target_gas_limit`.
178
- const bidGasLimit = Number(bid.gasLimit);
178
+ const bidGasLimit = bid.gasLimit;
179
179
  const parentGasLimit = parentPayloadVariant.executionPayloadGasLimit;
180
180
  const targetGasLimit = proposerPreferences.message.targetGasLimit;
181
181
  if (!isGasLimitTargetCompatible(parentGasLimit, bidGasLimit, targetGasLimit)) {
@@ -232,6 +232,18 @@ async function validateExecutionPayloadBid(
232
232
  });
233
233
  }
234
234
 
235
+ // [REJECT] `bid.prev_randao` is the correct RANDAO mix -- i.e. validate that
236
+ // `bid.prev_randao == get_randao_mix(parent_state, get_current_epoch(parent_state))`.
237
+ const randaoMix = state.getRandaoMix(computeEpochAtSlot(state.slot));
238
+ if (!byteArrayEquals(bid.prevRandao, randaoMix)) {
239
+ throw new ExecutionPayloadBidError(GossipAction.REJECT, {
240
+ code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO,
241
+ builderIndex: bid.builderIndex,
242
+ bidPrevRandao: toHex(bid.prevRandao),
243
+ expectedPrevRandao: toHex(randaoMix),
244
+ });
245
+ }
246
+
235
247
  // [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
236
248
  const signatureSet = createSingleSignatureSetFromComponents(
237
249
  PublicKey.fromBytes(builder.pubkey),
@@ -706,7 +706,7 @@ export function getBlockRootFromPayloadAttestationMessageSerialized(data: Uint8A
706
706
  * blockHash: Bytes32 (32 bytes)
707
707
  * prevRandao: Bytes32 (32 bytes)
708
708
  * feeRecipient: ExecutionAddress(20 bytes)
709
- * gasLimit: UintBn64 (8 bytes)
709
+ * gasLimit: UintNum64 (8 bytes)
710
710
  * builderIndex: BuilderIndex (8 bytes)
711
711
  * slot: Slot (8 bytes) ← absolute offset 264
712
712
  */