@lodestar/beacon-node 1.51.0-dev.3c46867203 → 1.51.0-dev.3fada841a9

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 (206) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +17 -27
  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 +5 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +1 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/validator/index.d.ts.map +1 -1
  10. package/lib/api/impl/validator/index.js +4 -1
  11. package/lib/api/impl/validator/index.js.map +1 -1
  12. package/lib/chain/GetBlobsTracker.d.ts +11 -0
  13. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  14. package/lib/chain/GetBlobsTracker.js +85 -27
  15. package/lib/chain/GetBlobsTracker.js.map +1 -1
  16. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  17. package/lib/chain/archiveStore/archiveStore.js +1 -0
  18. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  19. package/lib/chain/blocks/importExecutionPayload.d.ts +6 -11
  20. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  21. package/lib/chain/blocks/importExecutionPayload.js +8 -15
  22. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  23. package/lib/chain/blocks/index.js +1 -1
  24. package/lib/chain/blocks/index.js.map +1 -1
  25. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +12 -9
  26. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  27. package/lib/chain/blocks/payloadEnvelopeProcessor.js +24 -19
  28. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  29. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  30. package/lib/chain/blocks/verifyBlock.js +1 -1
  31. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  32. package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
  33. package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
  34. package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
  35. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +3 -3
  36. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  37. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +11 -6
  38. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  39. package/lib/chain/bls/multithread/index.js +5 -5
  40. package/lib/chain/bls/multithread/index.js.map +1 -1
  41. package/lib/chain/bls/multithread/types.d.ts +1 -1
  42. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  43. package/lib/chain/bls/multithread/worker.js +1 -1
  44. package/lib/chain/bls/multithread/worker.js.map +1 -1
  45. package/lib/chain/bls/singleThread.js +1 -1
  46. package/lib/chain/bls/singleThread.js.map +1 -1
  47. package/lib/chain/bls/utils.js +1 -1
  48. package/lib/chain/bls/utils.js.map +1 -1
  49. package/lib/chain/chain.d.ts +1 -1
  50. package/lib/chain/chain.d.ts.map +1 -1
  51. package/lib/chain/chain.js.map +1 -1
  52. package/lib/chain/errors/blockError.d.ts +1 -1
  53. package/lib/chain/errors/blockError.d.ts.map +1 -1
  54. package/lib/chain/errors/blockError.js +1 -1
  55. package/lib/chain/errors/blockError.js.map +1 -1
  56. package/lib/chain/interface.d.ts +2 -3
  57. package/lib/chain/interface.d.ts.map +1 -1
  58. package/lib/chain/interface.js.map +1 -1
  59. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  60. package/lib/chain/opPools/aggregatedAttestationPool.js +23 -10
  61. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  62. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  63. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  64. package/lib/chain/opPools/attestationPool.js +15 -4
  65. package/lib/chain/opPools/attestationPool.js.map +1 -1
  66. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  67. package/lib/chain/opPools/payloadAttestationPool.js +17 -7
  68. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  69. package/lib/chain/opPools/syncCommitteeMessagePool.d.ts.map +1 -1
  70. package/lib/chain/opPools/syncCommitteeMessagePool.js +9 -3
  71. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  72. package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
  73. package/lib/chain/opPools/syncContributionAndProofPool.js +11 -3
  74. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  75. package/lib/chain/opPools/utils.d.ts +1 -1
  76. package/lib/chain/opPools/utils.d.ts.map +1 -1
  77. package/lib/chain/opPools/utils.js +1 -1
  78. package/lib/chain/opPools/utils.js.map +1 -1
  79. package/lib/chain/options.d.ts +0 -1
  80. package/lib/chain/options.d.ts.map +1 -1
  81. package/lib/chain/options.js +0 -1
  82. package/lib/chain/options.js.map +1 -1
  83. package/lib/chain/validation/executionPayloadBid.js +13 -13
  84. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  85. package/lib/db/flatFileStore/flatFileStore.js +5 -5
  86. package/lib/db/flatFileStore/flatFileStore.js.map +1 -1
  87. package/lib/db/flatFileStore/slotIndex.d.ts.map +1 -1
  88. package/lib/db/flatFileStore/slotIndex.js +2 -2
  89. package/lib/db/flatFileStore/slotIndex.js.map +1 -1
  90. package/lib/execution/engine/index.d.ts +1 -1
  91. package/lib/execution/engine/index.d.ts.map +1 -1
  92. package/lib/execution/engine/index.js +1 -1
  93. package/lib/execution/engine/index.js.map +1 -1
  94. package/lib/execution/engine/interface.d.ts +1 -1
  95. package/lib/execution/engine/interface.d.ts.map +1 -1
  96. package/lib/execution/engine/interface.js.map +1 -1
  97. package/lib/execution/engine/types.d.ts.map +1 -1
  98. package/lib/execution/engine/types.js +2 -2
  99. package/lib/execution/engine/types.js.map +1 -1
  100. package/lib/metrics/metrics/lodestar.d.ts +3 -0
  101. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  102. package/lib/metrics/metrics/lodestar.js +5 -0
  103. package/lib/metrics/metrics/lodestar.js.map +1 -1
  104. package/lib/monitoring/service.js +1 -1
  105. package/lib/monitoring/service.js.map +1 -1
  106. package/lib/network/core/networkCore.d.ts +2 -0
  107. package/lib/network/core/networkCore.d.ts.map +1 -1
  108. package/lib/network/core/networkCore.js +3 -0
  109. package/lib/network/core/networkCore.js.map +1 -1
  110. package/lib/network/core/networkCoreWorker.js +1 -0
  111. package/lib/network/core/networkCoreWorker.js.map +1 -1
  112. package/lib/network/core/networkCoreWorkerHandler.d.ts +2 -0
  113. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  114. package/lib/network/core/networkCoreWorkerHandler.js +3 -0
  115. package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
  116. package/lib/network/core/types.d.ts +2 -0
  117. package/lib/network/core/types.d.ts.map +1 -1
  118. package/lib/network/interface.d.ts +2 -0
  119. package/lib/network/interface.d.ts.map +1 -1
  120. package/lib/network/network.d.ts +2 -0
  121. package/lib/network/network.d.ts.map +1 -1
  122. package/lib/network/network.js +6 -1
  123. package/lib/network/network.js.map +1 -1
  124. package/lib/network/peers/peerManager.d.ts +2 -1
  125. package/lib/network/peers/peerManager.d.ts.map +1 -1
  126. package/lib/network/peers/peerManager.js.map +1 -1
  127. package/lib/network/peers/utils/assertPeerRelevance.d.ts +9 -1
  128. package/lib/network/peers/utils/assertPeerRelevance.d.ts.map +1 -1
  129. package/lib/network/peers/utils/assertPeerRelevance.js +32 -21
  130. package/lib/network/peers/utils/assertPeerRelevance.js.map +1 -1
  131. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  132. package/lib/network/processor/gossipHandlers.js +9 -8
  133. package/lib/network/processor/gossipHandlers.js.map +1 -1
  134. package/lib/node/nodejs.d.ts +1 -1
  135. package/lib/node/nodejs.d.ts.map +1 -1
  136. package/lib/node/nodejs.js +1 -1
  137. package/lib/node/nodejs.js.map +1 -1
  138. package/lib/node/options.d.ts +1 -1
  139. package/lib/node/options.d.ts.map +1 -1
  140. package/lib/node/options.js +1 -1
  141. package/lib/node/options.js.map +1 -1
  142. package/lib/sync/interface.d.ts.map +1 -1
  143. package/lib/sync/interface.js.map +1 -1
  144. package/lib/sync/sync.d.ts +7 -0
  145. package/lib/sync/sync.d.ts.map +1 -1
  146. package/lib/sync/sync.js +61 -3
  147. package/lib/sync/sync.js.map +1 -1
  148. package/lib/util/file.d.ts.map +1 -1
  149. package/lib/util/file.js +8 -9
  150. package/lib/util/file.js.map +1 -1
  151. package/lib/util/queue/itemQueue.js +1 -1
  152. package/lib/util/queue/itemQueue.js.map +1 -1
  153. package/lib/util/sszBytes.js +2 -2
  154. package/lib/util/sszBytes.js.map +1 -1
  155. package/package.json +16 -17
  156. package/src/api/impl/beacon/blocks/index.ts +35 -45
  157. package/src/api/impl/beacon/pool/index.ts +5 -1
  158. package/src/api/impl/beacon/state/utils.ts +1 -1
  159. package/src/api/impl/validator/index.ts +4 -1
  160. package/src/chain/GetBlobsTracker.ts +97 -38
  161. package/src/chain/archiveStore/archiveStore.ts +1 -0
  162. package/src/chain/blocks/importExecutionPayload.ts +13 -21
  163. package/src/chain/blocks/index.ts +5 -1
  164. package/src/chain/blocks/payloadEnvelopeProcessor.ts +35 -24
  165. package/src/chain/blocks/verifyBlock.ts +1 -0
  166. package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -1
  167. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +14 -6
  168. package/src/chain/bls/multithread/index.ts +5 -5
  169. package/src/chain/bls/multithread/types.ts +1 -1
  170. package/src/chain/bls/multithread/worker.ts +1 -5
  171. package/src/chain/bls/singleThread.ts +1 -1
  172. package/src/chain/bls/utils.ts +1 -1
  173. package/src/chain/chain.ts +1 -1
  174. package/src/chain/errors/blockError.ts +1 -1
  175. package/src/chain/interface.ts +2 -3
  176. package/src/chain/opPools/aggregatedAttestationPool.ts +25 -9
  177. package/src/chain/opPools/attestationPool.ts +16 -4
  178. package/src/chain/opPools/payloadAttestationPool.ts +18 -7
  179. package/src/chain/opPools/syncCommitteeMessagePool.ts +10 -3
  180. package/src/chain/opPools/syncContributionAndProofPool.ts +13 -3
  181. package/src/chain/opPools/utils.ts +1 -1
  182. package/src/chain/options.ts +0 -2
  183. package/src/chain/validation/executionPayloadBid.ts +14 -13
  184. package/src/db/flatFileStore/flatFileStore.ts +7 -7
  185. package/src/db/flatFileStore/slotIndex.ts +4 -3
  186. package/src/execution/engine/index.ts +1 -1
  187. package/src/execution/engine/interface.ts +1 -1
  188. package/src/execution/engine/types.ts +3 -1
  189. package/src/metrics/metrics/lodestar.ts +5 -0
  190. package/src/monitoring/service.ts +1 -1
  191. package/src/network/core/networkCore.ts +5 -0
  192. package/src/network/core/networkCoreWorker.ts +1 -0
  193. package/src/network/core/networkCoreWorkerHandler.ts +4 -0
  194. package/src/network/core/types.ts +2 -0
  195. package/src/network/interface.ts +2 -0
  196. package/src/network/network.ts +8 -1
  197. package/src/network/peers/peerManager.ts +1 -1
  198. package/src/network/peers/utils/assertPeerRelevance.ts +39 -23
  199. package/src/network/processor/gossipHandlers.ts +9 -8
  200. package/src/node/nodejs.ts +6 -6
  201. package/src/node/options.ts +4 -5
  202. package/src/sync/interface.ts +1 -0
  203. package/src/sync/sync.ts +65 -4
  204. package/src/util/file.ts +8 -9
  205. package/src/util/queue/itemQueue.ts +1 -1
  206. package/src/util/sszBytes.ts +2 -2
