@lodestar/beacon-node 1.48.0-dev.b24dce51bf → 1.48.0-dev.b5f4a8f2c6

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 (56) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +0 -7
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/config/index.d.ts.map +1 -1
  5. package/lib/api/impl/config/index.js +4 -1
  6. package/lib/api/impl/config/index.js.map +1 -1
  7. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  8. package/lib/chain/archiveStore/archiveStore.js +4 -1
  9. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  10. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +9 -1
  11. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  12. package/lib/chain/archiveStore/utils/archiveBlocks.js +37 -4
  13. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  14. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  15. package/lib/chain/blocks/importBlock.js +3 -2
  16. package/lib/chain/blocks/importBlock.js.map +1 -1
  17. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  18. package/lib/chain/blocks/utils/chainSegment.js +16 -10
  19. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  20. package/lib/chain/errors/executionPayloadBid.d.ts +4 -0
  21. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  22. package/lib/chain/errors/executionPayloadBid.js +1 -0
  23. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  24. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  25. package/lib/chain/forkChoice/index.js +2 -0
  26. package/lib/chain/forkChoice/index.js.map +1 -1
  27. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  28. package/lib/chain/validation/executionPayloadBid.js +16 -0
  29. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  30. package/lib/execution/builder/validateBid.d.ts.map +1 -1
  31. package/lib/execution/builder/validateBid.js +3 -0
  32. package/lib/execution/builder/validateBid.js.map +1 -1
  33. package/lib/metrics/metrics/lodestar.d.ts +4 -3
  34. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  35. package/lib/metrics/metrics/lodestar.js +5 -5
  36. package/lib/metrics/metrics/lodestar.js.map +1 -1
  37. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  38. package/lib/network/processor/gossipHandlers.js +378 -278
  39. package/lib/network/processor/gossipHandlers.js.map +1 -1
  40. package/lib/network/processor/index.d.ts.map +1 -1
  41. package/lib/network/processor/index.js +11 -16
  42. package/lib/network/processor/index.js.map +1 -1
  43. package/package.json +14 -14
  44. package/src/api/impl/beacon/blocks/index.ts +0 -10
  45. package/src/api/impl/config/index.ts +4 -1
  46. package/src/chain/archiveStore/archiveStore.ts +6 -0
  47. package/src/chain/archiveStore/utils/archiveBlocks.ts +39 -3
  48. package/src/chain/blocks/importBlock.ts +4 -2
  49. package/src/chain/blocks/utils/chainSegment.ts +16 -11
  50. package/src/chain/errors/executionPayloadBid.ts +2 -0
  51. package/src/chain/forkChoice/index.ts +2 -0
  52. package/src/chain/validation/executionPayloadBid.ts +18 -0
  53. package/src/execution/builder/validateBid.ts +4 -0
  54. package/src/metrics/metrics/lodestar.ts +6 -5
  55. package/src/network/processor/gossipHandlers.ts +487 -348
  56. package/src/network/processor/index.ts +11 -17
