@lodestar/beacon-node 1.48.0-dev.262a9c1d16 → 1.48.0-dev.293e560a59

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 (45) hide show
  1. package/lib/api/impl/validator/index.d.ts.map +1 -1
  2. package/lib/api/impl/validator/index.js +39 -39
  3. package/lib/api/impl/validator/index.js.map +1 -1
  4. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  5. package/lib/chain/blocks/importBlock.js +13 -0
  6. package/lib/chain/blocks/importBlock.js.map +1 -1
  7. package/lib/chain/chain.d.ts +0 -5
  8. package/lib/chain/chain.d.ts.map +1 -1
  9. package/lib/chain/chain.js +38 -67
  10. package/lib/chain/chain.js.map +1 -1
  11. package/lib/chain/emitter.d.ts +1 -1
  12. package/lib/chain/emitter.js +1 -1
  13. package/lib/chain/errors/blockError.d.ts +5 -3
  14. package/lib/chain/errors/blockError.d.ts.map +1 -1
  15. package/lib/chain/errors/blockError.js +2 -2
  16. package/lib/chain/errors/blockError.js.map +1 -1
  17. package/lib/chain/errors/executionPayloadEnvelope.d.ts +11 -0
  18. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  19. package/lib/chain/errors/executionPayloadEnvelope.js +2 -0
  20. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  21. package/lib/chain/prepareNextSlot.js +13 -13
  22. package/lib/chain/prepareNextSlot.js.map +1 -1
  23. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  24. package/lib/chain/produceBlock/produceBlockBody.js +64 -46
  25. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  26. package/lib/chain/validation/block.d.ts.map +1 -1
  27. package/lib/chain/validation/block.js +50 -9
  28. package/lib/chain/validation/block.js.map +1 -1
  29. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  30. package/lib/chain/validation/executionPayloadEnvelope.js +29 -0
  31. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  32. package/lib/network/reqresp/rateLimit.js +1 -2
  33. package/lib/network/reqresp/rateLimit.js.map +1 -1
  34. package/package.json +15 -15
  35. package/src/api/impl/validator/index.ts +43 -44
  36. package/src/chain/blocks/importBlock.ts +13 -0
  37. package/src/chain/chain.ts +46 -74
  38. package/src/chain/emitter.ts +1 -1
  39. package/src/chain/errors/blockError.ts +3 -3
  40. package/src/chain/errors/executionPayloadEnvelope.ts +9 -0
  41. package/src/chain/prepareNextSlot.ts +16 -16
  42. package/src/chain/produceBlock/produceBlockBody.ts +71 -50
  43. package/src/chain/validation/block.ts +66 -9
  44. package/src/chain/validation/executionPayloadEnvelope.ts +37 -0
  45. package/src/network/reqresp/rateLimit.ts +1 -2
@@ -1,6 +1,22 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
2
  import {ExecutionStatus} from "@lodestar/fork-choice";
3
- import {ForkName, MIN_SEED_LOOKAHEAD, isForkPostBellatrix, isForkPostDeneb, isForkPostGloas} from "@lodestar/params";
3
+ import {
4
+ ForkName,
5
+ MAX_ATTESTATIONS_ELECTRA,
6
+ MAX_ATTESTER_SLASHINGS_ELECTRA,
7
+ MAX_BLS_TO_EXECUTION_CHANGES,
8
+ MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
9
+ MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
10
+ MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
11
+ MAX_PAYLOAD_ATTESTATIONS,
12
+ MAX_PROPOSER_SLASHINGS,
13
+ MAX_VOLUNTARY_EXITS,
14
+ MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
15
+ MIN_SEED_LOOKAHEAD,
16
+ isForkPostBellatrix,
17
+ isForkPostDeneb,
18
+ isForkPostGloas,
19
+ } from "@lodestar/params";
4
20
  import {
5
21
  computeEpochAtSlot,
6
22
  computeStartSlotAtEpoch,
@@ -157,8 +173,7 @@ export async function validateGossipBlock(
157
173
  }
158
174
 
159
175
  if (isForkPostGloas(fork)) {
160
- const body = (block as gloas.BeaconBlock).body;
161
- const bid = body.signedExecutionPayloadBid.message;
176
+ const bid = (block as gloas.BeaconBlock).body.signedExecutionPayloadBid.message;
162
177
 
163
178
  // [REJECT] The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer
164
179
  // -- i.e. validate that len(bid.blob_kzg_commitments) <= max_blobs_per_block
@@ -181,12 +196,54 @@ export async function validateGossipBlock(
181
196
  });
182
197
  }
183
198
 