@@ -1,9 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {MAX_COMMITTEES_PER_SLOT, isForkPostElectra} from "@lodestar/params";
5
+ import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
5
6
  import {Attestation, RootHex, SingleAttestation, Slot, isElectraSingleAttestation} from "@lodestar/types";
6
- import {MapDef, assert} from "@lodestar/utils";
7
+ import {MapDef, assert, byteArrayEquals} from "@lodestar/utils";
7
8
  import {Metrics} from "../../metrics/metrics.js";
8
9
  import {IClock} from "../../util/clock.js";
9
10
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
@@ -180,7 +181,13 @@ export class AttestationPool {
180
181
  assert.true(!isElectraAggregate(aggregate), "Aggregate should be type AggregateFastPhase0");
181
182
  }
182
183
 
183
- return fastToAttestation(aggregate);
184
+ const attestation = fastToAttestation(aggregate);
185
+ // The point at infinity is not a valid aggregate signature, do not serve such an aggregate
186
+ if (byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY)) {
187
+ return null;
188
+ }
189
+
190
+ return attestation;
184
191
  }
185
192
 
186
193
  /**
@@ -209,7 +216,12 @@ export class AttestationPool {
209
216
  if (aggregateByRoot) {
210
217
  for (const aggFastByIndex of aggregateByRoot.values()) {
211
218
  for (const aggFast of aggFastByIndex.values()) {
212
- attestations.push(fastToAttestation(aggFast));
219
+ const attestation = fastToAttestation(aggFast);
220
+ // The point at infinity is not a valid aggregate signature, do not serve such an aggregate
221
+ if (byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY)) {
222
+ continue;
223
+ }
224
+ attestations.push(attestation);
213
225
  }
214
226
  }
215
227
  }
@@ -1,9 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {MAX_COMMITTEES_PER_SLOT, MAX_PAYLOAD_ATTESTATIONS, PTC_SIZE} from "@lodestar/params";
5
+ import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
5
6
  import {RootHex, Slot, gloas} from "@lodestar/types";
6
- import {MapDef, toRootHex} from "@lodestar/utils";
7
+ import {MapDef, byteArrayEquals, toRootHex} from "@lodestar/utils";
7
8
  import {Metrics} from "../../metrics/metrics.js";
8
9
  import {IClock} from "../../util/clock.js";
9
10
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
@@ -112,11 +113,19 @@ export class PayloadAttestationPool {
112
113
  return [];
113
114
  }
114
115
 
115
- return Array.from(aggregateByDataRoot.values())
116
- .slice()
116
+ const payloadAttestations: gloas.PayloadAttestation[] = [];
117
+ for (const aggregate of aggregateByDataRoot.values()) {
118
+ const payloadAttestation = fastToPayloadAttestation(aggregate);
119
+ // The point at infinity is not a valid aggregate signature, exclude it from the block
120
+ if (byteArrayEquals(payloadAttestation.signature, G2_POINT_AT_INFINITY)) {
121
+ continue;
122
+ }
123
+ payloadAttestations.push(payloadAttestation);
124
+ }
125
+
126
+ return payloadAttestations
117
127
  .sort((a, b) => b.aggregationBits.getTrueBitIndexes().length - a.aggregationBits.getTrueBitIndexes().length)
118
- .slice(0, MAX_PAYLOAD_ATTESTATIONS)
119
- .map(fastToPayloadAttestation);
128
+ .slice(0, MAX_PAYLOAD_ATTESTATIONS);
120
129
  }
121
130
 
122
131
  getAll(slot?: Slot): gloas.PayloadAttestation[] {
@@ -139,9 +148,11 @@ export class PayloadAttestationPool {
139
148
  }
140
149
  }
141
150
 
151
+ // The point at infinity is not a valid aggregate signature, do not serve such an aggregate
142
152
  return aggregates
143
153
  .sort((a, b) => b.aggregationBits.getTrueBitIndexes().length - a.aggregationBits.getTrueBitIndexes().length)
144
- .map(fastToPayloadAttestation);
154
+ .map(fastToPayloadAttestation)
155
+ .filter((attestation) => !byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY));
145
156
  }
146
157
 
147
158
  prune(clockSlot: Slot): void {
@@ -1,9 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
5
+ import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
5
6
  import {Root, Slot, SubcommitteeIndex, SubnetID, altair} from "@lodestar/types";
6
- import {MapDef, toRootHex} from "@lodestar/utils";
7
+ import {MapDef, byteArrayEquals, toRootHex} from "@lodestar/utils";
7
8
  import {IClock} from "../../util/clock.js";
8
9
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
9
10
  import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js";
@@ -110,10 +111,16 @@ export class SyncCommitteeMessagePool {
110
111
  return null;
111
112
  }
112
113
 
114
+ const signature = contribution.signature.toBytes();
115
+ // The point at infinity is not a valid contribution signature, do not serve such a contribution
116
+ if (byteArrayEquals(signature, G2_POINT_AT_INFINITY)) {
117
+ return null;
118
+ }
119
+
113
120
  return {
114
121
  ...contribution,
115
122
  aggregationBits: contribution.aggregationBits,
116
- signature: contribution.signature.toBytes(),
123
+ signature,
117
124
  };
118
125
  }
119
126
 
@@ -1,10 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
5
5
  import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
6
6
  import {Root, Slot, SubnetID, altair, ssz} from "@lodestar/types";
7
- import {Logger, MapDef, toRootHex} from "@lodestar/utils";
7
+ import {Logger, MapDef, byteArrayEquals, toRootHex} from "@lodestar/utils";
8
8
  import {Metrics} from "../../metrics/metrics.js";
9
9
  import {IClock} from "../../util/clock.js";
10
10
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
@@ -234,8 +234,18 @@ export function aggregate(
234
234
  }
235
235
 
236
236
  metrics?.opPool.syncContributionAndProofPool.getAggregateParticipants.set(participationCount);
237
+
238
+ const syncCommitteeSignature = aggregateSignatures(signatures).toBytes();
239
+ // The point at infinity is only a valid sync aggregate signature with empty participation bits
240
+ if (byteArrayEquals(syncCommitteeSignature, G2_POINT_AT_INFINITY)) {
241
+ return {
242
+ syncCommitteeBits: BitArray.fromBitLen(SYNC_COMMITTEE_SIZE),
243
+ syncCommitteeSignature,
244
+ };
245
+ }
246
+
237
247
  return {
238
248
  syncCommitteeBits,
239
- syncCommitteeSignature: aggregateSignatures(signatures).toBytes(),
249
+ syncCommitteeSignature,
240
250
  };
241
251
  }
@@ -1,6 +1,6 @@
1
- import {Signature} from "@chainsafe/lodestar-z/blst";
2
1
  import {BeaconConfig} from "@lodestar/config";
3
2
  import {DbBatch, Id, Repository} from "@lodestar/db";
3
+ import {Signature} from "@lodestar/native/blst";
4
4
  import {BLS_WITHDRAWAL_PREFIX, DOMAIN_BEACON_ATTESTER, DOMAIN_BEACON_PROPOSER} from "@lodestar/params";
5
5
  import {IBeaconStateView, computeStartSlotAtEpoch} from "@lodestar/state-transition";
6
6
  import {AttesterSlashing, Domain, Slot, capella, phase0} from "@lodestar/types";
@@ -48,7 +48,6 @@ export type IChainOptions = BlockProcessOpts &
48
48
  /** Max number of produced block roots (blinded or full) cached for broadcast validations */
