@lodestar/beacon-node 1.43.0-dev.9fa9f08ef6 → 1.43.0-dev.a142c56215
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.js +4 -6
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -2
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +1 -1
- 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 +0 -4
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/archiveStore/interface.d.ts +4 -4
- package/lib/chain/archiveStore/interface.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
- package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts +2 -2
- package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
- package/lib/chain/archiveStore/utils/archiveBlocks.js +110 -58
- package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +6 -3
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +26 -14
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +73 -86
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts +5 -3
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +28 -10
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +14 -20
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +81 -12
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts +3 -2
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +30 -5
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +15 -4
- package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
- package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
- package/lib/chain/chain.d.ts +6 -5
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +16 -5
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +3 -3
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/errors/blockError.d.ts +8 -1
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +5 -17
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +5 -4
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +30 -10
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -2
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +39 -13
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +1 -0
- 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 +13 -1
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +19 -9
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +4 -3
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/db/repositories/executionPayloadEnvelopeArchive.js +1 -1
- package/lib/db/repositories/executionPayloadEnvelopeArchive.js.map +1 -1
- package/lib/execution/engine/http.d.ts.map +1 -1
- package/lib/execution/engine/http.js +21 -14
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -0
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +6 -0
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/types.d.ts +20 -0
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +18 -0
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +1 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +4 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +23 -2
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/network.js +1 -1
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +5 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/node/notifier.js +7 -1
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/range/batch.d.ts +12 -2
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +56 -30
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +6 -2
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +4 -3
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +17 -6
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/types.d.ts +34 -0
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +34 -0
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +24 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +649 -53
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +46 -10
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +147 -24
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +6 -2
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
- package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
- package/lib/sync/utils/pendingBlocksTree.js +0 -9
- package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +16 -3
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +17 -16
- package/src/api/impl/beacon/blocks/index.ts +6 -6
- package/src/api/impl/beacon/state/utils.ts +2 -2
- package/src/api/impl/lodestar/index.ts +1 -1
- package/src/api/impl/validator/index.ts +0 -4
- package/src/chain/archiveStore/archiveStore.ts +5 -5
- package/src/chain/archiveStore/interface.ts +4 -4
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +4 -4
- package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
- package/src/chain/blocks/importBlock.ts +4 -2
- package/src/chain/blocks/importExecutionPayload.ts +92 -107
- package/src/chain/blocks/index.ts +44 -13
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
- package/src/chain/blocks/types.ts +14 -25
- package/src/chain/blocks/utils/chainSegment.ts +106 -17
- package/src/chain/blocks/verifyBlock.ts +35 -6
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -7
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
- package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
- package/src/chain/chain.ts +33 -19
- package/src/chain/emitter.ts +3 -3
- package/src/chain/errors/blockError.ts +4 -1
- package/src/chain/errors/executionPayloadBid.ts +6 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
- package/src/chain/forkChoice/index.ts +2 -22
- package/src/chain/interface.ts +9 -3
- package/src/chain/prepareNextSlot.ts +42 -12
- package/src/chain/produceBlock/produceBlockBody.ts +43 -11
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
- package/src/chain/stateCache/persistentCheckpointsCache.ts +4 -1
- package/src/chain/validation/block.ts +1 -0
- package/src/chain/validation/executionPayloadBid.ts +14 -0
- package/src/chain/validation/executionPayloadEnvelope.ts +20 -10
- package/src/chain/validation/payloadAttestationMessage.ts +5 -3
- package/src/db/repositories/executionPayloadEnvelopeArchive.ts +1 -1
- package/src/execution/engine/http.ts +21 -14
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/mock.ts +8 -1
- package/src/execution/engine/types.ts +41 -0
- package/src/metrics/metrics/lodestar.ts +4 -0
- package/src/network/network.ts +1 -1
- package/src/network/processor/gossipHandlers.ts +7 -4
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
- package/src/node/notifier.ts +8 -1
- package/src/sync/range/batch.ts +90 -35
- package/src/sync/range/chain.ts +13 -5
- package/src/sync/range/range.ts +18 -6
- package/src/sync/types.ts +72 -0
- package/src/sync/unknownBlock.ts +810 -57
- package/src/sync/utils/downloadByRange.ts +256 -39
- package/src/sync/utils/downloadByRoot.ts +12 -2
- package/src/sync/utils/pendingBlocksTree.ts +0 -15
- package/src/util/sszBytes.ts +21 -3
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import {ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice";
|
|
2
|
-
import {ForkName, isForkPostFulu} from "@lodestar/params";
|
|
2
|
+
import {ForkName, ForkSeq, isForkPostFulu} from "@lodestar/params";
|
|
3
3
|
import {DataAvailabilityStatus, IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
|
|
4
|
-
import {IndexedAttestation, deneb} from "@lodestar/types";
|
|
4
|
+
import {IndexedAttestation, Slot, deneb} from "@lodestar/types";
|
|
5
|
+
import {getBlobKzgCommitments} from "../../util/dataColumns.js";
|
|
5
6
|
import type {BeaconChain} from "../chain.js";
|
|
6
7
|
import {BlockError, BlockErrorCode} from "../errors/index.js";
|
|
7
8
|
import {BlockProcessOpts} from "../options.js";
|
|
8
9
|
import {RegenCaller} from "../regen/index.js";
|
|
9
10
|
import {DAType, IBlockInput} from "./blockInput/index.js";
|
|
11
|
+
import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
10
12
|
import {ImportBlockOpts} from "./types.js";
|
|
11
13
|
import {DENEB_BLOWFISH_BANNER} from "./utils/blowfishBanner.js";
|
|
12
14
|
import {ELECTRA_GIRAFFE_BANNER} from "./utils/giraffeBanner.js";
|
|
@@ -16,6 +18,7 @@ import {verifyBlocksDataAvailability} from "./verifyBlocksDataAvailability.js";
|
|
|
16
18
|
import {SegmentExecStatus, verifyBlocksExecutionPayload} from "./verifyBlocksExecutionPayloads.js";
|
|
17
19
|
import {verifyBlocksSignatures} from "./verifyBlocksSignatures.js";
|
|
18
20
|
import {verifyBlocksStateTransitionOnly} from "./verifyBlocksStateTransitionOnly.js";
|
|
21
|
+
import {verifyPayloadsDataAvailability} from "./verifyPayloadsDataAvailability.js";
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Verifies 1 or more blocks are fully valid; from a linear sequence of blocks.
|
|
@@ -32,6 +35,7 @@ export async function verifyBlocksInEpoch(
|
|
|
32
35
|
this: BeaconChain,
|
|
33
36
|
parentBlock: ProtoBlock,
|
|
34
37
|
blockInputs: IBlockInput[],
|
|
38
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
35
39
|
opts: BlockProcessOpts & ImportBlockOpts
|
|
36
40
|
): Promise<{
|
|
37
41
|
postStates: IBeaconStateView[];
|
|
@@ -110,6 +114,26 @@ export async function verifyBlocksInEpoch(
|
|
|
110
114
|
});
|
|
111
115
|
}
|
|
112
116
|
|
|
117
|
+
// Pick the data-availability source by fork:
|
|
118
|
+
// - Pre-Gloas: blob/Fulu-column data lives in IBlockInput → verifyBlocksDataAvailability.
|
|
119
|
+
// - Post-Gloas: verifyPayloadsDataAvailability
|
|
120
|
+
const daAvailabilityPromise =
|
|
121
|
+
fork >= ForkSeq.gloas
|
|
122
|
+
? (async () => {
|
|
123
|
+
const payloadInputsForDa: PayloadEnvelopeInput[] = [];
|
|
124
|
+
for (const input of blockInputs) {
|
|
125
|
+
const pi = payloadEnvelopes?.get(input.slot);
|
|
126
|
+
if (pi !== undefined) payloadInputsForDa.push(pi);
|
|
127
|
+
}
|
|
128
|
+
await verifyPayloadsDataAvailability(payloadInputsForDa, abortController.signal);
|
|
129
|
+
return {
|
|
130
|
+
// post-gloas, DataAvailabilityStatus is NotRequired for forkChoice.onBlock() ProtoBlock
|
|
131
|
+
dataAvailabilityStatuses: blockInputs.map(() => DataAvailabilityStatus.NotRequired),
|
|
132
|
+
availableTime: Date.now(),
|
|
133
|
+
};
|
|
134
|
+
})()
|
|
135
|
+
: verifyBlocksDataAvailability(blockInputs, abortController.signal);
|
|
136
|
+
|
|
113
137
|
// batch all I/O operations to reduce overhead
|
|
114
138
|
const [
|
|
115
139
|
segmentExecStatus,
|
|
@@ -119,8 +143,8 @@ export async function verifyBlocksInEpoch(
|
|
|
119
143
|
] = await Promise.all([
|
|
120
144
|
verifyExecutionPayloadsPromise,
|
|
121
145
|
|
|
122
|
-
// data availability
|
|
123
|
-
|
|
146
|
+
// data availability (fork-specific; see daAvailabilityPromise above)
|
|
147
|
+
daAvailabilityPromise,
|
|
124
148
|
|
|
125
149
|
// Run state transition only
|
|
126
150
|
// TODO: Ensure it yields to allow flushing to workers and engine API
|
|
@@ -149,6 +173,9 @@ export async function verifyBlocksInEpoch(
|
|
|
149
173
|
opts
|
|
150
174
|
)
|
|
151
175
|
: Promise.resolve({verifySignaturesTime: Date.now()}),
|
|
176
|
+
|
|
177
|
+
// TODO GLOAS: can verify payload signatures in batch too
|
|
178
|
+
// maybe chain with the above verifyBlocksSignatures()
|
|
152
179
|
]);
|
|
153
180
|
|
|
154
181
|
if (opts.verifyOnly !== true) {
|
|
@@ -200,7 +227,9 @@ export async function verifyBlocksInEpoch(
|
|
|
200
227
|
blockInputs.length === 1 &&
|
|
201
228
|
// gossip blocks have seenTimestampSec
|
|
202
229
|
opts.seenTimestampSec !== undefined &&
|
|
230
|
+
// PreData (pre-deneb) and NoData (gloas) carry no blob data on the block — skip metric
|
|
203
231
|
blockInputs[0].type !== DAType.PreData &&
|
|
232
|
+
blockInputs[0].type !== DAType.NoData &&
|
|
204
233
|
executionStatuses[0] === ExecutionStatus.Valid
|
|
205
234
|
) {
|
|
206
235
|
// Find the max time when the block was actually verified
|
|
@@ -209,8 +238,8 @@ export async function verifyBlocksInEpoch(
|
|
|
209
238
|
this.metrics?.gossipBlock.receivedToFullyVerifiedTime.observe(recvTofullyVerifedTime);
|
|
210
239
|
|
|
211
240
|
const verifiedToBlobsAvailabiltyTime = Math.max(availableTime - fullyVerifiedTime, 0) / 1000;
|
|
212
|
-
const block = blockInputs[0].getBlock()
|
|
213
|
-
const numBlobs = block.
|
|
241
|
+
const block = blockInputs[0].getBlock();
|
|
242
|
+
const numBlobs = getBlobKzgCommitments(blockInputs[0].forkName, block as deneb.SignedBeaconBlock).length;
|
|
214
243
|
|
|
215
244
|
this.metrics?.gossipBlock.verifiedToBlobsAvailabiltyTime.observe({numBlobs}, verifiedToBlobsAvailabiltyTime);
|
|
216
245
|
this.logger.verbose("Verified blockInput fully with blobs availability", {
|
|
@@ -90,15 +90,24 @@ export function verifyBlocksSanityChecks(
|
|
|
90
90
|
} else {
|
|
91
91
|
// When importing a block segment, only the first NON-IGNORED block must be known to the fork-choice.
|
|
92
92
|
const parentRoot = toRootHex(block.message.parentRoot);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
parentRoot,
|
|
96
|
-
toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash)
|
|
97
|
-
)
|
|
98
|
-
: chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
|
|
99
|
-
if (!parentBlock) {
|
|
93
|
+
const parentBlockDefaultStatus = chain.forkChoice.getBlockHexDefaultStatus(parentRoot);
|
|
94
|
+
if (!parentBlockDefaultStatus) {
|
|
100
95
|
throw new BlockError(block, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot});
|
|
101
96
|
}
|
|
97
|
+
|
|
98
|
+
parentBlock = parentBlockDefaultStatus;
|
|
99
|
+
if (isGloasBeaconBlock(block.message)) {
|
|
100
|
+
const parentBlockHash = toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash);
|
|
101
|
+
const parentBlockWithPayload = chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHash);
|
|
102
|
+
if (!parentBlockWithPayload) {
|
|
103
|
+
throw new BlockError(block, {
|
|
104
|
+
code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
|
|
105
|
+
parentRoot,
|
|
106
|
+
parentBlockHash,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
parentBlock = parentBlockWithPayload;
|
|
110
|
+
}
|
|
102
111
|
// Parent is known to the fork-choice
|
|
103
112
|
parentBlockSlot = parentBlock.slot;
|
|
104
113
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
+
import {
|
|
3
|
+
type IBeaconStateViewGloas,
|
|
4
|
+
type PubkeyCache,
|
|
5
|
+
computeTimeAtSlot,
|
|
6
|
+
getExecutionPayloadEnvelopeSignatureSet,
|
|
7
|
+
} from "@lodestar/state-transition";
|
|
8
|
+
import {gloas, ssz} from "@lodestar/types";
|
|
9
|
+
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
10
|
+
import {IBlsVerifier} from "../bls/index.js";
|
|
11
|
+
|
|
12
|
+
export type VerifyExecutionPayloadEnvelopeOpts = {
|
|
13
|
+
verifyExecutionRequestsRoot?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Verify execution payload envelope fields against the post-block state.
|
|
18
|
+
*
|
|
19
|
+
* Signature verification and the execution engine call (`verify_and_notify_new_payload`) are
|
|
20
|
+
* performed outside this function, see `verifyExecutionPayloadEnvelopeSignature` and
|
|
21
|
+
* `importExecutionPayload` which run both in parallel with this check.
|
|
22
|
+
*
|
|
23
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope
|
|
24
|
+
*/
|
|
25
|
+
export function verifyExecutionPayloadEnvelope(
|
|
26
|
+
config: BeaconConfig,
|
|
27
|
+
state: IBeaconStateViewGloas,
|
|
28
|
+
envelope: gloas.ExecutionPayloadEnvelope,
|
|
29
|
+
opts?: VerifyExecutionPayloadEnvelopeOpts
|
|
30
|
+
): void {
|
|
31
|
+
const {verifyExecutionRequestsRoot = true} = opts ?? {};
|
|
32
|
+
const payload = envelope.payload;
|
|
33
|
+
|
|
34
|
+
// Verify consistency with the beacon block.
|
|
35
|
+
// Compute header root on a copy of latestBlockHeader to avoid mutating state.
|
|
36
|
+
const headerValue = {...state.latestBlockHeader};
|
|
37
|
+
if (byteArrayEquals(headerValue.stateRoot, ssz.Root.defaultValue())) {
|
|
38
|
+
headerValue.stateRoot = state.hashTreeRoot();
|
|
39
|
+
}
|
|
40
|
+
const headerRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(headerValue);
|
|
41
|
+
if (!byteArrayEquals(envelope.beaconBlockRoot, headerRoot)) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Envelope's block is not the latest block header envelope=${toRootHex(envelope.beaconBlockRoot)} latestBlockHeader=${toRootHex(headerRoot)}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Verify consistency with the committed bid
|
|
48
|
+
const bid = state.latestExecutionPayloadBid;
|
|
49
|
+
if (envelope.builderIndex !== bid.builderIndex) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Builder index mismatch between envelope and committed bid envelope=${envelope.builderIndex} bid=${bid.builderIndex}`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (!byteArrayEquals(bid.prevRandao, payload.prevRandao)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`Prev randao mismatch between bid and payload bid=${toHex(bid.prevRandao)} payload=${toHex(payload.prevRandao)}`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (Number(bid.gasLimit) !== payload.gasLimit) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${Number(bid.gasLimit)}`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (!byteArrayEquals(bid.blockHash, payload.blockHash)) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Block hash mismatch between payload and bid payload=${toRootHex(payload.blockHash)} bid=${toRootHex(bid.blockHash)}`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
// Verify execution_requests_root matches bid commitment.
|
|
70
|
+
// Can be skipped if already verified during gossip validation.
|
|
71
|
+
if (verifyExecutionRequestsRoot) {
|
|
72
|
+
const requestsRoot = ssz.electra.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
|
|
73
|
+
if (!byteArrayEquals(requestsRoot, bid.executionRequestsRoot)) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Execution requests root mismatch envelope=${toRootHex(requestsRoot)} bid=${toRootHex(bid.executionRequestsRoot)}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Verify the execution payload is valid
|
|
81
|
+
if (payload.slotNumber !== state.slot) {
|
|
82
|
+
throw new Error(`Slot mismatch between payload and state payload=${payload.slotNumber} state=${state.slot}`);
|
|
83
|
+
}
|
|
84
|
+
if (!byteArrayEquals(payload.parentHash, state.latestBlockHash)) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Parent hash mismatch between payload and state payload=${toRootHex(payload.parentHash)} state=${toRootHex(state.latestBlockHash)}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const expectedTimestamp = computeTimeAtSlot(config, state.slot, state.genesisTime);
|
|
90
|
+
if (payload.timestamp !== expectedTimestamp) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Timestamp mismatch between payload and state payload=${payload.timestamp} state=${expectedTimestamp}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Verify consistency with expected withdrawals
|
|
97
|
+
const payloadWithdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot(payload.withdrawals);
|
|
98
|
+
const expectedWithdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot(state.payloadExpectedWithdrawals);
|
|
99
|
+
if (!byteArrayEquals(payloadWithdrawalsRoot, expectedWithdrawalsRoot)) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Withdrawals mismatch between payload and expected payload=${toRootHex(payloadWithdrawalsRoot)} expected=${toRootHex(expectedWithdrawalsRoot)}`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Execution engine verification (verify_and_notify_new_payload) is done externally by the caller
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Verify the BLS signature of an execution payload envelope.
|
|
110
|
+
*
|
|
111
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope_signature
|
|
112
|
+
*/
|
|
113
|
+
export async function verifyExecutionPayloadEnvelopeSignature(
|
|
114
|
+
config: BeaconConfig,
|
|
115
|
+
state: IBeaconStateViewGloas,
|
|
116
|
+
pubkeyCache: PubkeyCache,
|
|
117
|
+
signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
|
|
118
|
+
proposerIndex: number,
|
|
119
|
+
bls: IBlsVerifier
|
|
120
|
+
): Promise<boolean> {
|
|
121
|
+
const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
|
|
122
|
+
config,
|
|
123
|
+
pubkeyCache,
|
|
124
|
+
state,
|
|
125
|
+
signedEnvelope,
|
|
126
|
+
proposerIndex
|
|
127
|
+
);
|
|
128
|
+
return bls.verifySignatureSets([signatureSet]);
|
|
129
|
+
}
|
|
@@ -5,7 +5,7 @@ import {writeDataColumnsToDb} from "./writeBlockInputToDb.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Persists payload envelope data to DB. This operation must be eventually completed if a payload is imported.
|
|
7
7
|
*
|
|
8
|
-
* TODO GLOAS: Persist envelope metadata (
|
|
8
|
+
* TODO GLOAS: Persist envelope metadata (executionRequests, builderIndex, etc.) without the full
|
|
9
9
|
* execution payload body — only keep the blockHash reference. The EL already stores the payload.
|
|
10
10
|
* See https://github.com/ChainSafe/lodestar/issues/5671
|
|
11
11
|
*/
|
|
@@ -33,23 +33,14 @@ export async function persistPayloadEnvelopeInput(
|
|
|
33
33
|
this: BeaconChain,
|
|
34
34
|
payloadInput: PayloadEnvelopeInput
|
|
35
35
|
): Promise<void> {
|
|
36
|
-
await writePayloadEnvelopeInputToDb
|
|
37
|
-
.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"Error persisting payload envelope in hot db",
|
|
41
|
-
{
|
|
42
|
-
slot: payloadInput.slot,
|
|
43
|
-
root: payloadInput.blockRootHex,
|
|
44
|
-
},
|
|
45
|
-
e
|
|
46
|
-
);
|
|
47
|
-
})
|
|
48
|
-
.finally(() => {
|
|
49
|
-
this.seenPayloadEnvelopeInputCache.prune(payloadInput.blockRootHex);
|
|
50
|
-
this.logger.debug("Pruned payload envelope input", {
|
|
36
|
+
await writePayloadEnvelopeInputToDb.call(this, payloadInput).catch((e) => {
|
|
37
|
+
this.logger.error(
|
|
38
|
+
"Error persisting payload envelope in hot db",
|
|
39
|
+
{
|
|
51
40
|
slot: payloadInput.slot,
|
|
52
41
|
root: payloadInput.blockRootHex,
|
|
53
|
-
}
|
|
54
|
-
|
|
42
|
+
},
|
|
43
|
+
e
|
|
44
|
+
);
|
|
45
|
+
});
|
|
55
46
|
}
|
package/src/chain/chain.ts
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import {PrivateKey} from "@libp2p/interface";
|
|
3
3
|
import {Type} from "@chainsafe/ssz";
|
|
4
4
|
import {BeaconConfig} from "@lodestar/config";
|
|
5
|
-
import {
|
|
5
|
+
import {CheckpointWithHex, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
|
|
6
6
|
import {LoggerNode} from "@lodestar/logger/node";
|
|
7
7
|
import {
|
|
8
8
|
EFFECTIVE_BALANCE_INCREMENT,
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
ValidatorIndex,
|
|
40
40
|
Wei,
|
|
41
41
|
deneb,
|
|
42
|
+
electra,
|
|
42
43
|
gloas,
|
|
43
44
|
isBlindedBeaconBlock,
|
|
44
45
|
phase0,
|
|
@@ -680,7 +681,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
680
681
|
}
|
|
681
682
|
|
|
682
683
|
getStateByCheckpoint(
|
|
683
|
-
checkpoint:
|
|
684
|
+
checkpoint: CheckpointWithHex
|
|
684
685
|
): {state: IBeaconStateView; executionOptimistic: boolean; finalized: boolean} | null {
|
|
685
686
|
// finalized or justified checkpoint states maynot be available with PersistentCheckpointStateCache, use getCheckpointStateOrBytes() api to get Uint8Array
|
|
686
687
|
const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
|
|
@@ -701,7 +702,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
701
702
|
}
|
|
702
703
|
|
|
703
704
|
async getStateOrBytesByCheckpoint(
|
|
704
|
-
checkpoint:
|
|
705
|
+
checkpoint: CheckpointWithHex
|
|
705
706
|
): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null> {
|
|
706
707
|
const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
|
|
707
708
|
const cachedStateCtx = await this.regen.getCheckpointStateOrBytes(checkpointHex);
|
|
@@ -886,6 +887,21 @@ export class BeaconChain implements IBeaconChain {
|
|
|
886
887
|
);
|
|
887
888
|
}
|
|
888
889
|
|
|
890
|
+
async getParentExecutionRequests(
|
|
891
|
+
parentBlockSlot: Slot,
|
|
892
|
+
parentBlockRootHex: RootHex
|
|
893
|
+
): Promise<electra.ExecutionRequests> {
|
|
894
|
+
// at the fork boundary, parent is pre-gloas
|
|
895
|
+
if (!isForkPostGloas(this.config.getForkName(parentBlockSlot))) {
|
|
896
|
+
return ssz.electra.ExecutionRequests.defaultValue();
|
|
897
|
+
}
|
|
898
|
+
const envelope = await this.getExecutionPayloadEnvelope(parentBlockSlot, parentBlockRootHex);
|
|
899
|
+
if (envelope === null) {
|
|
900
|
+
throw Error(`Parent execution payload envelope not found slot=${parentBlockSlot}, root=${parentBlockRootHex}`);
|
|
901
|
+
}
|
|
902
|
+
return envelope.message.executionRequests;
|
|
903
|
+
}
|
|
904
|
+
|
|
889
905
|
async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecar[]> {
|
|
890
906
|
const fork = this.config.getForkName(blockSlot);
|
|
891
907
|
|
|
@@ -1082,11 +1098,15 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1082
1098
|
}
|
|
1083
1099
|
|
|
1084
1100
|
async processBlock(block: IBlockInput, opts?: ImportBlockOpts): Promise<void> {
|
|
1085
|
-
return this.blockProcessor.processBlocksJob([block], opts);
|
|
1101
|
+
return this.blockProcessor.processBlocksJob([block], null, opts);
|
|
1086
1102
|
}
|
|
1087
1103
|
|
|
1088
|
-
async processChainSegment(
|
|
1089
|
-
|
|
1104
|
+
async processChainSegment(
|
|
1105
|
+
blocks: IBlockInput[],
|
|
1106
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
1107
|
+
opts?: ImportBlockOpts
|
|
1108
|
+
): Promise<void> {
|
|
1109
|
+
await this.blockProcessor.processBlocksJob(blocks, payloadEnvelopes, opts);
|
|
1090
1110
|
}
|
|
1091
1111
|
|
|
1092
1112
|
async processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void> {
|
|
@@ -1277,7 +1297,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1277
1297
|
* @param blockState state that declares justified checkpoint `checkpoint`
|
|
1278
1298
|
*/
|
|
1279
1299
|
private justifiedBalancesGetter(
|
|
1280
|
-
checkpoint:
|
|
1300
|
+
checkpoint: CheckpointWithHex,
|
|
1281
1301
|
blockState: IBeaconStateView
|
|
1282
1302
|
): EffectiveBalanceIncrements {
|
|
1283
1303
|
this.metrics?.balancesCache.requests.inc();
|
|
@@ -1316,7 +1336,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1316
1336
|
* @param blockState state that declares justified checkpoint `checkpoint`
|
|
1317
1337
|
*/
|
|
1318
1338
|
private closestJustifiedBalancesStateToCheckpoint(
|
|
1319
|
-
checkpoint:
|
|
1339
|
+
checkpoint: CheckpointWithHex,
|
|
1320
1340
|
blockState: IBeaconStateView
|
|
1321
1341
|
): {state: IBeaconStateView; stateId: string; shouldWarn: boolean} {
|
|
1322
1342
|
const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
|
|
@@ -1331,10 +1351,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1331
1351
|
}
|
|
1332
1352
|
|
|
1333
1353
|
// Find a state in the same branch of checkpoint at same epoch. Balances should exactly the same
|
|
1334
|
-
for (const descendantBlock of this.forkChoice.
|
|
1335
|
-
checkpoint.rootHex,
|
|
1336
|
-
checkpoint.payloadStatus
|
|
1337
|
-
)) {
|
|
1354
|
+
for (const descendantBlock of this.forkChoice.forwardIterateDescendantsDefaultStatus(checkpoint.rootHex)) {
|
|
1338
1355
|
if (computeEpochAtSlot(descendantBlock.slot) === checkpoint.epoch) {
|
|
1339
1356
|
const descendantBlockState = this.regen.getStateSync(descendantBlock.stateRoot);
|
|
1340
1357
|
if (descendantBlockState) {
|
|
@@ -1350,10 +1367,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1350
1367
|
|
|
1351
1368
|
// Find a state in the same branch of checkpoint at a latter epoch. Balances are not the same, but should be close
|
|
1352
1369
|
// Note: must call .forwardIterateDescendants() again since nodes are not sorted
|
|
1353
|
-
for (const descendantBlock of this.forkChoice.
|
|
1354
|
-
checkpoint.rootHex,
|
|
1355
|
-
checkpoint.payloadStatus
|
|
1356
|
-
)) {
|
|
1370
|
+
for (const descendantBlock of this.forkChoice.forwardIterateDescendantsDefaultStatus(checkpoint.rootHex)) {
|
|
1357
1371
|
if (computeEpochAtSlot(descendantBlock.slot) > checkpoint.epoch) {
|
|
1358
1372
|
const descendantBlockState = this.regen.getStateSync(descendantBlock.stateRoot);
|
|
1359
1373
|
if (descendantBlockState) {
|
|
@@ -1457,7 +1471,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1457
1471
|
this.seenContributionAndProof.prune(head.slot);
|
|
1458
1472
|
}
|
|
1459
1473
|
|
|
1460
|
-
private onForkChoiceJustified(this: BeaconChain, cp:
|
|
1474
|
+
private onForkChoiceJustified(this: BeaconChain, cp: CheckpointWithHex): void {
|
|
1461
1475
|
this.logger.verbose("Fork choice justified", {epoch: cp.epoch, root: cp.rootHex});
|
|
1462
1476
|
}
|
|
1463
1477
|
|
|
@@ -1468,7 +1482,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1468
1482
|
});
|
|
1469
1483
|
}
|
|
1470
1484
|
|
|
1471
|
-
private async onForkChoiceFinalized(this: BeaconChain, cp:
|
|
1485
|
+
private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
|
|
1472
1486
|
this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
|
|
1473
1487
|
const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
|
|
1474
1488
|
this.seenBlockProposers.prune(finalizedSlot);
|
|
@@ -1509,7 +1523,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1509
1523
|
}
|
|
1510
1524
|
}
|
|
1511
1525
|
|
|
1512
|
-
private async updateValidatorsCustodyRequirement(finalizedCheckpoint:
|
|
1526
|
+
private async updateValidatorsCustodyRequirement(finalizedCheckpoint: CheckpointWithHex): Promise<void> {
|
|
1513
1527
|
if (this.custodyConfig.targetCustodyGroupCount === this.config.NUMBER_OF_CUSTODY_GROUPS) {
|
|
1514
1528
|
// Custody requirements can only be increased, we can disable dynamic custody updates
|
|
1515
1529
|
// if the node already maintains custody of all custody groups in case it is configured
|
package/src/chain/emitter.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {EventEmitter} from "node:events";
|
|
2
2
|
import {StrictEventEmitter} from "strict-event-emitter-types";
|
|
3
3
|
import {routes} from "@lodestar/api";
|
|
4
|
-
import {
|
|
4
|
+
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
5
5
|
import {IBeaconStateView} from "@lodestar/state-transition";
|
|
6
6
|
import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
|
|
7
7
|
import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
|
|
@@ -110,8 +110,8 @@ export type ChainEventData = {
|
|
|
110
110
|
export type IChainEvents = ApiEvents & {
|
|
111
111
|
[ChainEvent.checkpoint]: (checkpoint: phase0.Checkpoint, state: IBeaconStateView) => void;
|
|
112
112
|
|
|
113
|
-
[ChainEvent.forkChoiceJustified]: (checkpoint:
|
|
114
|
-
[ChainEvent.forkChoiceFinalized]: (checkpoint:
|
|
113
|
+
[ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithHex) => void;
|
|
114
|
+
[ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithHex) => void;
|
|
115
115
|
|
|
116
116
|
[ChainEvent.updateTargetCustodyGroupCount]: (targetGroupCount: number) => void;
|
|
117
117
|
|
|
@@ -74,6 +74,8 @@ export enum BlockErrorCode {
|
|
|
74
74
|
PARENT_EXECUTION_INVALID = "BLOCK_ERROR_PARENT_EXECUTION_INVALID",
|
|
75
75
|
/** The block's parent execution payload (defined by bid.parent_block_hash) has not been seen */
|
|
76
76
|
PARENT_PAYLOAD_UNKNOWN = "BLOCK_ERROR_PARENT_PAYLOAD_UNKNOWN",
|
|
77
|
+
/** An execution payload envelope in the chain segment references a block root that does not match its slot's block */
|
|
78
|
+
ENVELOPE_BLOCK_ROOT_MISMATCH = "BLOCK_ERROR_ENVELOPE_BLOCK_ROOT_MISMATCH",
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
type ExecutionErrorStatus = Exclude<
|
|
@@ -107,6 +109,7 @@ export type BlockErrorType =
|
|
|
107
109
|
| {code: BlockErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
|
|
108
110
|
| {code: BlockErrorCode.NON_LINEAR_PARENT_ROOTS}
|
|
109
111
|
| {code: BlockErrorCode.NON_LINEAR_SLOTS}
|
|
112
|
+
| {code: BlockErrorCode.ENVELOPE_BLOCK_ROOT_MISMATCH; envelopeBlockRoot: RootHex; blockRoot: RootHex}
|
|
110
113
|
| {code: BlockErrorCode.PER_BLOCK_PROCESSING_ERROR; error: Error}
|
|
111
114
|
| {code: BlockErrorCode.BEACON_CHAIN_ERROR; error: Error}
|
|
112
115
|
| {code: BlockErrorCode.KNOWN_BAD_BLOCK}
|
|
@@ -120,7 +123,7 @@ export type BlockErrorType =
|
|
|
120
123
|
| {code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS; blobKzgCommitmentsLen: number; commitmentLimit: number}
|
|
121
124
|
| {code: BlockErrorCode.BID_PARENT_ROOT_MISMATCH; bidParentRoot: RootHex; blockParentRoot: RootHex}
|
|
122
125
|
| {code: BlockErrorCode.PARENT_EXECUTION_INVALID; parentRoot: RootHex}
|
|
123
|
-
| {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentBlockHash: RootHex};
|
|
126
|
+
| {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentRoot: RootHex; parentBlockHash: RootHex};
|
|
124
127
|
|
|
125
128
|
export class BlockGossipError extends GossipActionError<BlockErrorType> {}
|
|
126
129
|
|
|
@@ -7,6 +7,7 @@ export enum ExecutionPayloadBidErrorCode {
|
|
|
7
7
|
BID_ALREADY_KNOWN = "EXECUTION_PAYLOAD_BID_ERROR_BID_ALREADY_KNOWN",
|
|
8
8
|
BID_TOO_LOW = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_LOW",
|
|
9
9
|
BID_TOO_HIGH = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_HIGH",
|
|
10
|
+
TOO_MANY_KZG_COMMITMENTS = "EXECUTION_PAYLOAD_BID_ERROR_TOO_MANY_KZG_COMMITMENTS",
|
|
10
11
|
UNKNOWN_BLOCK_ROOT = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_BLOCK_ROOT",
|
|
11
12
|
INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
|
|
12
13
|
INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
|
|
@@ -28,6 +29,11 @@ export type ExecutionPayloadBidErrorType =
|
|
|
28
29
|
}
|
|
29
30
|
| {code: ExecutionPayloadBidErrorCode.BID_TOO_LOW; bidValue: number; currentHighestBid: number}
|
|
30
31
|
| {code: ExecutionPayloadBidErrorCode.BID_TOO_HIGH; bidValue: number; builderBalance: number}
|
|
32
|
+
| {
|
|
33
|
+
code: ExecutionPayloadBidErrorCode.TOO_MANY_KZG_COMMITMENTS;
|
|
34
|
+
blobKzgCommitmentsLen: number;
|
|
35
|
+
commitmentLimit: number;
|
|
36
|
+
}
|
|
31
37
|
| {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
|
|
32
38
|
| {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
|
|
33
39
|
| {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot};
|
|
@@ -11,6 +11,7 @@ export enum ExecutionPayloadEnvelopeErrorCode {
|
|
|
11
11
|
SLOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_SLOT_MISMATCH",
|
|
12
12
|
BUILDER_INDEX_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BUILDER_INDEX_MISMATCH",
|
|
13
13
|
BLOCK_HASH_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_HASH_MISMATCH",
|
|
14
|
+
EXECUTION_REQUESTS_ROOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_EXECUTION_REQUESTS_ROOT_MISMATCH",
|
|
14
15
|
INVALID_SIGNATURE = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_SIGNATURE",
|
|
15
16
|
PAYLOAD_ENVELOPE_INPUT_MISSING = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_PAYLOAD_ENVELOPE_INPUT_MISSING",
|
|
16
17
|
}
|
|
@@ -36,6 +37,11 @@ export type ExecutionPayloadEnvelopeErrorType =
|
|
|
36
37
|
envelopeBlockHash: RootHex;
|
|
37
38
|
bidBlockHash: RootHex | null;
|
|
38
39
|
}
|
|
40
|
+
| {
|
|
41
|
+
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH;
|
|
42
|
+
envelopeRequestsRoot: RootHex;
|
|
43
|
+
bidRequestsRoot: RootHex;
|
|
44
|
+
}
|
|
39
45
|
| {code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE}
|
|
40
46
|
| {code: ExecutionPayloadEnvelopeErrorCode.PAYLOAD_ENVELOPE_INPUT_MISSING; blockRoot: RootHex};
|
|
41
47
|
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
ProtoArray,
|
|
9
9
|
ProtoBlock,
|
|
10
10
|
ForkChoiceOpts as RawForkChoiceOpts,
|
|
11
|
-
getCheckpointPayloadStatus,
|
|
12
11
|
} from "@lodestar/fork-choice";
|
|
13
12
|
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
14
13
|
import {
|
|
@@ -104,16 +103,6 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
104
103
|
|
|
105
104
|
const isForkPostGloas = computeEpochAtSlot(state.slot) >= config.GLOAS_FORK_EPOCH;
|
|
106
105
|
|
|
107
|
-
// Determine justified checkpoint payload status
|
|
108
|
-
const justifiedPayloadStatus = isForkPostGloas
|
|
109
|
-
? PayloadStatus.PENDING
|
|
110
|
-
: getCheckpointPayloadStatus(config, state, justifiedCheckpoint.epoch);
|
|
111
|
-
|
|
112
|
-
// Determine finalized checkpoint payload status
|
|
113
|
-
const finalizedPayloadStatus = isForkPostGloas
|
|
114
|
-
? PayloadStatus.PENDING
|
|
115
|
-
: getCheckpointPayloadStatus(config, state, finalizedCheckpoint.epoch);
|
|
116
|
-
|
|
117
106
|
return new forkchoiceConstructor(
|
|
118
107
|
config,
|
|
119
108
|
|
|
@@ -123,8 +112,6 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
123
112
|
finalizedCheckpoint,
|
|
124
113
|
justifiedBalances,
|
|
125
114
|
justifiedBalancesGetter,
|
|
126
|
-
justifiedPayloadStatus,
|
|
127
|
-
finalizedPayloadStatus,
|
|
128
115
|
{
|
|
129
116
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
130
117
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
@@ -161,7 +148,7 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
161
148
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
162
149
|
|
|
163
150
|
dataAvailabilityStatus: DataAvailabilityStatus.PreData,
|
|
164
|
-
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
151
|
+
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
165
152
|
parentBlockHash: isStatePostGloas(state) ? toRootHex(state.latestBlockHash) : null,
|
|
166
153
|
},
|
|
167
154
|
currentSlot
|
|
@@ -208,19 +195,12 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
208
195
|
|
|
209
196
|
const isForkPostGloas = computeEpochAtSlot(unfinalizedState.slot) >= config.GLOAS_FORK_EPOCH;
|
|
210
197
|
|
|
211
|
-
// For unfinalized state, use getCheckpointPayloadStatus to determine the correct status.
|
|
212
|
-
// It checks state.execution_payload_availability to determine EMPTY vs FULL.
|
|
213
|
-
const justifiedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, justifiedCheckpoint.epoch);
|
|
214
|
-
const finalizedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, finalizedCheckpoint.epoch);
|
|
215
|
-
|
|
216
198
|
const store = new ForkChoiceStore(
|
|
217
199
|
currentSlot,
|
|
218
200
|
justifiedCheckpoint,
|
|
219
201
|
finalizedCheckpoint,
|
|
220
202
|
justifiedBalances,
|
|
221
203
|
justifiedBalancesGetter,
|
|
222
|
-
justifiedPayloadStatus,
|
|
223
|
-
finalizedPayloadStatus,
|
|
224
204
|
{
|
|
225
205
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
226
206
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
@@ -260,7 +240,7 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
260
240
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
261
241
|
|
|
262
242
|
dataAvailabilityStatus: DataAvailabilityStatus.PreData,
|
|
263
|
-
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
243
|
+
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
264
244
|
parentBlockHash: isStatePostGloas(unfinalizedState) ? toRootHex(unfinalizedState.latestBlockHash) : null,
|
|
265
245
|
};
|
|
266
246
|
|
package/src/chain/interface.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Type} from "@chainsafe/ssz";
|
|
2
2
|
import {BeaconConfig} from "@lodestar/config";
|
|
3
|
-
import {CheckpointWithHex,
|
|
3
|
+
import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
4
4
|
import {EpochShuffling, IBeaconStateView, PubkeyCache} from "@lodestar/state-transition";
|
|
5
5
|
import {
|
|
6
6
|
BeaconBlock,
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
altair,
|
|
19
19
|
capella,
|
|
20
20
|
deneb,
|
|
21
|
+
electra,
|
|
21
22
|
gloas,
|
|
22
23
|
phase0,
|
|
23
24
|
rewards,
|
|
@@ -195,7 +196,7 @@ export interface IBeaconChain {
|
|
|
195
196
|
): {state: IBeaconStateView; executionOptimistic: boolean; finalized: boolean} | null;
|
|
196
197
|
/** Return state bytes by checkpoint */
|
|
197
198
|
getStateOrBytesByCheckpoint(
|
|
198
|
-
checkpoint:
|
|
199
|
+
checkpoint: CheckpointWithHex
|
|
199
200
|
): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null>;
|
|
200
201
|
|
|
201
202
|
/**
|
|
@@ -231,6 +232,7 @@ export interface IBeaconChain {
|
|
|
231
232
|
blockSlot: Slot,
|
|
232
233
|
blockRootHex: string
|
|
233
234
|
): Promise<gloas.SignedExecutionPayloadEnvelope | null>;
|
|
235
|
+
getParentExecutionRequests(parentBlockSlot: Slot, parentBlockRootHex: RootHex): Promise<electra.ExecutionRequests>;
|
|
234
236
|
|
|
235
237
|
produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
|
|
236
238
|
produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
|
|
@@ -248,7 +250,11 @@ export interface IBeaconChain {
|
|
|
248
250
|
/** Process a block until complete */
|
|
249
251
|
processBlock(block: IBlockInput, opts?: ImportBlockOpts): Promise<void>;
|
|
250
252
|
/** Process a chain of blocks until complete */
|
|
251
|
-
processChainSegment(
|
|
253
|
+
processChainSegment(
|
|
254
|
+
blocks: IBlockInput[],
|
|
255
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
256
|
+
opts?: ImportBlockOpts
|
|
257
|
+
): Promise<void>;
|
|
252
258
|
|
|
253
259
|
/** Process execution payload envelope: verify, import to fork choice, and persist to DB */
|
|
254
260
|
processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void>;
|