@lodestar/beacon-node 1.44.0-dev.16e0233677 → 1.44.0-dev.171f6028ff
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/api/impl/beacon/blocks/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +36 -33
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +0 -25
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/config/constants.d.ts +4 -0
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +5 -1
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +28 -0
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +20 -27
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +3 -2
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +3 -3
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/chain.d.ts +2 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +9 -2
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +2 -1
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +0 -7
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +0 -3
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +12 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +2 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts +4 -4
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +10 -7
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -0
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +2 -2
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +4 -4
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/validation/block.d.ts +5 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +4 -14
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +23 -1
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +1 -3
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/execution/engine/http.js +1 -1
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +2 -2
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/interface.js +6 -2
- package/lib/execution/engine/interface.js.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +3 -5
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/types.d.ts +15 -7
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +47 -9
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +4 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +10 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +22 -2
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +9 -2
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/index.d.ts +2 -2
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +25 -23
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +9 -5
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +8 -3
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +13 -3
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/index.js +2 -2
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +1 -2
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/sync/types.d.ts +9 -1
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +9 -2
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +64 -30
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/dataColumns.d.ts.map +1 -1
- package/lib/util/dataColumns.js +16 -11
- package/lib/util/dataColumns.js.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +40 -42
- package/src/api/impl/beacon/pool/index.ts +1 -41
- package/src/api/impl/config/constants.ts +8 -0
- package/src/api/impl/lodestar/index.ts +30 -0
- package/src/api/impl/validator/index.ts +29 -39
- package/src/chain/blocks/importBlock.ts +7 -5
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +3 -5
- package/src/chain/chain.ts +12 -4
- package/src/chain/emitter.ts +3 -2
- package/src/chain/errors/blockError.ts +0 -4
- package/src/chain/errors/executionPayloadBid.ts +14 -0
- package/src/chain/forkChoice/index.ts +13 -0
- package/src/chain/interface.ts +1 -2
- package/src/chain/options.ts +1 -0
- package/src/chain/produceBlock/produceBlockBody.ts +7 -7
- package/src/chain/validation/block.ts +12 -16
- package/src/chain/validation/executionPayloadBid.ts +25 -1
- package/src/chain/validation/executionPayloadEnvelope.ts +1 -3
- package/src/execution/engine/http.ts +1 -1
- package/src/execution/engine/interface.ts +12 -2
- package/src/execution/engine/mock.ts +6 -5
- package/src/execution/engine/types.ts +75 -14
- package/src/metrics/metrics/lodestar.ts +11 -0
- package/src/network/processor/gossipHandlers.ts +9 -2
- package/src/network/processor/index.ts +27 -27
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +12 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +11 -3
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +19 -3
- package/src/network/reqresp/handlers/index.ts +2 -2
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +1 -2
- package/src/sync/types.ts +11 -2
- package/src/sync/unknownBlock.ts +70 -31
- package/src/util/dataColumns.ts +17 -12
- package/src/util/sszBytes.ts +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import {routes} from "@lodestar/api";
|
|
1
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
3
|
import {
|
|
3
4
|
ExecutionStatus,
|
|
4
5
|
ForkChoice,
|
|
6
|
+
ForkChoiceStateGetter,
|
|
5
7
|
ForkChoiceStore,
|
|
6
8
|
JustifiedBalancesGetter,
|
|
7
9
|
PayloadStatus,
|
|
@@ -45,6 +47,7 @@ export function initializeForkChoice(
|
|
|
45
47
|
isFinalizedState: boolean,
|
|
46
48
|
opts: ForkChoiceOpts,
|
|
47
49
|
justifiedBalancesGetter: JustifiedBalancesGetter,
|
|
50
|
+
stateGetter: ForkChoiceStateGetter,
|
|
48
51
|
metrics: Metrics | null,
|
|
49
52
|
logger?: Logger
|
|
50
53
|
): ForkChoice {
|
|
@@ -56,6 +59,7 @@ export function initializeForkChoice(
|
|
|
56
59
|
state,
|
|
57
60
|
opts,
|
|
58
61
|
justifiedBalancesGetter,
|
|
62
|
+
stateGetter,
|
|
59
63
|
metrics,
|
|
60
64
|
logger
|
|
61
65
|
)
|
|
@@ -66,6 +70,7 @@ export function initializeForkChoice(
|
|
|
66
70
|
state,
|
|
67
71
|
opts,
|
|
68
72
|
justifiedBalancesGetter,
|
|
73
|
+
stateGetter,
|
|
69
74
|
metrics,
|
|
70
75
|
logger
|
|
71
76
|
);
|
|
@@ -81,6 +86,7 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
81
86
|
state: IBeaconStateView,
|
|
82
87
|
opts: ForkChoiceOpts,
|
|
83
88
|
justifiedBalancesGetter: JustifiedBalancesGetter,
|
|
89
|
+
stateGetter: ForkChoiceStateGetter,
|
|
84
90
|
metrics: Metrics | null,
|
|
85
91
|
logger?: Logger
|
|
86
92
|
): ForkChoice {
|
|
@@ -112,9 +118,12 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
112
118
|
finalizedCheckpoint,
|
|
113
119
|
justifiedBalances,
|
|
114
120
|
justifiedBalancesGetter,
|
|
121
|
+
stateGetter,
|
|
115
122
|
{
|
|
116
123
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
117
124
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
125
|
+
onFastConfirmation: ({block, slot, currentSlot}) =>
|
|
126
|
+
emitter.emit(routes.events.EventType.fastConfirmation, {block, slot, currentSlot}),
|
|
118
127
|
}
|
|
119
128
|
),
|
|
120
129
|
|
|
@@ -172,6 +181,7 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
172
181
|
unfinalizedState: IBeaconStateView,
|
|
173
182
|
opts: ForkChoiceOpts,
|
|
174
183
|
justifiedBalancesGetter: JustifiedBalancesGetter,
|
|
184
|
+
stateGetter: ForkChoiceStateGetter,
|
|
175
185
|
metrics: Metrics | null,
|
|
176
186
|
logger?: Logger
|
|
177
187
|
): ForkChoice {
|
|
@@ -203,9 +213,12 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
203
213
|
finalizedCheckpoint,
|
|
204
214
|
justifiedBalances,
|
|
205
215
|
justifiedBalancesGetter,
|
|
216
|
+
stateGetter,
|
|
206
217
|
{
|
|
207
218
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
208
219
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
220
|
+
onFastConfirmation: ({block, slot, currentSlot}) =>
|
|
221
|
+
emitter.emit(routes.events.EventType.fastConfirmation, {block, slot, currentSlot}),
|
|
209
222
|
}
|
|
210
223
|
);
|
|
211
224
|
|
package/src/chain/interface.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
altair,
|
|
19
19
|
capella,
|
|
20
20
|
deneb,
|
|
21
|
-
electra,
|
|
22
21
|
gloas,
|
|
23
22
|
phase0,
|
|
24
23
|
rewards,
|
|
@@ -236,7 +235,7 @@ export interface IBeaconChain {
|
|
|
236
235
|
blockSlot: Slot,
|
|
237
236
|
blockRootHex: string
|
|
238
237
|
): Promise<gloas.SignedExecutionPayloadEnvelope | null>;
|
|
239
|
-
getParentExecutionRequests(parentBlockSlot: Slot, parentBlockRootHex: RootHex): Promise<
|
|
238
|
+
getParentExecutionRequests(parentBlockSlot: Slot, parentBlockRootHex: RootHex): Promise<gloas.ExecutionRequests>;
|
|
240
239
|
|
|
241
240
|
produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
|
|
242
241
|
produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
|
package/src/chain/options.ts
CHANGED
|
@@ -105,6 +105,7 @@ export const defaultChainOptions: IChainOptions = {
|
|
|
105
105
|
proposerBoost: true,
|
|
106
106
|
proposerBoostReorg: true,
|
|
107
107
|
computeUnrealized: true,
|
|
108
|
+
fastConfirmation: false,
|
|
108
109
|
suggestedFeeRecipient: defaultValidatorOptions.suggestedFeeRecipient,
|
|
109
110
|
serveHistoricalState: false,
|
|
110
111
|
assertCorrectProgressiveBalances: false,
|
|
@@ -108,7 +108,7 @@ export type ProduceFullGloas = {
|
|
|
108
108
|
type: BlockType.Full;
|
|
109
109
|
fork: ForkPostGloas;
|
|
110
110
|
executionPayload: ExecutionPayload<ForkPostGloas>;
|
|
111
|
-
executionRequests:
|
|
111
|
+
executionRequests: gloas.ExecutionRequests;
|
|
112
112
|
blobsBundle: BlobsBundle<ForkPostGloas>;
|
|
113
113
|
cells: fulu.Cell[][];
|
|
114
114
|
parentBlockRoot: Root;
|
|
@@ -228,7 +228,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
228
228
|
);
|
|
229
229
|
const parentExecutionRequests = isExtendingPayload
|
|
230
230
|
? await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot)
|
|
231
|
-
: ssz.
|
|
231
|
+
: ssz.gloas.ExecutionRequests.defaultValue();
|
|
232
232
|
executionPayloadValue = BigInt(builderBid.message.value) * GWEI_TO_WEI;
|
|
233
233
|
|
|
234
234
|
const commonBlockBody = await commonBlockBodyPromise;
|
|
@@ -272,7 +272,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
272
272
|
|
|
273
273
|
// Get execution payload from EL
|
|
274
274
|
let parentBlockHash: Bytes32;
|
|
275
|
-
let parentExecutionRequests:
|
|
275
|
+
let parentExecutionRequests: gloas.ExecutionRequests;
|
|
276
276
|
// Apply parent payload once here as it's reused by EL prep and voluntary exit filtering below
|
|
277
277
|
let stateAfterParentPayload: IBeaconStateViewBellatrix = currentState;
|
|
278
278
|
// Spec: should_build_on_full(store, head). `parentBlock` is the proposer's head
|
|
@@ -285,7 +285,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
285
285
|
stateAfterParentPayload = currentState.withParentPayloadApplied(parentExecutionRequests);
|
|
286
286
|
} else {
|
|
287
287
|
parentBlockHash = currentState.latestExecutionPayloadBid.parentBlockHash;
|
|
288
|
-
parentExecutionRequests = ssz.
|
|
288
|
+
parentExecutionRequests = ssz.gloas.ExecutionRequests.defaultValue();
|
|
289
289
|
}
|
|
290
290
|
const prepareRes = await prepareExecutionPayload(
|
|
291
291
|
this,
|
|
@@ -344,13 +344,13 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
344
344
|
blockHash: executionPayload.blockHash,
|
|
345
345
|
prevRandao: currentState.getRandaoMix(currentState.epoch),
|
|
346
346
|
feeRecipient: executionPayload.feeRecipient,
|
|
347
|
-
gasLimit:
|
|
347
|
+
gasLimit: executionPayload.gasLimit,
|
|
348
348
|
builderIndex: BUILDER_INDEX_SELF_BUILD,
|
|
349
349
|
slot: blockSlot,
|
|
350
350
|
value: 0,
|
|
351
351
|
executionPayment: 0,
|
|
352
352
|
blobKzgCommitments: blobsBundle.commitments,
|
|
353
|
-
executionRequestsRoot: ssz.
|
|
353
|
+
executionRequestsRoot: ssz.gloas.ExecutionRequests.hashTreeRoot(executionRequests as gloas.ExecutionRequests),
|
|
354
354
|
};
|
|
355
355
|
const signedBid: gloas.SignedExecutionPayloadBid = {
|
|
356
356
|
message: bid,
|
|
@@ -375,7 +375,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
375
375
|
// Store execution payload data required to construct execution payload envelope later
|
|
376
376
|
const gloasResult = produceResult as ProduceFullGloas;
|
|
377
377
|
gloasResult.executionPayload = executionPayload as ExecutionPayload<ForkPostGloas>;
|
|
378
|
-
gloasResult.executionRequests = executionRequests;
|
|
378
|
+
gloasResult.executionRequests = executionRequests as gloas.ExecutionRequests;
|
|
379
379
|
gloasResult.blobsBundle = blobsBundle;
|
|
380
380
|
gloasResult.cells = cells;
|
|
381
381
|
gloasResult.parentBlockRoot = fromHex(parentBlock.blockRoot);
|
|
@@ -15,12 +15,17 @@ import {BlockErrorCode, BlockGossipError, GossipAction} from "../errors/index.js
|
|
|
15
15
|
import {IBeaconChain} from "../interface.js";
|
|
16
16
|
import {RegenCaller} from "../regen/index.js";
|
|
17
17
|
|
|
18
|
+
export type GossipBlockValidationResult = {
|
|
19
|
+
/** Number of skipped slots between the block and its parent (blockSlot - parentSlot - 1) */
|
|
20
|
+
skippedSlots: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
18
23
|
export async function validateGossipBlock(
|
|
19
24
|
config: ChainForkConfig,
|
|
20
25
|
chain: IBeaconChain,
|
|
21
26
|
signedBlock: SignedBeaconBlock,
|
|
22
27
|
fork: ForkName
|
|
23
|
-
): Promise<
|
|
28
|
+
): Promise<GossipBlockValidationResult> {
|
|
24
29
|
const block = signedBlock.message;
|
|
25
30
|
const blockSlot = block.slot;
|
|
26
31
|
const blockEpoch = computeEpochAtSlot(blockSlot);
|
|
@@ -109,21 +114,6 @@ export async function validateGossipBlock(
|
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
|
|
112
|
-
// [IGNORE] The attestation head block is too far behind the attestation slot, causing many skip slots.
|
|
113
|
-
// This is deemed a DoS risk because we need to get the proposerShuffling. To get the shuffling we have
|
|
114
|
-
// to do a bunch of epoch transitions, the longer the distance between the parent and block,
|
|
115
|
-
// the more we have to do. epochTransitions are expensive ~750ms, so we must limit how many a
|
|
116
|
-
// single bad block can trigger
|
|
117
|
-
// Note: Ensure this check is done before calling chain.regen.getBlockSlotStat as this is the function that does various epoch transitions.
|
|
118
|
-
// Note: This validation check is not part of the spec.
|
|
119
|
-
if (chain.opts.maxSkipSlots != null && parentBlock.slot + chain.opts.maxSkipSlots < blockSlot) {
|
|
120
|
-
throw new BlockGossipError(GossipAction.IGNORE, {
|
|
121
|
-
code: BlockErrorCode.TOO_MANY_SKIPPED_SLOTS,
|
|
122
|
-
parentSlot: parentBlock.slot,
|
|
123
|
-
blockSlot,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
117
|
// [REJECT] The block is from a higher slot than its parent.
|
|
128
118
|
if (parentBlock.slot >= blockSlot) {
|
|
129
119
|
throw new BlockGossipError(GossipAction.REJECT, {
|
|
@@ -133,6 +123,10 @@ export async function validateGossipBlock(
|
|
|
133
123
|
});
|
|
134
124
|
}
|
|
135
125
|
|
|
126
|
+
// Number of skipped slots between block and parent (non-spec). Previously this gated blocks via
|
|
127
|
+
// maxSkipSlots; now the caller only observes it so legitimate post-skip blocks are no longer ignored.
|
|
128
|
+
const skippedSlots = blockSlot - parentBlock.slot - 1;
|
|
129
|
+
|
|
136
130
|
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer -- i.e. validate that len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK
|
|
137
131
|
if (isForkPostDeneb(fork) && !isForkPostGloas(fork)) {
|
|
138
132
|
const blobKzgCommitmentsLen = (block as deneb.BeaconBlock).body.blobKzgCommitments.length;
|
|
@@ -247,4 +241,6 @@ export async function validateGossipBlock(
|
|
|
247
241
|
}
|
|
248
242
|
|
|
249
243
|
chain.seenBlockProposers.add(blockSlot, proposerIndex);
|
|
244
|
+
|
|
245
|
+
return {skippedSlots};
|
|
250
246
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {PublicKey} from "@chainsafe/blst";
|
|
2
|
+
import {PAYLOAD_BUILDER_VERSION} from "@lodestar/params";
|
|
2
3
|
import {
|
|
3
4
|
computeEpochAtSlot,
|
|
4
5
|
createSingleSignatureSetFromComponents,
|
|
@@ -139,6 +140,17 @@ async function validateExecutionPayloadBid(
|
|
|
139
140
|
});
|
|
140
141
|
}
|
|
141
142
|
|
|
143
|
+
// [REJECT] The builder version is `PAYLOAD_BUILDER_VERSION` -- i.e.
|
|
144
|
+
// `state.builders[bid.builder_index].version == PAYLOAD_BUILDER_VERSION`.
|
|
145
|
+
if (builder.version !== PAYLOAD_BUILDER_VERSION) {
|
|
146
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
147
|
+
code: ExecutionPayloadBidErrorCode.INVALID_BUILDER_VERSION,
|
|
148
|
+
builderIndex: bid.builderIndex,
|
|
149
|
+
version: builder.version,
|
|
150
|
+
expectedVersion: PAYLOAD_BUILDER_VERSION,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
142
154
|
// [REJECT] `bid.execution_payment` is zero.
|
|
143
155
|
if (bid.executionPayment !== 0) {
|
|
144
156
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
@@ -175,7 +187,7 @@ async function validateExecutionPayloadBid(
|
|
|
175
187
|
// [IGNORE] `is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, target_gas_limit)`,
|
|
176
188
|
// where `parent_gas_limit` is the `gas_limit` of the parent execution payload and
|
|
177
189
|
// `target_gas_limit` is `proposer_preferences.target_gas_limit`.
|
|
178
|
-
const bidGasLimit =
|
|
190
|
+
const bidGasLimit = bid.gasLimit;
|
|
179
191
|
const parentGasLimit = parentPayloadVariant.executionPayloadGasLimit;
|
|
180
192
|
const targetGasLimit = proposerPreferences.message.targetGasLimit;
|
|
181
193
|
if (!isGasLimitTargetCompatible(parentGasLimit, bidGasLimit, targetGasLimit)) {
|
|
@@ -232,6 +244,18 @@ async function validateExecutionPayloadBid(
|
|
|
232
244
|
});
|
|
233
245
|
}
|
|
234
246
|
|
|
247
|
+
// [REJECT] `bid.prev_randao` is the correct RANDAO mix -- i.e. validate that
|
|
248
|
+
// `bid.prev_randao == get_randao_mix(parent_state, get_current_epoch(parent_state))`.
|
|
249
|
+
const randaoMix = state.getRandaoMix(computeEpochAtSlot(state.slot));
|
|
250
|
+
if (!byteArrayEquals(bid.prevRandao, randaoMix)) {
|
|
251
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
252
|
+
code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO,
|
|
253
|
+
builderIndex: bid.builderIndex,
|
|
254
|
+
bidPrevRandao: toHex(bid.prevRandao),
|
|
255
|
+
expectedPrevRandao: toHex(randaoMix),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
235
259
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
236
260
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
237
261
|
PublicKey.fromBytes(builder.pubkey),
|
|
@@ -35,8 +35,6 @@ async function validateExecutionPayloadEnvelope(
|
|
|
35
35
|
// [IGNORE] The envelope's block root `envelope.beacon_block_root` has been seen (via
|
|
36
36
|
// gossip or non-gossip sources) (a client MAY queue payload for processing once
|
|
37
37
|
// the block is retrieved).
|
|
38
|
-
// TODO GLOAS: Need to review this, we should queue the envelope for later
|
|
39
|
-
// processing if the block is not yet known, otherwise we would ignore it here
|
|
40
38
|
const block = chain.forkChoice.getBlockDefaultStatus(envelope.beaconBlockRoot);
|
|
41
39
|
if (block === null) {
|
|
42
40
|
throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
|
|
@@ -108,7 +106,7 @@ async function validateExecutionPayloadEnvelope(
|
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
// [REJECT] `hash_tree_root(envelope.execution_requests) == bid.execution_requests_root`
|
|
111
|
-
const requestsRoot = ssz.
|
|
109
|
+
const requestsRoot = ssz.gloas.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
|
|
112
110
|
if (!byteArrayEquals(requestsRoot, payloadInput.getBid().executionRequestsRoot)) {
|
|
113
111
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
114
112
|
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH,
|
|
@@ -244,7 +244,7 @@ export class ExecutionEngineHttp implements IExecutionEngine {
|
|
|
244
244
|
if (executionRequests === undefined) {
|
|
245
245
|
throw Error(`executionRequests required in notifyNewPayload for fork=${fork}`);
|
|
246
246
|
}
|
|
247
|
-
const serializedExecutionRequests = serializeExecutionRequests(executionRequests);
|
|
247
|
+
const serializedExecutionRequests = serializeExecutionRequests(fork, executionRequests);
|
|
248
248
|
engineRequest = {
|
|
249
249
|
method: ForkSeq[fork] >= ForkSeq.gloas ? "engine_newPayloadV5" : "engine_newPayloadV4",
|
|
250
250
|
params: [
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {
|
|
3
|
+
BUILDER_DEPOSIT_REQUEST_TYPE,
|
|
4
|
+
BUILDER_EXIT_REQUEST_TYPE,
|
|
3
5
|
CONSOLIDATION_REQUEST_TYPE,
|
|
4
6
|
DEPOSIT_REQUEST_TYPE,
|
|
5
7
|
ForkName,
|
|
@@ -51,10 +53,18 @@ export enum ExecutionEngineState {
|
|
|
51
53
|
export type ExecutionRequestType =
|
|
52
54
|
| typeof DEPOSIT_REQUEST_TYPE
|
|
53
55
|
| typeof WITHDRAWAL_REQUEST_TYPE
|
|
54
|
-
| typeof CONSOLIDATION_REQUEST_TYPE
|
|
56
|
+
| typeof CONSOLIDATION_REQUEST_TYPE
|
|
57
|
+
| typeof BUILDER_DEPOSIT_REQUEST_TYPE
|
|
58
|
+
| typeof BUILDER_EXIT_REQUEST_TYPE;
|
|
55
59
|
|
|
56
60
|
export function isExecutionRequestType(type: number): type is ExecutionRequestType {
|
|
57
|
-
return
|
|
61
|
+
return (
|
|
62
|
+
type === DEPOSIT_REQUEST_TYPE ||
|
|
63
|
+
type === WITHDRAWAL_REQUEST_TYPE ||
|
|
64
|
+
type === CONSOLIDATION_REQUEST_TYPE ||
|
|
65
|
+
type === BUILDER_DEPOSIT_REQUEST_TYPE ||
|
|
66
|
+
type === BUILDER_EXIT_REQUEST_TYPE
|
|
67
|
+
);
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
export type ExecutePayloadResponse =
|
|
@@ -393,11 +393,12 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
393
393
|
blobs,
|
|
394
394
|
proofs,
|
|
395
395
|
}),
|
|
396
|
-
executionRequests: serializeExecutionRequests(
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
396
|
+
executionRequests: serializeExecutionRequests(
|
|
397
|
+
fork,
|
|
398
|
+
ForkSeq[fork] >= ForkSeq.gloas
|
|
399
|
+
? ssz.gloas.ExecutionRequests.defaultValue()
|
|
400
|
+
: ssz.electra.ExecutionRequests.defaultValue()
|
|
401
|
+
),
|
|
401
402
|
});
|
|
402
403
|
|
|
403
404
|
// IF the payload is deemed VALID and the build process has begun
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BUILDER_DEPOSIT_REQUEST_TYPE,
|
|
3
|
+
BUILDER_EXIT_REQUEST_TYPE,
|
|
2
4
|
BYTES_PER_FIELD_ELEMENT,
|
|
3
5
|
BYTES_PER_LOGS_BLOOM,
|
|
4
6
|
CELLS_PER_EXT_BLOB,
|
|
@@ -205,16 +207,27 @@ export type WithdrawalRpc = {
|
|
|
205
207
|
};
|
|
206
208
|
|
|
207
209
|
/**
|
|
208
|
-
* ExecutionRequestsRpc
|
|
209
|
-
* -
|
|
210
|
-
* - ssz'ed
|
|
211
|
-
* - ssz'ed
|
|
210
|
+
* ExecutionRequestsRpc holds at most 5 elements and no repeated type, ordered by
|
|
211
|
+
* the single-byte request type prefix:
|
|
212
|
+
* - ssz'ed DepositRequests (0x00)
|
|
213
|
+
* - ssz'ed WithdrawalRequests (0x01)
|
|
214
|
+
* - ssz'ed ConsolidationRequests (0x02)
|
|
215
|
+
* - ssz'ed BuilderDepositRequests (0x03)
|
|
216
|
+
* - ssz'ed BuilderExitRequests (0x04)
|
|
212
217
|
*/
|
|
213
|
-
export type ExecutionRequestsRpc = (
|
|
218
|
+
export type ExecutionRequestsRpc = (
|
|
219
|
+
| DepositRequestsRpc
|
|
220
|
+
| WithdrawalRequestsRpc
|
|
221
|
+
| ConsolidationRequestsRpc
|
|
222
|
+
| BuilderDepositRequestsRpc
|
|
223
|
+
| BuilderExitRequestsRpc
|
|
224
|
+
)[];
|
|
214
225
|
|
|
215
226
|
export type DepositRequestsRpc = DATA;
|
|
216
227
|
export type WithdrawalRequestsRpc = DATA;
|
|
217
228
|
export type ConsolidationRequestsRpc = DATA;
|
|
229
|
+
export type BuilderDepositRequestsRpc = DATA;
|
|
230
|
+
export type BuilderExitRequestsRpc = DATA;
|
|
218
231
|
|
|
219
232
|
export type BlobAndProofRpc = {
|
|
220
233
|
blob: DATA;
|
|
@@ -339,7 +352,7 @@ export function parseExecutionPayload(
|
|
|
339
352
|
data = response.executionPayload;
|
|
340
353
|
blobsBundle = response.blobsBundle ? parseBlobsBundle(response.blobsBundle) : undefined;
|
|
341
354
|
executionRequests = response.executionRequests
|
|
342
|
-
? deserializeExecutionRequests(response.executionRequests)
|
|
355
|
+
? deserializeExecutionRequests(fork, response.executionRequests)
|
|
343
356
|
: undefined;
|
|
344
357
|
shouldOverrideBuilder = response.shouldOverrideBuilder ?? false;
|
|
345
358
|
} else {
|
|
@@ -526,13 +539,36 @@ function deserializeConsolidationRequests(serialized: ConsolidationRequestsRpc):
|
|
|
526
539
|
return ssz.electra.ConsolidationRequests.deserialize(dataToBytes(serialized, null));
|
|
527
540
|
}
|
|
528
541
|
|
|
542
|
+
function serializeBuilderDepositRequests(
|
|
543
|
+
builderDepositRequests: gloas.BuilderDepositRequests
|
|
544
|
+
): BuilderDepositRequestsRpc {
|
|
545
|
+
const requestsBytes = ssz.gloas.BuilderDepositRequests.serialize(builderDepositRequests);
|
|
546
|
+
return bytesToData(prefixRequests(requestsBytes, BUILDER_DEPOSIT_REQUEST_TYPE));
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function deserializeBuilderDepositRequests(serialized: BuilderDepositRequestsRpc): gloas.BuilderDepositRequests {
|
|
550
|
+
return ssz.gloas.BuilderDepositRequests.deserialize(dataToBytes(serialized, null));
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function serializeBuilderExitRequests(builderExitRequests: gloas.BuilderExitRequests): BuilderExitRequestsRpc {
|
|
554
|
+
const requestsBytes = ssz.gloas.BuilderExitRequests.serialize(builderExitRequests);
|
|
555
|
+
return bytesToData(prefixRequests(requestsBytes, BUILDER_EXIT_REQUEST_TYPE));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function deserializeBuilderExitRequests(serialized: BuilderExitRequestsRpc): gloas.BuilderExitRequests {
|
|
559
|
+
return ssz.gloas.BuilderExitRequests.deserialize(dataToBytes(serialized, null));
|
|
560
|
+
}
|
|
561
|
+
|
|
529
562
|
/**
|
|
530
563
|
* This is identical to get_execution_requests_list in
|
|
531
564
|
* https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/electra/beacon-chain.md#new-get_execution_requests_list
|
|
565
|
+
*
|
|
566
|
+
* Gloas extends the list with builder deposits (0x03) and builder exits (0x04) per
|
|
567
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.11/specs/gloas/beacon-chain.md#modified-get_execution_requests_list
|
|
532
568
|
*/
|
|
533
|
-
export function serializeExecutionRequests(executionRequests: ExecutionRequests): ExecutionRequestsRpc {
|
|
569
|
+
export function serializeExecutionRequests(fork: ForkName, executionRequests: ExecutionRequests): ExecutionRequestsRpc {
|
|
534
570
|
const {deposits, withdrawals, consolidations} = executionRequests;
|
|
535
|
-
const result = [];
|
|
571
|
+
const result: ExecutionRequestsRpc = [];
|
|
536
572
|
|
|
537
573
|
if (deposits.length !== 0) {
|
|
538
574
|
result.push(serializeDepositRequests(deposits));
|
|
@@ -546,15 +582,26 @@ export function serializeExecutionRequests(executionRequests: ExecutionRequests)
|
|
|
546
582
|
result.push(serializeConsolidationRequests(consolidations));
|
|
547
583
|
}
|
|
548
584
|
|
|
585
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
586
|
+
const {builderDeposits, builderExits} = executionRequests as gloas.ExecutionRequests;
|
|
587
|
+
|
|
588
|
+
if (builderDeposits.length !== 0) {
|
|
589
|
+
result.push(serializeBuilderDepositRequests(builderDeposits));
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (builderExits.length !== 0) {
|
|
593
|
+
result.push(serializeBuilderExitRequests(builderExits));
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
549
597
|
return result;
|
|
550
598
|
}
|
|
551
599
|
|
|
552
|
-
export function deserializeExecutionRequests(serialized: ExecutionRequestsRpc): ExecutionRequests {
|
|
553
|
-
const result: ExecutionRequests =
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
};
|
|
600
|
+
export function deserializeExecutionRequests(fork: ForkName, serialized: ExecutionRequestsRpc): ExecutionRequests {
|
|
601
|
+
const result: ExecutionRequests =
|
|
602
|
+
ForkSeq[fork] >= ForkSeq.gloas
|
|
603
|
+
? {deposits: [], withdrawals: [], consolidations: [], builderDeposits: [], builderExits: []}
|
|
604
|
+
: {deposits: [], withdrawals: [], consolidations: []};
|
|
558
605
|
|
|
559
606
|
if (serialized.length === 0) {
|
|
560
607
|
return result;
|
|
@@ -601,6 +648,20 @@ export function deserializeExecutionRequests(serialized: ExecutionRequestsRpc):
|
|
|
601
648
|
result.consolidations = deserializeConsolidationRequests(requests);
|
|
602
649
|
break;
|
|
603
650
|
}
|
|
651
|
+
case BUILDER_DEPOSIT_REQUEST_TYPE: {
|
|
652
|
+
if (ForkSeq[fork] < ForkSeq.gloas) {
|
|
653
|
+
throw Error(`Builder deposit request is not supported pre-gloas fork=${fork}`);
|
|
654
|
+
}
|
|
655
|
+
(result as gloas.ExecutionRequests).builderDeposits = deserializeBuilderDepositRequests(requests);
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
658
|
+
case BUILDER_EXIT_REQUEST_TYPE: {
|
|
659
|
+
if (ForkSeq[fork] < ForkSeq.gloas) {
|
|
660
|
+
throw Error(`Builder exit request is not supported pre-gloas fork=${fork}`);
|
|
661
|
+
}
|
|
662
|
+
(result as gloas.ExecutionRequests).builderExits = deserializeBuilderExitRequests(requests);
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
604
665
|
}
|
|
605
666
|
prevRequestType = currentRequestType;
|
|
606
667
|
}
|
|
@@ -610,6 +610,11 @@ export function createLodestarMetrics(
|
|
|
610
610
|
help: "The origination source of one of the BlockInputSync triggers",
|
|
611
611
|
labelNames: ["source"],
|
|
612
612
|
}),
|
|
613
|
+
payloadSource: register.counter<{source: BlockInputSource}>({
|
|
614
|
+
name: "lodestar_payload_input_sync_source_total",
|
|
615
|
+
help: "Count of payload (execution payload envelope) sync triggers, labeled by their source",
|
|
616
|
+
labelNames: ["source"],
|
|
617
|
+
}),
|
|
613
618
|
pendingBlocks: register.gauge({
|
|
614
619
|
name: "lodestar_sync_unknown_block_pending_blocks_size",
|
|
615
620
|
help: "Current size of UnknownBlockSync pending blocks cache",
|
|
@@ -861,6 +866,12 @@ export function createLodestarMetrics(
|
|
|
861
866
|
labelNames: ["numBlobs"],
|
|
862
867
|
}),
|
|
863
868
|
|
|
869
|
+
skippedSlots: register.histogram({
|
|
870
|
+
name: "lodestar_gossip_block_skipped_slots",
|
|
871
|
+
help: "Number of skipped slots between a gossip block and its parent (blockSlot - parentSlot - 1)",
|
|
872
|
+
buckets: [0, 1, 2, 4, 8, 16, 32],
|
|
873
|
+
}),
|
|
874
|
+
|
|
864
875
|
processBlockErrors: register.gauge<{error: BlockErrorCode | "NOT_BLOCK_ERROR"}>({
|
|
865
876
|
name: "lodestar_gossip_block_process_block_errors",
|
|
866
877
|
help: "Count of errors, by error type, while processing blocks",
|
|
@@ -185,7 +185,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
185
185
|
peerIdStr,
|
|
186
186
|
});
|
|
187
187
|
try {
|
|
188
|
-
await validateGossipBlock(config, chain, signedBlock, fork);
|
|
188
|
+
const {skippedSlots} = await validateGossipBlock(config, chain, signedBlock, fork);
|
|
189
189
|
|
|
190
190
|
if (isForkPostGloas(fork)) {
|
|
191
191
|
chain.seenPayloadEnvelopeInputCache.add({
|
|
@@ -205,8 +205,15 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
205
205
|
|
|
206
206
|
metrics?.gossipBlock.gossipValidation.recvToValidation.observe(recvToValidation);
|
|
207
207
|
metrics?.gossipBlock.gossipValidation.validationTime.observe(validationTime);
|
|
208
|
+
metrics?.gossipBlock.skippedSlots.observe(skippedSlots);
|
|
208
209
|
|
|
209
|
-
logger.debug("Validated gossip block", {
|
|
210
|
+
logger.debug("Validated gossip block", {
|
|
211
|
+
...blockInputMeta,
|
|
212
|
+
...logCtx,
|
|
213
|
+
recvToValidation,
|
|
214
|
+
validationTime,
|
|
215
|
+
skippedSlots,
|
|
216
|
+
});
|
|
210
217
|
|
|
211
218
|
chain.emitter.emit(routes.events.EventType.blockGossip, {slot, block: blockRootHex});
|
|
212
219
|
|