@@ -37,17 +37,6 @@ export function assertLinearChainSegment(
37
37
 
38
38
  const warnings: OrphanedPayloadEnvelope[] = [];
39
39
 
40
- let parentExecHash: string | null = parentBlock?.executionPayloadBlockHash ?? null;
41
- if (parentBlock !== null) {
42
- const parentPayloadInput = payloadEnvelopes?.get(parentBlock.slot);
43
- if (parentPayloadInput?.hasPayloadEnvelope()) {
44
- // Checkpoint-sync first batch: the anchor is stored PENDING with the inherited (grandparent)
45
- // hash, not its own payload. Its payload envelope is in this batch, so use that blockHash as
46
- // the real parent EL head.
47
- parentExecHash = parentPayloadInput.getBlockHashHex();
48
- }
49
- }
50
-
51
40
  // Track the expected execution payload block hash through the segment, seeded from the FIRST
52
41
  // block's own bid
53
42
  const firstBlockMessage = blocks[0].getBlock().message;
@@ -55,6 +44,22 @@ export function assertLinearChainSegment(
55
44
  ? toRootHex(firstBlockMessage.body.signedExecutionPayloadBid.message.parentBlockHash)
56
45
  : null;
57
46
 
47
+ let parentExecHash: string | null = parentBlock?.executionPayloadBlockHash ?? null;
48
+ if (parentBlock !== null) {
49
+ const parentPayloadInput = payloadEnvelopes?.get(parentBlock.slot);
50
+ if (parentPayloadInput?.hasPayloadEnvelope()) {
51
+ const parentPayloadBlockHash = parentPayloadInput.getBlockHashHex();
52
+ if (currentExecHash === parentPayloadBlockHash) {
53
+ // Checkpoint-sync first batch: the anchor is stored PENDING with the inherited (grandparent)
54
+ // hash, its own payload is in this batch and is the real parent EL head
55
+ parentExecHash = parentPayloadBlockHash;
56
+ } else {
57
+ // First block builds on the parent's EMPTY variant, the parent's payload in this batch is orphaned
58
+ warnings.push({slot: parentBlock.slot, payloadEnvelopeInput: parentPayloadInput});
59
+ }
60
+ }
61
+ }
62
+
58
63
  // First block must build on the parent's EL head. PARENT_PAYLOAD_UNKNOWN (vs the in-segment
59
64
  // NON_LINEAR_PAYLOAD_ROOTS below) tells range sync this is a parent-link problem, not an in-batch one.
60
65
  if (parentExecHash !== null && currentExecHash !== null && currentExecHash !== parentExecHash) {
@@ -5,6 +5,7 @@ export enum ExecutionPayloadBidErrorCode {
5
5
  BUILDER_NOT_ELIGIBLE = "EXECUTION_PAYLOAD_BID_ERROR_BUILDER_NOT_ELIGIBLE",
6
6
  INVALID_BUILDER_VERSION = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_BUILDER_VERSION",
7
7
  NON_ZERO_EXECUTION_PAYMENT = "EXECUTION_PAYLOAD_BID_ERROR_NON_ZERO_EXECUTION_PAYMENT",
8
+ BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH = "EXECUTION_PAYLOAD_BID_ERROR_BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH",
8
9
  INCOMPATIBLE_WITH_HEAD = "EXECUTION_PAYLOAD_BID_ERROR_INCOMPATIBLE_WITH_HEAD",
9
10
  BID_ALREADY_KNOWN = "EXECUTION_PAYLOAD_BID_ERROR_BID_ALREADY_KNOWN",
10
11
  BID_TOO_LOW = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_LOW",
@@ -63,6 +64,7 @@ export type ExecutionPayloadBidErrorType =
63
64
  }
64
65
  | {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
65
66
  | {code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH; parentBlockHash: RootHex}
67
+ | {code: ExecutionPayloadBidErrorCode.BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH; blockHash: RootHex}
66
68
  | {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
67
69
  | {code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
68
70
  | {
@@ -135,6 +135,7 @@ export function initializeForkChoiceFromFinalizedState(
135
135
  blockRoot: toRootHex(checkpoint.root),
136
136
  timeliness: true, // Optimistically assume is timely
137
137
  ptcTimeliness: true, // Spec: block_timeliness for anchor = [True, True]
138
+ importedTimely: true, // Optimistically assume is timely
138
139
  proposerIndex: blockHeader.proposerIndex,
139
140
 
140
141
  justifiedEpoch: justifiedCheckpoint.epoch,
@@ -233,6 +234,7 @@ export function initializeForkChoiceFromUnfinalizedState(
233
234
  targetRoot: headRoot,
234
235
  timeliness: true, // Optimistically assume is timely
235
236
  ptcTimeliness: true, // Spec: block_timeliness for anchor = [True, True]
237
+ importedTimely: true, // Optimistically assume is timely
236
238
  proposerIndex: blockHeader.proposerIndex,
237
239
 
238
240
  justifiedEpoch: justifiedCheckpoint.epoch,
@@ -113,6 +113,15 @@ export async function validateApiExecutionPayloadBid(
113
113
  });
114
114
  }
115
115
 
116
+ // [REJECT] The bid's block hash is not equal to its parent block hash -- i.e.
117
+ // `bid.block_hash != bid.parent_block_hash`.
118
+ if (byteArrayEquals(bid.blockHash, bid.parentBlockHash)) {
119
+ throw new ExecutionPayloadBidError(GossipAction.REJECT, {
120
+ code: ExecutionPayloadBidErrorCode.BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH,
121
+ blockHash: toRootHex(bid.blockHash),
122
+ });
123
+ }
124
+
116
125
  // [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
117
126
  // consensus layer -- i.e. validate that
118
127
  // `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
@@ -266,6 +275,15 @@ async function validateExecutionPayloadBid(
266
275
  });
267
276
  }
268
277
 
278
+ // [REJECT] The bid's block hash is not equal to its parent block hash -- i.e.
279
+ // `bid.block_hash != bid.parent_block_hash`.
280
+ if (byteArrayEquals(bid.blockHash, bid.parentBlockHash)) {
281
+ throw new ExecutionPayloadBidError(GossipAction.REJECT, {
282
+ code: ExecutionPayloadBidErrorCode.BLOCK_HASH_EQUALS_PARENT_BLOCK_HASH,
283
+ blockHash: toRootHex(bid.blockHash),
284
+ });
285
+ }
286
+
269
287
  // [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
270
288
  // consensus layer -- i.e. validate that
271
289
  // `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
@@ -56,6 +56,10 @@ export async function validateBuilderApiExecutionPayloadBid(
56
56
  );
57
57
  }
58
58
 
59
+ if (byteArrayEquals(bid.blockHash, bid.parentBlockHash)) {
60
+ throw Error(`Bid block hash ${toRootHex(bid.blockHash)} must not equal its parent block hash`);
61
+ }
62
+
59
63
  const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
60
64
  const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
61
65
  if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
@@ -2,6 +2,7 @@
2
2
  import {NotReorgedReason} from "@lodestar/fork-choice";
3
3
  import {ArchiveStoreTask} from "../../chain/archiveStore/archiveStore.js";
4
4
  import {FrequencyStateArchiveStep} from "../../chain/archiveStore/strategies/frequencyStateArchiveStrategy.js";
5
+ import type {LateCanonicalBlockReason} from "../../chain/archiveStore/utils/archiveBlocks.js";
5
6
  import {BlockInputSource} from "../../chain/blocks/blockInput/index.js";
6
7
  import {PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
7
8
  import {
@@ -1047,6 +1048,11 @@ export function createLodestarMetrics(
1047
1048
  name: "lodestar_import_block_set_head_after_cutoff_total",
1048
1049
  help: "Total times an imported block is set as head after ATTESTATION_DUE_BPS of the slot",
1049
1050
  }),
1051
+ lateCanonicalBlock: register.counter<{reason: LateCanonicalBlockReason}>({
1052
+ name: "lodestar_import_block_late_canonical_total",
1053
+ help: "Total finalized-canonical blocks this node imported after the attestation cutoff; reason distinguishes this node's processing lag (slow_import) from late reception (late_receive)",
1054
+ labelNames: ["reason"],
1055
+ }),
1050
1056
  bySource: register.gauge<{source: BlockInputSource}>({
1051
1057
  name: "lodestar_import_block_by_source_total",
1052
1058
  help: "Total number of imported blocks by source",
@@ -1352,11 +1358,6 @@ export function createLodestarMetrics(
1352
1358
  help: "Total number of InsertOutcome as a result of adding an execution payload bid from gossip to the pool",
1353
1359
  labelNames: ["insertOutcome"],
1354
1360
  }),
1355
- apiInsertOutcome: register.counter<{insertOutcome: InsertOutcome}>({
1356
- name: "lodestar_oppool_execution_payload_bid_pool_api_insert_outcome_total",
1357
- help: "Total number of InsertOutcome as a result of adding an execution payload bid from api to the pool",
1358
- labelNames: ["insertOutcome"],
1359
- }),
1360
1361
  apiValidationTime: register.histogram({
1361
1362
  name: "lodestar_api_execution_payload_bid_validation_time_seconds",
1362
1363
  help: "Time elapsed for signed execution payload bid validation - api path",