49
49
  maxCachedProducedRoots?: number;
50
50
  initialCustodyGroupCount?: number;
51
- broadcastValidationStrictness?: string;
52
51
  minSameMessageSignatureSetsToBatch: number;
53
52
  archiveDateEpochs?: number;
54
53
  nHistoricalStatesFileDataStore?: boolean;
@@ -121,7 +120,6 @@ export const defaultChainOptions: IChainOptions = {
121
120
  // for attestation validation, having this value ensures we don't have to regen states most of the time
122
121
  maxSkipSlots: 32,
123
122
  disableProposerSlashings: false,
124
- broadcastValidationStrictness: "warn",
125
123
  // should be less than or equal to MIN_SIGNATURE_SETS_TO_BATCH_VERIFY
126
124
  // batching too much may block the I/O thread so if useWorker=false, suggest this value to be 32
127
125
  // since this batch attestation work is designed to work with useWorker=true, make this the lowest value
@@ -179,6 +179,20 @@ async function validateExecutionPayloadBid(
179
179
  });
180
180
  }
181
181
 
182
+ // [IGNORE] this bid is the highest value bid seen for the tuple
183
+ // `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
184
+ // As a DoS prevention measure, the bid must also exceed the current highest bid by a minimum
185
+ // increment, see https://github.com/ethereum/consensus-specs/pull/4831. This prevents spam
186
+ // from builders submitting numerous bids with minimal value increments.
187
+ const bestBid = chain.executionPayloadBidPool.getBestBid(bid.slot, bidParentBlockHash, bidParentBlockRoot);
188
+ if (bestBid !== null && bid.value < getMinBidValue(bestBid.signedBid.message.value)) {
189
+ throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
190
+ code: ExecutionPayloadBidErrorCode.BID_TOO_LOW,
191
+ bidValue: bid.value,
192
+ currentHighestBid: bestBid.signedBid.message.value,
193
+ });
194
+ }
195
+
182
196
  // [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon block in fork choice.
