@lodestar/beacon-node 1.44.0-dev.f715896231 → 1.44.0-dev.fb3e80a516

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 (156) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +13 -5
  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 -1
  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 +21 -9
  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/importExecutionPayload.js +1 -1
  28. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  29. package/lib/chain/chain.d.ts.map +1 -1
  30. package/lib/chain/chain.js +8 -1
  31. package/lib/chain/chain.js.map +1 -1
  32. package/lib/chain/errors/blockError.d.ts +0 -7
  33. package/lib/chain/errors/blockError.d.ts.map +1 -1
  34. package/lib/chain/errors/blockError.js +0 -3
  35. package/lib/chain/errors/blockError.js.map +1 -1
  36. package/lib/chain/errors/payloadAttestation.d.ts +6 -0
  37. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
  38. package/lib/chain/errors/payloadAttestation.js +1 -0
  39. package/lib/chain/errors/payloadAttestation.js.map +1 -1
  40. package/lib/chain/forkChoice/index.d.ts +4 -4
  41. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  42. package/lib/chain/forkChoice/index.js +10 -7
  43. package/lib/chain/forkChoice/index.js.map +1 -1
  44. package/lib/chain/options.d.ts.map +1 -1
  45. package/lib/chain/options.js +1 -0
  46. package/lib/chain/options.js.map +1 -1
  47. package/lib/chain/prepareNextSlot.js +1 -1
  48. package/lib/chain/prepareNextSlot.js.map +1 -1
  49. package/lib/chain/produceBlock/produceBlockBody.js +3 -3
  50. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  51. package/lib/chain/regen/interface.d.ts +2 -1
  52. package/lib/chain/regen/interface.d.ts.map +1 -1
  53. package/lib/chain/regen/interface.js +2 -0
  54. package/lib/chain/regen/interface.js.map +1 -1
  55. package/lib/chain/regen/queued.d.ts +0 -1
  56. package/lib/chain/regen/queued.d.ts.map +1 -1
  57. package/lib/chain/regen/queued.js +0 -4
  58. package/lib/chain/regen/queued.js.map +1 -1
  59. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +0 -5
  60. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  61. package/lib/chain/stateCache/fifoBlockStateCache.js +0 -5
  62. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  63. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -4
  64. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  65. package/lib/chain/stateCache/persistentCheckpointsCache.js +5 -2
  66. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  67. package/lib/chain/stateCache/types.d.ts +0 -2
  68. package/lib/chain/stateCache/types.d.ts.map +1 -1
  69. package/lib/chain/stateCache/types.js.map +1 -1
  70. package/lib/chain/validation/block.d.ts +5 -1
  71. package/lib/chain/validation/block.d.ts.map +1 -1
  72. package/lib/chain/validation/block.js +4 -14
  73. package/lib/chain/validation/block.js.map +1 -1
  74. package/lib/chain/validation/executionPayloadBid.js +22 -5
  75. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  76. package/lib/chain/validation/executionPayloadEnvelope.js +0 -2
  77. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  78. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  79. package/lib/chain/validation/payloadAttestationMessage.js +24 -4
  80. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  81. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  82. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  83. package/lib/metrics/metrics/lodestar.js +5 -0
  84. package/lib/metrics/metrics/lodestar.js.map +1 -1
  85. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  86. package/lib/network/processor/gossipHandlers.js +10 -3
  87. package/lib/network/processor/gossipHandlers.js.map +1 -1
  88. package/lib/network/processor/index.d.ts +2 -2
  89. package/lib/network/processor/index.d.ts.map +1 -1
  90. package/lib/network/processor/index.js +24 -22
  91. package/lib/network/processor/index.js.map +1 -1
  92. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  93. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +9 -5
  94. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  95. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  96. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +13 -3
  97. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  98. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -1
  99. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
  100. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts +2 -1
  101. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  102. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +16 -6
  103. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  104. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts +2 -1
  105. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  106. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +15 -1
  107. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  108. package/lib/network/reqresp/handlers/index.js +4 -4
  109. package/lib/network/reqresp/handlers/index.js.map +1 -1
  110. package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
  111. package/lib/network/reqresp/utils/dataColumnResponseValidation.js +22 -3
  112. package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
  113. package/lib/sync/unknownBlock.d.ts.map +1 -1
  114. package/lib/sync/unknownBlock.js +24 -19
  115. package/lib/sync/unknownBlock.js.map +1 -1
  116. package/lib/util/dataColumns.d.ts.map +1 -1
  117. package/lib/util/dataColumns.js +16 -11
  118. package/lib/util/dataColumns.js.map +1 -1
  119. package/package.json +14 -16
  120. package/src/api/impl/beacon/blocks/index.ts +13 -5
  121. package/src/api/impl/beacon/pool/index.ts +1 -0
  122. package/src/api/impl/config/constants.ts +2 -0
  123. package/src/api/impl/debug/index.ts +73 -12
  124. package/src/api/impl/lodestar/index.ts +30 -0
  125. package/src/api/impl/validator/index.ts +23 -14
  126. package/src/chain/archiveStore/archiveStore.ts +0 -5
  127. package/src/chain/blocks/importBlock.ts +1 -0
  128. package/src/chain/blocks/importExecutionPayload.ts +1 -1
  129. package/src/chain/chain.ts +10 -1
  130. package/src/chain/errors/blockError.ts +0 -4
  131. package/src/chain/errors/payloadAttestation.ts +2 -0
  132. package/src/chain/forkChoice/index.ts +13 -0
  133. package/src/chain/options.ts +1 -0
  134. package/src/chain/prepareNextSlot.ts +1 -1
  135. package/src/chain/produceBlock/produceBlockBody.ts +3 -3
  136. package/src/chain/regen/interface.ts +2 -1
  137. package/src/chain/regen/queued.ts +0 -5
  138. package/src/chain/stateCache/fifoBlockStateCache.ts +0 -6
  139. package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
  140. package/src/chain/stateCache/types.ts +0 -2
  141. package/src/chain/validation/block.ts +12 -16
  142. package/src/chain/validation/executionPayloadBid.ts +23 -5
  143. package/src/chain/validation/executionPayloadEnvelope.ts +0 -2
  144. package/src/chain/validation/payloadAttestationMessage.ts +26 -4
  145. package/src/metrics/metrics/lodestar.ts +6 -0
  146. package/src/network/processor/gossipHandlers.ts +10 -2
  147. package/src/network/processor/index.ts +26 -26
  148. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +12 -5
  149. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -3
  150. package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
  151. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +22 -6
  152. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +20 -1
  153. package/src/network/reqresp/handlers/index.ts +4 -4
  154. package/src/network/reqresp/utils/dataColumnResponseValidation.ts +21 -3
  155. package/src/sync/unknownBlock.ts +27 -19
  156. package/src/util/dataColumns.ts +17 -12