184
- // [REJECT] The block contains no deposits.
185
- if (body.deposits.length !== 0) {
186
- throw new BlockGossipError(GossipAction.REJECT, {
187
- code: BlockErrorCode.NON_ZERO_DEPOSITS,
188
- count: body.deposits.length,
189
- });
199
+ // [REJECT] The counts of `block.body.parent_execution_requests` are within
200
+ // their respective limits -- i.e. validate that
201
+ // `len(block.body.parent_execution_requests.withdrawals) <= MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD`,
202
+ // `len(block.body.parent_execution_requests.consolidations) <= MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD`,
203
+ // `len(block.body.parent_execution_requests.builder_deposits) <= MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD`,
204
+ // and
205
+ // `len(block.body.parent_execution_requests.builder_exits) <= MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD`.
206
+ // [REJECT] The counts of the block body operations are within their respective
207
+ // limits -- i.e. validate that
208
+ // `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`,
209
+ // `len(block.body.attester_slashings) <= MAX_ATTESTER_SLASHINGS_ELECTRA`,
210
+ // `len(block.body.attestations) <= MAX_ATTESTATIONS_ELECTRA`,
211
+ // `len(block.body.deposits) == 0`,
212
+ // `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`,
213
+ // `len(block.body.bls_to_execution_changes) <= MAX_BLS_TO_EXECUTION_CHANGES`,
214
+ // and `len(block.body.payload_attestations) <= MAX_PAYLOAD_ATTESTATIONS`.
215
+ const body = (block as gloas.BeaconBlock).body;
216
+ const requests = body.parentExecutionRequests;
217
+ const countLimits: [string, number, number][] = [
218
+ ["parentExecutionRequests.withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
219
+ [
220
+ "parentExecutionRequests.consolidations",
221
+ requests.consolidations.length,
222
+ MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
223
+ ],
224
+ [
225
+ "parentExecutionRequests.builderDeposits",
226
+ requests.builderDeposits.length,
227
+ MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
228
+ ],
229
+ ["parentExecutionRequests.builderExits", requests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
230
+ ["proposerSlashings", body.proposerSlashings.length, MAX_PROPOSER_SLASHINGS],
231
+ ["attesterSlashings", body.attesterSlashings.length, MAX_ATTESTER_SLASHINGS_ELECTRA],
232
+ ["attestations", body.attestations.length, MAX_ATTESTATIONS_ELECTRA],
233
+ ["deposits", body.deposits.length, 0],
234
+ ["voluntaryExits", body.voluntaryExits.length, MAX_VOLUNTARY_EXITS],
235
+ ["blsToExecutionChanges", body.blsToExecutionChanges.length, MAX_BLS_TO_EXECUTION_CHANGES],
236
+ ["payloadAttestations", body.payloadAttestations.length, MAX_PAYLOAD_ATTESTATIONS],
237
+ ];
238
+ for (const [name, count, limit] of countLimits) {
239
+ if (count > limit) {
240
+ throw new BlockGossipError(GossipAction.REJECT, {
241
+ code: BlockErrorCode.TOO_MANY_BLOCK_OPERATIONS,
242
+ name,
243
+ count,
244
+ limit,
245
+ });
246
+ }
190
247
  }
191
248
 
192
249
  // TODO GLOAS: [REJECT] The block's execution payload parent (defined by bid.parent_block_hash) passes all validation
@@ -1,4 +1,11 @@
1
1
  import {PayloadStatus} from "@lodestar/fork-choice";
2
+ import {
3
+ MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
4
+ MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
5
+ MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
6
+ MAX_WITHDRAWALS_PER_PAYLOAD,
7
+ MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
8
+ } from "@lodestar/params";
2
9
  import {
3
10
  computeStartSlotAtEpoch,
4
11
  getExecutionPayloadEnvelopeSignatureSet,
@@ -115,6 +122,36 @@ async function validateExecutionPayloadEnvelope(
115
122
  });
116
123
  }
117
124
 
125
+ // [REJECT] The counts of `execution_requests` are within their respective limits.
126
+ // New in Gloas:EIP7688 — progressive lists are unbounded at the type level, so bounds
127
+ // are enforced here in gossip validation.
128
+ const {executionRequests} = envelope;
129
+ const requestCountLimits: [string, number, number][] = [
130
+ ["withdrawals", executionRequests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
131
+ ["consolidations", executionRequests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD],
132
+ ["builderDeposits", executionRequests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD],
133
+ ["builderExits", executionRequests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
134
+ ];
135
+ for (const [name, count, limit] of requestCountLimits) {
136
+ if (count > limit) {
137
+ throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
138
+ code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_COUNT_EXCEEDED,
139
+ name,
140
+ count,
141
+ limit,
142
+ });
143
+ }
144
+ }
145
+
146
+ // [REJECT] The number of withdrawals is within the limit.
147
+ if (payload.withdrawals.length > MAX_WITHDRAWALS_PER_PAYLOAD) {
148
+ throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
149
+ code: ExecutionPayloadEnvelopeErrorCode.WITHDRAWALS_COUNT_EXCEEDED,
150
+ count: payload.withdrawals.length,
151
+ limit: MAX_WITHDRAWALS_PER_PAYLOAD,
152
+ });
153
+ }
154
+
118
155
  // Get the block state to verify the builder's signature.
119
156
  const blockState = await chain.regen
120
157
  .getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)
@@ -126,8 +126,7 @@ function getRequestCountFn<T extends ReqRespMethod>(
126
126
  const type = requestSszTypeByMethod(fork, config)[method];
127
127
  return (reqData: Uint8Array) => {
128
128
  try {
129
- // A schema-valid request can cost 0 tokens; floor to 1 so it stays charged and bannable, not free.
130
- return Math.max(1, (type && fn(type.deserialize(reqData))) ?? 1);
129
+ return (type && fn(type.deserialize(reqData))) ?? 1;
131
130
  } catch (_e) {
132
131
  return 1;
133
132
  }