183
197
  // Moved earlier than the spec ordering so we can derive the proposer dependent root for the
184
198
  // proposer-preferences lookup below from a known fork-choice block.
@@ -352,19 +366,6 @@ async function validateExecutionPayloadBid(
352
366
  });
353
367
  }
354
368
 
355
- // [IGNORE] this bid is the highest value bid seen for the tuple
356
- // `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
357
- // As a DoS prevention measure, the bid must also exceed the current highest bid by a minimum
358
- // increment, see https://github.com/ethereum/consensus-specs/pull/4831. This prevents spam
359
- // from builders submitting numerous bids with minimal value increments.
360
- const bestBid = chain.executionPayloadBidPool.getBestBid(bid.slot, bidParentBlockHash, bidParentBlockRoot);
361
- if (bestBid !== null && bid.value < getMinBidValue(bestBid.signedBid.message.value)) {
362
- throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
363
- code: ExecutionPayloadBidErrorCode.BID_TOO_LOW,
364
- bidValue: bid.value,
365
- currentHighestBid: bestBid.signedBid.message.value,
366
- });
367
- }
368
369
  // [IGNORE] `bid.value` is less or equal than the builder's excess balance --
369
370
  // i.e. `can_builder_cover_bid(state, builder_index, amount)` returns `True`.