@@ -1,4 +1,5 @@
1
1
  import {LogData} from "@lodestar/logger";
2
+ import {ForkSeq} from "@lodestar/params";
2
3
  import {RespStatus, ResponseError} from "@lodestar/reqresp";
3
4
  import {ColumnIndex, Slot} from "@lodestar/types";
4
5
  import {prettyBytes, prettyPrintIndices, toRootHex} from "@lodestar/utils";
@@ -38,6 +39,13 @@ export async function handleColumnSidecarUnavailability({
38
39
 
39
40
  chain.logger.debug("dataColumnSidecar requested unavailable", logData);
40
41
 
42
+ // Post-gloas, columns exist only for FULL blocks; a finalized block is FULL if its envelope was
43
+ // archived. Bid blobsCount is unreliable here since an EMPTY block's bid may still commit to blobs
44
+ if (blockRoot === undefined && chain.config.getForkSeq(slot) >= ForkSeq.gloas) {
45
+ const envelopeBytes = await db.executionPayloadEnvelopeArchive.getBinary(slot);
46
+ if (!envelopeBytes) return;
47
+ }
48
+
41
49
  const blockBytes = blockRoot ? await db.block.getBinary(blockRoot) : await db.blockArchive.getBinary(slot);
42
50
  if (!blockBytes) {
43
51
  chain.logger.verbose(
@@ -71,9 +79,19 @@ export function validateRequestedDataColumns(chain: IBeaconChain, requestedColum
71
79
  throw new ResponseError(RespStatus.INVALID_REQUEST, "dataColumnSidecar requested without column indices");
72
80
  }
73
81
 
74
- const custodyColumns = chain.custodyConfig.custodyColumns;
75
- const availableColumns = requestedColumns.filter((c) => custodyColumns.includes(c));
76
- const missingColumns = requestedColumns.filter((c) => !custodyColumns.includes(c));
82
+ const {custodyColumns, custodyColumnsIndex} = chain.custodyConfig;
83
+ const availableColumns: ColumnIndex[] = [];
84
+ const missingColumns: ColumnIndex[] = [];
85
+ for (const c of requestedColumns) {
86
+ // `c` is peer-controlled and SSZ-deserialized as `uint64`, so it may exceed
87
+ // `NUMBER_OF_COLUMNS - 1`; `Uint8Array` returns `undefined` for OOB reads,
88
+ // and `undefined !== 0` would silently classify OOB indices as custodied.
89
+ if ((custodyColumnsIndex[c] ?? 0) !== 0) {
90
+ availableColumns.push(c);
91
+ } else {
92
+ missingColumns.push(c);
93
+ }
94
+ }
77
95
 
78
96
  if (missingColumns.length > 0) {
79
97
  chain.logger.verbose("Requested dataColumnSidecar for non-custody columns", {
@@ -850,25 +850,28 @@ export class BlockInputSync {
850
850
  }
851
851
 
852
852
  const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
853
- if (!payloadInput) {
854
- if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
855
- // Column commitments live on the block body, so an envelope-only entry has to pull the block first.
856
- if (!this.pendingBlocks.has(rootHex)) {
857
- this.addByRootHex(rootHex);
858
- }
853
+ if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
854
+ // Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
855
+ // non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
856
+ // onBlockImported re-triggers the search to resume this envelope.
857
+ if (!this.pendingBlocks.has(rootHex)) {
858
+ this.addByRootHex(rootHex);
859
+ }
859
860
 
860
- const pendingBlock = this.pendingBlocks.get(rootHex);
861
- if (pendingBlock && this.network.getConnectedPeers().length > 0) {
862
- await this.downloadBlock(pendingBlock);
863
- }
864
- } else {
865
- this.logger.debug("Missing PayloadEnvelopeInput for known block while reconciling payload envelope", {
866
- root: rootHex,
867
- });
861
+ const pendingBlock = this.pendingBlocks.get(rootHex);
862
+ if (pendingBlock && this.network.getConnectedPeers().length > 0) {
863
+ await this.downloadBlock(pendingBlock);
868
864
  }
869
865
  return;
870
866
  }
871
867
 
868
+ if (!payloadInput) {
869
+ this.logger.debug("Missing PayloadEnvelopeInput for known block while reconciling payload envelope", {
870
+ root: rootHex,
871
+ });
872
+ return;
873
+ }
874
+
872
875
  if (!payloadInput.hasPayloadEnvelope()) {
873
876
  const validationResult = await wrapError(
874
877
  validateGossipExecutionPayloadEnvelope(this.chain, pendingPayload.envelope)
@@ -1073,11 +1076,11 @@ export class BlockInputSync {
1073
1076
  }
1074
1077
 
1075
1078
  payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1076
- if (!payloadInput) {
1077
- if (this.chain.forkChoice.hasBlockHex(rootHex)) {
1078
- throw new Error(`Missing PayloadEnvelopeInput for known block ${rootHex}`);
1079
- }
1080
- // Keep the validated envelope around, but wait for the block body before turning it into a full payload input.
1079
+ if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
1080
+ // Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
1081
+ // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
1082
+ // payloadInput may be seeded from the block body during download, so a non-null payloadInput does not
1083
+ // imply the block is imported.
1081
1084
  return {
1082
1085
  status: PendingPayloadInputStatus.waitingForBlock,
1083
1086
  envelope,
@@ -1086,6 +1089,11 @@ export class BlockInputSync {
1086
1089
  };
1087
1090
  }
1088
1091
 
1092
+ if (!payloadInput) {
1093
+ // Block is in fork choice but no PayloadEnvelopeInput exists, should have been created during block import.
1094
+ throw new Error(`Missing PayloadEnvelopeInput for known block ${rootHex}`);
1095
+ }
1096
+
1089
1097
  if (!payloadInput.hasPayloadEnvelope()) {
1090
1098
  await validateGossipExecutionPayloadEnvelope(this.chain, envelope);
1091
1099
  }
@@ -470,15 +470,17 @@ export async function recoverDataColumnSidecars(
470
470
  return DataColumnReconstructionCode.SuccessLate;
471
471
  }
472
472
 
473
- // Once the node obtains a column through reconstruction,
474
- // the node MUST expose the new column as if it had received it over the network.
475
- // If the node is subscribed to the subnet corresponding to the column,
476
- // it MUST send the reconstructed DataColumnSidecar to its topic mesh neighbors.
477
- // If instead the node is not subscribed to the corresponding subnet,
478
- // it SHOULD still expose the availability of the DataColumnSidecar as part of the gossip emission process.
479
- // After exposing the reconstructed DataColumnSidecar to the network,
480
- // the node MAY delete the DataColumnSidecar if it is not part of the node's custody requirement.
481
- const sidecarsToPublish = [];
473
+ // Per consensus-specs PR #4657, only publish reconstructed columns the node is
474
+ // subscribed to (custody + sampling). Eagerly cross-seeding non-subscribed
475
+ // columns floods the network with duplicates because the sender has no
476
+ // visibility into which peers already saw the message via the topic mesh.
477
+ // This matches the getBlobsV2 path in `getDataColumnSidecarsFromExecution` and
478
+ // aligns with Lighthouse/Prysm. Capture missing sampled indices before adding
479
+ // any reconstructed columns so they are not filtered out by the subsequent
480
+ // `addColumn` calls.
481
+ const missingSampledColumns = new Set(input.getMissingSampledColumnMeta().missing);
482
+ const sidecarsReconstructed: DataColumnSidecar[] = [];
483
+ const sidecarsToPublish: DataColumnSidecar[] = [];
482
484
  for (const columnSidecar of fullSidecars) {
483
485
  if (!input.hasColumn(columnSidecar.index)) {
484
486
  if (input instanceof PayloadEnvelopeInput) {
@@ -501,11 +503,14 @@ export async function recoverDataColumnSidecars(
501
503
  source: BlockInputSource.recovery,
502
504
  });
503
505
  }
504
- sidecarsToPublish.push(columnSidecar);
506
+ sidecarsReconstructed.push(columnSidecar);
507
+ if (missingSampledColumns.has(columnSidecar.index)) {
508
+ sidecarsToPublish.push(columnSidecar);
509
+ }
505
510
  }
506
511
  }
507
- metrics?.peerDas.reconstructedColumns.inc(sidecarsToPublish.length);
508
- metrics?.dataColumns.bySource.inc({source: BlockInputSource.recovery}, sidecarsToPublish.length);
512
+ metrics?.peerDas.reconstructedColumns.inc(sidecarsReconstructed.length);
513
+ metrics?.dataColumns.bySource.inc({source: BlockInputSource.recovery}, sidecarsReconstructed.length);
509
514
  emitter.emit(ChainEvent.publishDataColumns, sidecarsToPublish);
510
515
  // TODO: Can we record dataColumns.sentPeersPerSubnet metric somehow
511
516
  return DataColumnReconstructionCode.SuccessResolved;