@lodestar/beacon-node 1.48.0-dev.7d85330f92 → 1.48.0-dev.b24dce51bf
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.
- package/lib/chain/lightClient/index.d.ts +3 -3
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +21 -23
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts +2 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +5 -1
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +40 -40
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +5 -6
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/execution/builder/validateBid.js +5 -5
- package/lib/execution/builder/validateBid.js.map +1 -1
- package/lib/network/network.js +2 -2
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +10 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/package.json +14 -14
- package/src/chain/lightClient/index.ts +32 -36
- package/src/chain/lightClient/proofs.ts +10 -0
- package/src/chain/validation/executionPayloadBid.ts +44 -44
- package/src/chain/validation/payloadAttestationMessage.ts +8 -9
- package/src/execution/builder/validateBid.ts +6 -6
- package/src/network/network.ts +2 -2
- package/src/network/processor/gossipHandlers.ts +15 -9
|
@@ -104,6 +104,28 @@ export async function validateApiExecutionPayloadBid(
|
|
|
104
104
|
const bid = signedExecutionPayloadBid.message;
|
|
105
105
|
const bidParentBlockRoot = toRootHex(bid.parentBlockRoot);
|
|
106
106
|
|
|
107
|
+
// [REJECT] `bid.execution_payment` is zero.
|
|
108
|
+
if (bid.executionPayment !== 0n) {
|
|
109
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
110
|
+
code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT,
|
|
111
|
+
builderIndex: bid.builderIndex,
|
|
112
|
+
executionPayment: bid.executionPayment,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
117
|
+
// consensus layer -- i.e. validate that
|
|
118
|
+
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
119
|
+
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
120
|
+
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
121
|
+
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
122
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
123
|
+
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
124
|
+
blobKzgCommitmentsLen,
|
|
125
|
+
commitmentLimit: maxBlobsPerBlock,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
107
129
|
// [IGNORE] `bid.slot` is the current slot, or the next slot (`bid.slot - 1` is current), allowing for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
|
|
108
130
|
if (
|
|
109
131
|
!chain.clock.isCurrentSlotGivenGossipDisparity(bid.slot) &&
|
|
@@ -138,28 +160,6 @@ export async function validateApiExecutionPayloadBid(
|
|
|
138
160
|
});
|
|
139
161
|
}
|
|
140
162
|
|
|
141
|
-
// [REJECT] `bid.execution_payment` is zero.
|
|
142
|
-
if (bid.executionPayment !== 0n) {
|
|
143
|
-
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
144
|
-
code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT,
|
|
145
|
-
builderIndex: bid.builderIndex,
|
|
146
|
-
executionPayment: bid.executionPayment,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
151
|
-
// consensus layer -- i.e. validate that
|
|
152
|
-
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
153
|
-
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
154
|
-
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
155
|
-
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
156
|
-
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
157
|
-
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
158
|
-
blobKzgCommitmentsLen,
|
|
159
|
-
commitmentLimit: maxBlobsPerBlock,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
163
|
const state = await chain.regen
|
|
164
164
|
.getBlockSlotState(parentBlock, bid.slot, {dontTransferCache: true}, RegenCaller.validateApiExecutionPayloadBid)
|
|
165
165
|
.catch(() => {
|
|
@@ -257,6 +257,28 @@ async function validateExecutionPayloadBid(
|
|
|
257
257
|
const bidParentBlockRoot = toRootHex(bid.parentBlockRoot);
|
|
258
258
|
const bidParentBlockHash = toRootHex(bid.parentBlockHash);
|
|
259
259
|
|
|
260
|
+
// [REJECT] `bid.execution_payment` is zero.
|
|
261
|
+
if (bid.executionPayment !== 0n) {
|
|
262
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
263
|
+
code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT,
|
|
264
|
+
builderIndex: bid.builderIndex,
|
|
265
|
+
executionPayment: bid.executionPayment,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
270
|
+
// consensus layer -- i.e. validate that
|
|
271
|
+
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
272
|
+
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
273
|
+
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
274
|
+
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
275
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
276
|
+
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
277
|
+
blobKzgCommitmentsLen,
|
|
278
|
+
commitmentLimit: maxBlobsPerBlock,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
260
282
|
// [IGNORE] `bid.slot` is the current slot, or the next slot (`bid.slot - 1` is current), allowing for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
|
|
261
283
|
if (
|
|
262
284
|
!chain.clock.isCurrentSlotGivenGossipDisparity(bid.slot) &&
|
|
@@ -402,15 +424,6 @@ async function validateExecutionPayloadBid(
|
|
|
402
424
|
});
|
|
403
425
|
}
|
|
404
426
|
|
|
405
|
-
// [REJECT] `bid.execution_payment` is zero.
|
|
406
|
-
if (bid.executionPayment !== 0n) {
|
|
407
|
-
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
408
|
-
code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT,
|
|
409
|
-
builderIndex: bid.builderIndex,
|
|
410
|
-
executionPayment: bid.executionPayment,
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
427
|
// [IGNORE] `bid.fee_recipient == proposer_preferences.fee_recipient`.
|
|
415
428
|
if (!byteArrayEquals(bid.feeRecipient, proposerPreferences.message.feeRecipient)) {
|
|
416
429
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
@@ -451,19 +464,6 @@ async function validateExecutionPayloadBid(
|
|
|
451
464
|
});
|
|
452
465
|
}
|
|
453
466
|
|
|
454
|
-
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
455
|
-
// consensus layer -- i.e. validate that
|
|
456
|
-
// `len(bid.blob_kzg_commitments) <= get_blob_parameters(compute_epoch_at_slot(bid.slot)).max_blobs_per_block`.
|
|
457
|
-
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
458
|
-
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
459
|
-
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
460
|
-
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
461
|
-
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS,
|
|
462
|
-
blobKzgCommitmentsLen,
|
|
463
|
-
commitmentLimit: maxBlobsPerBlock,
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
|
|
467
467
|
// [IGNORE] this bid is the highest value bid seen for the tuple
|
|
468
468
|
// `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
|
|
469
469
|
// As a DoS prevention measure, the bid must also exceed the current highest bid by a minimum
|
|
@@ -7,7 +7,6 @@ import {RootHex, gloas, ssz} from "@lodestar/types";
|
|
|
7
7
|
import {toRootHex} from "@lodestar/utils";
|
|
8
8
|
import {GossipAction, PayloadAttestationError, PayloadAttestationErrorCode} from "../errors/index.js";
|
|
9
9
|
import {IBeaconChain} from "../index.js";
|
|
10
|
-
import {RegenCaller} from "../regen/index.js";
|
|
11
10
|
|
|
12
11
|
export type PayloadAttestationValidationResult = {
|
|
13
12
|
attDataRootHex: RootHex;
|
|
@@ -82,15 +81,15 @@ async function validatePayloadAttestationMessage(
|
|
|
82
81
|
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
|
|
83
82
|
// it is possible that the block didn't pass the validation
|
|
84
83
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
84
|
+
// block.slot === data.slot is enforced above, so use the block's post-state directly to avoid
|
|
85
|
+
// getting through regen queue
|
|
86
|
+
const state = chain.regen.getStateSync(block.stateRoot);
|
|
87
|
+
if (state == null) {
|
|
88
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
89
|
+
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
90
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
93
91
|
});
|
|
92
|
+
}
|
|
94
93
|
|
|
95
94
|
if (!isStatePostGloas(state)) {
|
|
96
95
|
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
|
|
@@ -56,6 +56,12 @@ export async function validateBuilderApiExecutionPayloadBid(
|
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
60
|
+
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
61
|
+
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
62
|
+
throw Error(`Bid has too many KZG commitments len=${blobKzgCommitmentsLen} limit=${maxBlobsPerBlock}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
59
65
|
const totalPayment = getBuilderBidTotalGwei(bid, entry.maxExecutionPayment);
|
|
60
66
|
if (totalPayment < entry.minBid) {
|
|
61
67
|
throw Error(
|
|
@@ -100,12 +106,6 @@ export async function validateBuilderApiExecutionPayloadBid(
|
|
|
100
106
|
);
|
|
101
107
|
}
|
|
102
108
|
|
|
103
|
-
const blobKzgCommitmentsLen = bid.blobKzgCommitments.length;
|
|
104
|
-
const maxBlobsPerBlock = chain.config.getMaxBlobsPerBlock(computeEpochAtSlot(bid.slot));
|
|
105
|
-
if (blobKzgCommitmentsLen > maxBlobsPerBlock) {
|
|
106
|
-
throw Error(`Bid has too many KZG commitments len=${blobKzgCommitmentsLen} limit=${maxBlobsPerBlock}`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
109
|
// The coverage check only applies to the staked collateral payment, a pure execution
|
|
110
110
|
// layer payment bid has nothing to cover on-chain
|
|
111
111
|
if (bid.value > 0 && !state.canBuilderCoverBid(bid.builderIndex, bid.value)) {
|
package/src/network/network.ts
CHANGED
|
@@ -481,7 +481,7 @@ export class Network implements INetwork {
|
|
|
481
481
|
}
|
|
482
482
|
|
|
483
483
|
async publishLightClientFinalityUpdate(update: LightClientFinalityUpdate): Promise<number> {
|
|
484
|
-
const epoch = computeEpochAtSlot(update.
|
|
484
|
+
const epoch = computeEpochAtSlot(update.attestedHeader.beacon.slot);
|
|
485
485
|
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
486
486
|
|
|
487
487
|
return this.publishGossip<GossipType.light_client_finality_update>(
|
|
@@ -491,7 +491,7 @@ export class Network implements INetwork {
|
|
|
491
491
|
}
|
|
492
492
|
|
|
493
493
|
async publishLightClientOptimisticUpdate(update: LightClientOptimisticUpdate): Promise<number> {
|
|
494
|
-
const epoch = computeEpochAtSlot(update.
|
|
494
|
+
const epoch = computeEpochAtSlot(update.attestedHeader.beacon.slot);
|
|
495
495
|
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
496
496
|
|
|
497
497
|
return this.publishGossip<GossipType.light_client_optimistic_update>(
|
|
@@ -1268,16 +1268,22 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1268
1268
|
const delaySec = chain.clock.secFromSlot(payloadAttestationMessage.data.slot, seenTimestampSec);
|
|
1269
1269
|
metrics?.gossipPayloadAttestationMessage.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
|
|
1270
1270
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1271
|
+
const nextSlotProposer = chain.getHeadState().getBeaconProposer(payloadAttestationMessage.data.slot + 1);
|
|
1272
|
+
const isNextSlotProposer = chain.beaconProposerCache.get(nextSlotProposer) !== undefined;
|
|
1273
|
+
|
|
1274
|
+
if (isNextSlotProposer) {
|
|
1275
|
+
try {
|
|
1276
|
+
const insertOutcome = chain.payloadAttestationPool.add(
|
|
1277
|
+
payloadAttestationMessage,
|
|
1278
|
+
validationResult.attDataRootHex,
|
|
1279
|
+
validationResult.validatorCommitteeIndices
|
|
1280
|
+
);
|
|
1281
|
+
metrics?.opPool.payloadAttestationPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1282
|
+
} catch (e) {
|
|
1283
|
+
logger.debug("Error adding to payloadAttestation pool", {}, e as Error);
|
|
1284
|
+
}
|
|
1280
1285
|
}
|
|
1286
|
+
|
|
1281
1287
|
chain.forkChoice.notifyPtcMessages(
|
|
1282
1288
|
toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
1283
1289
|
payloadAttestationMessage.data.slot,
|