370
371
  if (!state.canBuilderCoverBid(bid.builderIndex, bid.value)) {
@@ -1,4 +1,4 @@
1
- import fs from "node:fs";
1
+ import {type FileHandle, open, readFile, rm} from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import {ChainForkConfig} from "@lodestar/config";
4
4
  import {ForkPostFulu} from "@lodestar/params";
@@ -172,7 +172,7 @@ export class FlatFileStore implements IFlatFileStore {
172
172
  for (const slot of slotsToPrune) {
173
173
  const release = await this.acquireMutationLock(slot);
174
174
  try {
175
- await fs.promises.rm(path.join(this.dataColumnDir, padSlot(slot)), {recursive: true, force: true});
175
+ await rm(path.join(this.dataColumnDir, padSlot(slot)), {recursive: true, force: true});
176
176
  this.slotIndex.remove(slot);
177
177
  this.metrics?.prunedDirectories.inc();
178
178
  } finally {
@@ -212,7 +212,7 @@ export class FlatFileStore implements IFlatFileStore {
212
212
 
213
213
  private async readFile(slot: Slot, rootHex: RootHex): Promise<Uint8Array | null> {
214
214
  try {
215
- return await fs.promises.readFile(this.filePath(slot, rootHex));
215
+ return await readFile(this.filePath(slot, rootHex));
216
216
  } catch (e) {
217
217
  if (!isFsNotFoundError(e)) throw e;
218
218
  return null;
@@ -224,9 +224,9 @@ export class FlatFileStore implements IFlatFileStore {
224
224
  rootHex: RootHex,
225
225
  indices: number[]
226
226
  ): Promise<(Uint8Array | undefined)[] | null> {
227
- let fd: fs.promises.FileHandle;
227
+ let fd: FileHandle;
228
228
  try {
229
- fd = await fs.promises.open(this.filePath(slot, rootHex), "r");
229
+ fd = await open(this.filePath(slot, rootHex), "r");
230
230
  } catch (e) {
231
231
  if (!isFsNotFoundError(e)) throw e;
232
232
  return null;
@@ -270,7 +270,7 @@ export class FlatFileStore implements IFlatFileStore {
270
270
  await observeFlatFileStoreOperation(this.metrics, FlatFileStoreOperation.delete, async () => {
271
271
  const release = await this.acquireMutationLock(slot);
272
272
  try {
273
- await fs.promises.rm(this.filePath(slot, rootHex), {force: true});
273
+ await rm(this.filePath(slot, rootHex), {force: true});
274
274
  } finally {
275
275
  release();
276
276
  }
@@ -294,7 +294,7 @@ function validateDcolHeader(header: DcolHeader, slot: Slot, rootHex: RootHex): v
294
294
  }
295
295
  }
296
296
 
297
- async function readExactly(fd: fs.promises.FileHandle, buffer: Uint8Array, position: number): Promise<void> {
297
+ async function readExactly(fd: FileHandle, buffer: Uint8Array, position: number): Promise<void> {
298
298
  let totalRead = 0;
299
299
  while (totalRead < buffer.length) {
300
300
  const {bytesRead} = await fd.read(buffer, totalRead, buffer.length - totalRead, position + totalRead);
@@ -1,4 +1,5 @@
1
- import fs from "node:fs";
1
+ import type {Dirent} from "node:fs";
2
+ import {readdir} from "node:fs/promises";
2
3
  import {Slot} from "@lodestar/types";
3
4
  import {isFsNotFoundError} from "./errors.js";
4
5
  import {padSlot} from "./path.js";
@@ -33,9 +34,9 @@ export class SlotIndex {
33
34
 
34
35
  async rebuildFromDisk(columnsDir: string): Promise<SlotIndexRebuildStats> {
35
36
  this.slots.clear();
36
- let entries: fs.Dirent[];
37
+ let entries: Dirent[];
37
38
  try {
38
- entries = await fs.promises.readdir(columnsDir, {withFileTypes: true});
39
+ entries = await readdir(columnsDir, {withFileTypes: true});
39
40
  } catch (e) {
40
41
  if (!isFsNotFoundError(e)) throw e;
41
42
  return {slots: 0, ignoredEntries: 0};
@@ -17,8 +17,8 @@ import {EngineRestHttpClient} from "./restHttpClient.js";
17
17
  import {RestEngineTransport, formatClientVersionHeader} from "./restTransport.js";
18
18
  import {ExecutionEngineMockJsonRpcClient, JsonRpcBackend} from "./utils.js";
19
19
 
20
- export {ExecutionEngineHttp, ExecutionEngineDisabled, defaultExecutionEngineHttpOpts, engineApiModes};
21
20
  export type {EngineApiMode};
21
+ export {ExecutionEngineDisabled, ExecutionEngineHttp, defaultExecutionEngineHttpOpts, engineApiModes};
22
22
 
23
23
  export type ExecutionEngineOpts =
24
24
  | ({mode?: "http"} & ExecutionEngineHttpOpts)
@@ -25,7 +25,7 @@ import {PayloadId, PayloadIdCache, WithdrawalV1} from "./payloadIdCache.js";
25
25
  import {ExecutionPayloadBodyV2} from "./types.js";
26
26
  import {DATA} from "./utils.js";
27
27
 
28
- export {PayloadIdCache, type PayloadId, type WithdrawalV1};
28
+ export {type PayloadId, PayloadIdCache, type WithdrawalV1};
29
29
  export type ClientVersion = routes.node.ClientVersion;
30
30
  export const ClientCode = routes.node.ClientCode;
31
31
 
@@ -9,6 +9,7 @@ import {
9
9
  DEPOSIT_REQUEST_TYPE,
10
10
  FIELD_ELEMENTS_PER_BLOB,
11
11
  ForkName,
12
+ ForkPostElectra,
12
13
  ForkSeq,
13
14
  WITHDRAWAL_REQUEST_TYPE,
14
15
  } from "@lodestar/params";
@@ -23,6 +24,7 @@ import {
23
24
  deneb,
24
25
  gloas,
25
26
  ssz,
27
+ sszTypesFor,
26
28
  } from "@lodestar/types";
27
29
  import {BlobAndProof} from "@lodestar/types/deneb";
28
30
  import {BlobAndProofV2} from "@lodestar/types/fulu";
@@ -628,7 +630,7 @@ export function deserializeExecutionRequestsFromBytes(fork: ForkName, serialized
628
630
 
629
631
  switch (currentRequestType) {
630
632
  case DEPOSIT_REQUEST_TYPE: {
631
- result.deposits = ssz.electra.DepositRequests.deserialize(requests);
633
+ result.deposits = sszTypesFor(fork as ForkPostElectra).DepositRequests.deserialize(requests);
632
634
  break;
633
635
  }
634
636
  case WITHDRAWAL_REQUEST_TYPE: {
@@ -645,6 +645,11 @@ export function createLodestarMetrics(
645
645
  help: "Count of peers by sync type [FullySynced, Advanced, Behind]",
646
646
  labelNames: ["syncType"],
647
647
  }),
648
+ syncPeerFinalizedCheckpointMismatch: register.counter<{reason: string}>({
649
+ name: "lodestar_sync_peer_finalized_checkpoint_mismatch_total",
650
+ help: "Total behind peers whose Status finalized checkpoint is not in our chain, by reason",
651
+ labelNames: ["reason"],
652
+ }),
648
653
  syncSwitchGossipSubscriptions: register.gauge<{action: string}>({
649
654
  name: "lodestar_sync_switch_gossip_subscriptions",
650
655
  help: "Sync switched gossip subscriptions on/off",
@@ -101,7 +101,7 @@ export class MonitoringService {
101
101
  if (this.monitoringInterval) {
102
102
  clearTimeout(this.monitoringInterval);
103
103
  }
104
- if (this.pendingRequest) {
104
+ if (this.pendingRequest !== undefined) {
105
105
  this.fetchAbortController?.abort(FetchAbortReason.Close);
106
106
  await this.pendingRequest;
107
107
  }
@@ -10,6 +10,7 @@ import {isForkPostFulu} from "@lodestar/params";
10
10
  import {ResponseIncoming} from "@lodestar/reqresp";
11
11
  import {Epoch, Status, fulu, sszTypesFor} from "@lodestar/types";
12
12
  import {formatNodePeer} from "../../api/impl/node/utils.js";
13
+ import {GoodByeReasonCode} from "../../constants/index.js";
13
14
  import {RegistryMetricCreator} from "../../metrics/index.js";
14
15
  import {ClockEvent, IClock} from "../../util/clock.js";
15
16
  import {CustodyConfig} from "../../util/dataColumns.js";
@@ -332,6 +333,10 @@ export class NetworkCore implements INetworkCore {
332
333
  this.peerManager.reStatusPeers(peers);
333
334
  }
334
335
 
336
+ async goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void> {
337
+ await this.peerManager.goodbyeAndDisconnect(peerIdFromString(peer), reason);
338
+ }
339
+
335
340
  /**
336
341
  * Request att subnets up `toSlot`. Network will ensure to mantain some peers for each
337
342
  */
@@ -138,6 +138,7 @@ const libp2pWorkerApi: NetworkWorkerApi = {
138
138
  prepareSyncCommitteeSubnets: (subscriptions) => core.prepareSyncCommitteeSubnets(subscriptions),
139
139
  reportPeer: (peer, action, actionName) => core.reportPeer(peer, action, actionName),
140
140
  reStatusPeers: (peers) => core.reStatusPeers(peers),
141
+ goodbyeAndDisconnect: (peer, reason) => core.goodbyeAndDisconnect(peer, reason),
141
142
  subscribeGossipCoreTopics: () => core.subscribeGossipCoreTopics(),
142
143
  unsubscribeGossipCoreTopics: () => core.unsubscribeGossipCoreTopics(),
143
144
 
@@ -11,6 +11,7 @@ import type {LoggerNode} from "@lodestar/logger/node";
11
11
  import {ResponseIncoming, ResponseOutgoing} from "@lodestar/reqresp";
12
12
  import {Status} from "@lodestar/types";
13
13
  import {withTimeout} from "@lodestar/utils";
14
+ import {GoodByeReasonCode} from "../../constants/index.js";
14
15
  import {Metrics} from "../../metrics/index.js";
15
16
  import {AsyncIterableBridgeCaller, AsyncIterableBridgeHandler} from "../../util/asyncIterableToEvents.js";
16
17
  import {PeerIdStr, peerIdFromString} from "../../util/peerId.js";
@@ -205,6 +206,9 @@ export class WorkerNetworkCore implements INetworkCore {
205
206
  reStatusPeers(peers: PeerIdStr[]): Promise<void> {
206
207
  return this.getApi().reStatusPeers(peers);
207
208
  }
209
+ goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void> {
210
+ return this.getApi().goodbyeAndDisconnect(peer, reason);
211
+ }
208
212
  reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): Promise<void> {
209
213
  return this.getApi().reportPeer(peer, action, actionName);
210
214
  }
@@ -5,6 +5,7 @@ import {SpecJson} from "@lodestar/config";
5
5
  import {LoggerNodeOpts} from "@lodestar/logger/node";
6
6
  import {ResponseIncoming} from "@lodestar/reqresp";
7
7
  import {Status} from "@lodestar/types";
8
+ import {GoodByeReasonCode} from "../../constants/index.js";
8
9
  import {PeerIdStr} from "../../util/peerId.js";
9
10
  import {NetworkOptions} from "../options.js";
10
11
  import {PeerAction, PeerScoreStats} from "../peers/index.js";
@@ -53,6 +54,7 @@ export interface INetworkCore extends INetworkCorePublic {
53
54
  // Sync method
54
55
  reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): void;
55
56
  reStatusPeers(peers: PeerIdStr[]): Promise<void>;
57
+ goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void>;
56
58
 
57
59
  // TODO: Duplicated methods with INetwork interface
58
60
  getConnectedPeers(): Promise<PeerIdStr[]>;
@@ -37,6 +37,7 @@ import {
37
37
  phase0,
38
38
  } from "@lodestar/types";
39
39
  import {BlockInputSource} from "../chain/blocks/blockInput/types.js";
40
+ import {GoodByeReasonCode} from "../constants/index.js";
40
41
  import {CustodyConfig} from "../util/dataColumns.js";
41
42
  import {PeerIdStr} from "../util/peerId.js";
42
43
  import {
@@ -74,6 +75,7 @@ export interface INetwork extends INetworkCorePublic {
74
75
  reportPeer(peer: PeerIdStr, action: PeerAction, actionName: string): void;
75
76
  shouldAggregate(subnet: SubnetID, slot: Slot): boolean;
76
77
  reStatusPeers(peers: PeerIdStr[]): Promise<void>;
78
+ goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void>;
77
79
  searchUnknownBlock(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void;
78
80
  searchUnknownEnvelope(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void;
79
81
  // ReqResp
@@ -34,6 +34,7 @@ import {prettyPrintIndices, sleep} from "@lodestar/utils";
34
34
  import {BlockInputSource} from "../chain/blocks/blockInput/types.js";
35
35
  import {ChainEvent, IBeaconChain} from "../chain/index.js";
36
36
  import {computeSubnetForDataColumnSidecar} from "../chain/validation/dataColumnSidecar.js";
37
+ import {GoodByeReasonCode} from "../constants/index.js";
37
38
  import {IBeaconDb} from "../db/interface.js";
38
39
  import {Metrics, RegistryMetricCreator} from "../metrics/index.js";
39
40
  import {IClock} from "../util/clock.js";
@@ -289,6 +290,10 @@ export class Network implements INetwork {
289
290
  return this.core.reStatusPeers(peers);
290
291
  }
291
292
 
293
+ async goodbyeAndDisconnect(peer: PeerIdStr, reason: GoodByeReasonCode): Promise<void> {
294
+ return this.core.goodbyeAndDisconnect(peer, reason);
295
+ }
296
+
292
297
  searchUnknownBlock(slotRoot: SlotRootHex, source: BlockInputSource, peer?: PeerIdStr): void {
293
298
  this.networkProcessor.searchUnknownBlock(slotRoot, source, peer);
294
299
  }
@@ -855,7 +860,9 @@ export class Network implements INetwork {
855
860
  };
856
861
 
857
862
  private onTargetGroupCountUpdated = (count: number): void => {
858
- this.core.setTargetGroupCount(count);
863
+ this.core.setTargetGroupCount(count).catch((e) => {
864
+ this.logger.debug("Error setting target custody group count", {count}, e as Error);
865
+ });
859
866
  };
860
867
 
861
868
  private onPublishDataColumns = async (sidecars: DataColumnSidecar[]): Promise<void> => {
@@ -893,7 +893,7 @@ export class PeerManager {
893
893
  }
894
894
  }
895
895
 
896
- private async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
896
+ async goodbyeAndDisconnect(peer: PeerId, goodbye: GoodByeReasonCode): Promise<void> {
897
897
  const reason = GOODBYE_KNOWN_CODES[goodbye.toString()] || "";
898
898
  const peerIdStr = peer.toString();
899
899
  try {
@@ -1,5 +1,6 @@
1
- import {ForkName, isForkPostFulu} from "@lodestar/params";
2
- import {ForkDigest, Root, Slot, Status, fulu, ssz} from "@lodestar/types";
1
+ import {ForkName, GENESIS_EPOCH, isForkPostFulu} from "@lodestar/params";
2
+ import {computeEpochAtSlot} from "@lodestar/state-transition";
3
+ import {Epoch, ForkDigest, Root, Slot, Status, fulu, ssz} from "@lodestar/types";
3
4
  import {toHex, toRootHex} from "@lodestar/utils";
4
5
 
5
6
  // TODO: Why this value? (From Lighthouse)
@@ -9,6 +10,8 @@ export enum IrrelevantPeerCode {
9
10
  INCOMPATIBLE_FORKS = "IRRELEVANT_PEER_INCOMPATIBLE_FORKS",
10
11
  DIFFERENT_CLOCKS = "IRRELEVANT_PEER_DIFFERENT_CLOCKS",
11
12
  DIFFERENT_FINALIZED = "IRRELEVANT_PEER_DIFFERENT_FINALIZED",
13
+ FINALIZED_EPOCH_TOO_HIGH = "IRRELEVANT_PEER_FINALIZED_EPOCH_TOO_HIGH",
14
+ INVALID_FINALIZED_ROOT = "IRRELEVANT_PEER_INVALID_FINALIZED_ROOT",
12
15
  NO_EARLIEST_AVAILABLE_SLOT = "NO_EARLIEST_AVAILABLE_SLOT",
13
16
  }
14
17
 
@@ -16,6 +19,8 @@ type IrrelevantPeerType =
16
19
  | {code: IrrelevantPeerCode.INCOMPATIBLE_FORKS; ours: ForkDigest; theirs: ForkDigest}
17
20
  | {code: IrrelevantPeerCode.DIFFERENT_CLOCKS; slotDiff: number}
18
21
  | {code: IrrelevantPeerCode.NO_EARLIEST_AVAILABLE_SLOT}
22
+ | {code: IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH; finalizedEpoch: Epoch; maxFinalizedEpoch: Epoch}
23
+ | {code: IrrelevantPeerCode.INVALID_FINALIZED_ROOT}
19
24
  | {code: IrrelevantPeerCode.DIFFERENT_FINALIZED; expectedRoot: Root; remoteRoot: Root};
20
25
 
21
26
  /**
@@ -45,29 +50,35 @@ export function assertPeerRelevance(
45
50
  return {code: IrrelevantPeerCode.DIFFERENT_CLOCKS, slotDiff};
46
51
  }
47
52
 
48
- // The remote's finalized epoch is less than or equal to ours, but the block root is
49
- // different to the one in our chain. Therefore, the node is on a different chain and we
50
- // should not communicate with them.
53
+ // A checkpoint can be finalized at the earliest at the start of epoch + 2
54
+ const maxFinalizedEpoch = Math.max(
55
+ GENESIS_EPOCH,
56
+ computeEpochAtSlot(Math.max(currentSlot, 0) + FUTURE_SLOT_TOLERANCE) - 2
57
+ );
58
+ if (remote.finalizedEpoch > maxFinalizedEpoch) {
59
+ return {
60
+ code: IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH,
61
+ finalizedEpoch: remote.finalizedEpoch,
62
+ maxFinalizedEpoch,
63
+ };
64
+ }
65
+
66
+ if (remote.finalizedEpoch > GENESIS_EPOCH && isZeroRoot(remote.finalizedRoot)) {
67
+ return {code: IrrelevantPeerCode.INVALID_FINALIZED_ROOT};
68
+ }
51
69
 
70
+ // The remote's finalized epoch is equal to ours, but the block root is different to the one in our chain.
71
+ // Therefore, the node is on a different chain and we should not communicate with them.
52
72
  if (
53
- remote.finalizedEpoch <= local.finalizedEpoch &&
54
- !isZeroRoot(remote.finalizedRoot) &&
55
- !isZeroRoot(local.finalizedRoot)
73
+ remote.finalizedEpoch === local.finalizedEpoch &&
74
+ !isZeroRoot(local.finalizedRoot) &&
75
+ !ssz.Root.equals(remote.finalizedRoot, local.finalizedRoot)
56
76
  ) {
57
- // NOTE: due to preferring to not access chain state here, we can't check the finalized root against our history.
58
- // The impact of not doing check is low: peers that are behind us we can't confirm they are in the same chain as us.
59
- // In the worst case they will attempt to sync from us, fail and disconnect. The ENR fork check should be sufficient
60
- // to differentiate most peers in normal network conditions.
61
- const remoteRoot = remote.finalizedRoot;
62
- const expectedRoot = remote.finalizedEpoch === local.finalizedEpoch ? local.finalizedRoot : null;
63
-
64
- if (expectedRoot !== null && !ssz.Root.equals(remoteRoot, expectedRoot)) {
65
- return {
66
- code: IrrelevantPeerCode.DIFFERENT_FINALIZED,
67
- expectedRoot: expectedRoot, // forkChoice returns Tree BranchNode which the logger prints as {}
68
- remoteRoot: remoteRoot,
69
- };
70
- }
77
+ return {
78
+ code: IrrelevantPeerCode.DIFFERENT_FINALIZED,
79
+ expectedRoot: local.finalizedRoot,
80
+ remoteRoot: remote.finalizedRoot,
81
+ };
71
82
  }
72
83
 
73
84
  if (isForkPostFulu(forkName) && (remote as fulu.Status).earliestAvailableSlot === undefined) {
@@ -76,7 +87,8 @@ export function assertPeerRelevance(
76
87
  };
77
88
  }
78
89
 
79
- // Note: Accept request status finalized checkpoint in the future, we do not know if it is a true finalized root
90
+ // Note: for a behind finalized checkpoint, we validate it more on the main thread against our history,
91
+ // see BeaconSync.verifyPastFinalizedCheckpoint
80
92
  return null;
81
93
  }
82
94
 
@@ -93,6 +105,10 @@ export function renderIrrelevantPeerType(type: IrrelevantPeerType): string {
93
105
  return `DIFFERENT_CLOCKS slotDiff: ${type.slotDiff}`;
94
106
  case IrrelevantPeerCode.DIFFERENT_FINALIZED:
95
107
  return `DIFFERENT_FINALIZED root: ${toRootHex(type.remoteRoot)} expected: ${toRootHex(type.expectedRoot)}`;
108
+ case IrrelevantPeerCode.FINALIZED_EPOCH_TOO_HIGH:
109
+ return `FINALIZED_EPOCH_TOO_HIGH finalizedEpoch: ${type.finalizedEpoch} max: ${type.maxFinalizedEpoch}`;
110
+ case IrrelevantPeerCode.INVALID_FINALIZED_ROOT:
111
+ return "INVALID_FINALIZED_ROOT zero root for a non-genesis finalized epoch";
96
112
  case IrrelevantPeerCode.NO_EARLIEST_AVAILABLE_SLOT:
97
113
  return "No earliestAvailableSlot announced via peer Status";
98
114
  }
@@ -705,10 +705,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
705
705
 
706
706
  // Immediately attempt fetch of data columns from execution engine as the bid contains kzg commitments
707
707
  // which is all the information we need so there is no reason to delay until execution payload arrives
708
- // TODO GLOAS: If we want EL retries after this initial attempt, add an explicit retry policy here
709
- // (for example later in the slot). Do not couple retries to incoming gossip columns.
710
- // Columns fetched here feed payloadInput.addColumn, which resolves waitForAllData for any
711
- // in-flight importExecutionPayload. No processExecutionPayload trigger needed from this path.
708
+ // Columns fetched here feed payloadInput.addColumn, which resolves the waitForAllData of a
709
+ // pending payload import. No processExecutionPayload trigger needed from this path.
712
710
  chain.getBlobsTracker.triggerGetBlobs(payloadInput);
713
711
  }
714
712
  })
@@ -718,11 +716,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
718
716
 
719
717
  if (e instanceof BlockError) {
720
718
  switch (e.type.code) {
721
- case BlockErrorCode.DATA_UNAVAILABLE: {
722
- // Error is quite frequent and not critical
719
+ case BlockErrorCode.DATA_UNAVAILABLE:
720
+ // Data did not arrive in time, BlockInputSync keeps pulling it and retries the import
723
721
  logLevel = LogLevel.debug;
724
722
  break;
725
- }
726
723
  // ALREADY_KNOWN should not happen with ignoreIfKnown=true above
727
724
  // PARENT_BLOCK_UNKNOWN should not happen, we handled this in validateBeaconBlock() function above
728
725
  case BlockErrorCode.ALREADY_KNOWN:
@@ -930,7 +927,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
930
927
  }
931
928
 
932
929
  // NOTE: we do NOT call chain.processExecutionPayload here. That is triggered only by
933
- // envelope arrival (gossip or API). An in-flight importExecutionPayload is awaiting
930
+ // envelope arrival (gossip or API). A pending payload import is awaiting
934
931
  // payloadInput.waitForAllData(); addColumn above will resolve it once hasAllData flips.
935
932
 
936
933
  scheduleIncompletePayloadEnvelope(payloadInput, peerIdStr);
@@ -1358,6 +1355,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1358
1355
 
1359
1356
  if (e instanceof PayloadError) {
1360
1357
  switch (e.type.code) {
1358
+ case PayloadErrorCode.DATA_UNAVAILABLE:
1359
+ // Columns did not arrive in time, BlockInputSync keeps pulling them and retries the import
1360
+ logLevel = LogLevel.debug;
1361
+ break;
1361
1362
  // BLOCK_NOT_IN_FORK_CHOICE should not happen, validateGossipExecutionPayloadEnvelope above
1362
1363
  // already verified the block is in fork choice
1363
1364
  case PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE: