@lodestar/beacon-node 1.42.0 → 1.43.0-dev.2870b59b6a
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 +20 -0
- 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 +4 -0
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +13 -10
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/lodestar/attesterSlashing.d.ts +8 -0
- package/lib/api/impl/lodestar/attesterSlashing.d.ts.map +1 -0
- package/lib/api/impl/lodestar/attesterSlashing.js +29 -0
- package/lib/api/impl/lodestar/attesterSlashing.js.map +1 -0
- package/lib/api/impl/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +39 -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 +9 -3
- 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 +10 -8
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +14 -5
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.js +1 -1
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +3 -3
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +3 -2
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSignatures.js +4 -2
- package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
- package/lib/chain/chain.d.ts +2 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +25 -15
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/attestationError.d.ts +8 -1
- package/lib/chain/errors/attestationError.d.ts.map +1 -1
- package/lib/chain/errors/attestationError.js +4 -0
- package/lib/chain/errors/attestationError.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +11 -1
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +4 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +10 -8
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -1
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts +2 -2
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +7 -0
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +5 -2
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.d.ts +2 -2
- package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.js +2 -2
- package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +7 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts +3 -3
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +8 -8
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +5 -5
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +23 -4
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +0 -1
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/queued.d.ts +2 -3
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +7 -32
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +7 -26
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/stateCache/datastore/db.d.ts +5 -4
- package/lib/chain/stateCache/datastore/db.d.ts.map +1 -1
- package/lib/chain/stateCache/datastore/db.js +10 -32
- package/lib/chain/stateCache/datastore/db.js.map +1 -1
- package/lib/chain/stateCache/datastore/file.d.ts +1 -1
- package/lib/chain/stateCache/datastore/file.d.ts.map +1 -1
- package/lib/chain/stateCache/datastore/file.js +5 -5
- package/lib/chain/stateCache/datastore/file.js.map +1 -1
- package/lib/chain/stateCache/datastore/types.d.ts +1 -1
- package/lib/chain/stateCache/datastore/types.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +1 -7
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +0 -8
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +19 -30
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +118 -209
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +12 -13
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.js.map +1 -1
- package/lib/chain/validation/aggregateAndProof.js +12 -0
- package/lib/chain/validation/aggregateAndProof.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +12 -0
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +27 -5
- 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 +7 -4
- 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 +7 -2
- 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 -1
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/syncCommittee.d.ts.map +1 -1
- package/lib/chain/validation/syncCommittee.js +4 -0
- package/lib/chain/validation/syncCommittee.js.map +1 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -1
- package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +3 -3
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +2 -729
- 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 +4 -0
- 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 +2 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.js +2 -0
- package/lib/network/reqresp/handlers/beaconBlocksByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts +2 -2
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +7 -3
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +6 -0
- package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts +2 -2
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +7 -3
- 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 +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +3 -8
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +4 -1
- package/lib/node/nodejs.js.map +1 -1
- package/lib/node/notifier.d.ts.map +1 -1
- package/lib/node/notifier.js +2 -2
- package/lib/node/notifier.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +29 -0
- package/src/api/impl/beacon/pool/index.ts +4 -0
- package/src/api/impl/beacon/state/index.ts +15 -15
- package/src/api/impl/lodestar/attesterSlashing.ts +43 -0
- package/src/api/impl/lodestar/index.ts +51 -1
- package/src/api/impl/validator/index.ts +9 -2
- package/src/chain/blocks/importBlock.ts +15 -11
- package/src/chain/blocks/importExecutionPayload.ts +15 -5
- package/src/chain/blocks/index.ts +1 -1
- package/src/chain/blocks/types.ts +3 -3
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +2 -1
- package/src/chain/blocks/verifyBlocksSignatures.ts +9 -2
- package/src/chain/chain.ts +33 -23
- package/src/chain/errors/attestationError.ts +6 -1
- package/src/chain/errors/blockError.ts +7 -1
- package/src/chain/forkChoice/index.ts +11 -8
- package/src/chain/interface.ts +5 -0
- package/src/chain/lightClient/index.ts +15 -3
- package/src/chain/opPools/aggregatedAttestationPool.ts +6 -1
- package/src/chain/opPools/executionPayloadBidPool.ts +3 -3
- package/src/chain/prepareNextSlot.ts +8 -0
- package/src/chain/produceBlock/computeNewStateRoot.ts +11 -10
- package/src/chain/produceBlock/produceBlockBody.ts +40 -10
- package/src/chain/regen/interface.ts +0 -1
- package/src/chain/regen/queued.ts +8 -36
- package/src/chain/regen/regen.ts +8 -28
- package/src/chain/stateCache/datastore/db.ts +10 -33
- package/src/chain/stateCache/datastore/file.ts +5 -6
- package/src/chain/stateCache/datastore/types.ts +2 -3
- package/src/chain/stateCache/fifoBlockStateCache.ts +1 -10
- package/src/chain/stateCache/persistentCheckpointsCache.ts +142 -240
- package/src/chain/stateCache/types.ts +10 -13
- package/src/chain/validation/aggregateAndProof.ts +13 -0
- package/src/chain/validation/attestation.ts +13 -0
- package/src/chain/validation/block.ts +30 -7
- package/src/chain/validation/executionPayloadBid.ts +7 -3
- package/src/chain/validation/executionPayloadEnvelope.ts +11 -2
- package/src/chain/validation/payloadAttestationMessage.ts +4 -0
- package/src/chain/validation/syncCommittee.ts +5 -1
- package/src/chain/validation/syncCommitteeContributionAndProof.ts +5 -1
- package/src/chain/validatorMonitor.ts +3 -2
- package/src/network/processor/gossipHandlers.ts +5 -0
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +3 -1
- package/src/network/reqresp/handlers/beaconBlocksByRoot.ts +3 -0
- package/src/network/reqresp/handlers/blobSidecarsByRange.ts +15 -3
- package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +11 -0
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +19 -3
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +3 -1
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +3 -12
- package/src/node/nodejs.ts +5 -2
- package/src/node/notifier.ts +7 -2
|
@@ -103,7 +103,7 @@ type FullyVerifiedBlockBase = {
|
|
|
103
103
|
/**
|
|
104
104
|
* A wrapper around a `SignedBeaconBlock` that indicates that this block is fully verified and ready to import.
|
|
105
105
|
*
|
|
106
|
-
* Discriminated union on `
|
|
106
|
+
* Discriminated union on `postPayloadState`:
|
|
107
107
|
* - `null` → block has no pre-verified envelope; `executionStatus` is any `BlockExecutionStatus`
|
|
108
108
|
* - non-null → envelope was pre-verified during state transition; `executionStatus` is narrowed to
|
|
109
109
|
* `Valid | Syncing` (matching what `forkChoice.onExecutionPayload` expects)
|
|
@@ -111,12 +111,12 @@ type FullyVerifiedBlockBase = {
|
|
|
111
111
|
export type FullyVerifiedBlock = FullyVerifiedBlockBase &
|
|
112
112
|
(
|
|
113
113
|
| {
|
|
114
|
-
|
|
114
|
+
postPayloadState: null;
|
|
115
115
|
/** If the execution payload couldn't be verified because of EL syncing status, used in optimistic sync or for merge block */
|
|
116
116
|
executionStatus: BlockExecutionStatus;
|
|
117
117
|
}
|
|
118
118
|
| {
|
|
119
|
-
|
|
119
|
+
postPayloadState: IBeaconStateView;
|
|
120
120
|
executionStatus: PayloadExecutionStatus;
|
|
121
121
|
}
|
|
122
122
|
);
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ProtoBlock,
|
|
9
9
|
} from "@lodestar/fork-choice";
|
|
10
10
|
import {ForkSeq} from "@lodestar/params";
|
|
11
|
-
import {IBeaconStateView, isExecutionBlockBodyType} from "@lodestar/state-transition";
|
|
11
|
+
import {IBeaconStateView, isExecutionBlockBodyType, isStatePostBellatrix} from "@lodestar/state-transition";
|
|
12
12
|
import {bellatrix, electra} from "@lodestar/types";
|
|
13
13
|
import {ErrorAborted, Logger, toRootHex} from "@lodestar/utils";
|
|
14
14
|
import {ExecutionPayloadStatus, IExecutionEngine} from "../../execution/engine/interface.js";
|
|
@@ -152,6 +152,7 @@ export async function verifyBlockExecutionPayload(
|
|
|
152
152
|
|
|
153
153
|
/** Not null if execution is enabled */
|
|
154
154
|
const executionPayloadEnabled =
|
|
155
|
+
isStatePostBellatrix(preState0) &&
|
|
155
156
|
preState0.isExecutionStateType &&
|
|
156
157
|
isExecutionBlockBodyType(block.message.body) &&
|
|
157
158
|
preState0.isExecutionEnabled(block.message)
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
IBeaconStateView,
|
|
4
|
+
SyncCommitteeCacheEmpty,
|
|
5
|
+
getBlockSignatureSets,
|
|
6
|
+
isStatePostAltair,
|
|
7
|
+
} from "@lodestar/state-transition";
|
|
3
8
|
import {IndexedAttestation, SignedBeaconBlock} from "@lodestar/types";
|
|
4
9
|
import {Logger} from "@lodestar/utils";
|
|
5
10
|
import {Metrics} from "../../metrics/metrics.js";
|
|
@@ -27,7 +32,9 @@ export async function verifyBlocksSignatures(
|
|
|
27
32
|
): Promise<{verifySignaturesTime: number}> {
|
|
28
33
|
const isValidPromises: Promise<boolean>[] = [];
|
|
29
34
|
const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000);
|
|
30
|
-
const currentSyncCommitteeIndexed = preState0
|
|
35
|
+
const currentSyncCommitteeIndexed = isStatePostAltair(preState0)
|
|
36
|
+
? preState0.currentSyncCommitteeIndexed
|
|
37
|
+
: new SyncCommitteeCacheEmpty();
|
|
31
38
|
|
|
32
39
|
// Verifies signatures after running state transition, so all SyncCommittee signed roots are known at this point.
|
|
33
40
|
// We must ensure block.slot <= state.slot before running getAllBlockSignatureSets().
|
package/src/chain/chain.ts
CHANGED
|
@@ -2,14 +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 {
|
|
6
|
-
CheckpointWithPayloadStatus,
|
|
7
|
-
IForkChoice,
|
|
8
|
-
PayloadStatus,
|
|
9
|
-
ProtoBlock,
|
|
10
|
-
UpdateHeadOpt,
|
|
11
|
-
getCheckpointPayloadStatus,
|
|
12
|
-
} from "@lodestar/fork-choice";
|
|
5
|
+
import {CheckpointWithPayloadStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
|
|
13
6
|
import {LoggerNode} from "@lodestar/logger/node";
|
|
14
7
|
import {
|
|
15
8
|
BUILDER_INDEX_SELF_BUILD,
|
|
@@ -18,7 +11,6 @@ import {
|
|
|
18
11
|
type ForkPostGloas,
|
|
19
12
|
GENESIS_SLOT,
|
|
20
13
|
SLOTS_PER_EPOCH,
|
|
21
|
-
isForkPostElectra,
|
|
22
14
|
isForkPostGloas,
|
|
23
15
|
} from "@lodestar/params";
|
|
24
16
|
import {
|
|
@@ -30,6 +22,9 @@ import {
|
|
|
30
22
|
computeEpochAtSlot,
|
|
31
23
|
computeStartSlotAtEpoch,
|
|
32
24
|
getEffectiveBalancesFromStateBytes,
|
|
25
|
+
isStatePostAltair,
|
|
26
|
+
isStatePostElectra,
|
|
27
|
+
isStatePostGloas,
|
|
33
28
|
} from "@lodestar/state-transition";
|
|
34
29
|
import {
|
|
35
30
|
BeaconBlock,
|
|
@@ -98,7 +93,7 @@ import {
|
|
|
98
93
|
} from "./opPools/index.js";
|
|
99
94
|
import {IChainOptions} from "./options.js";
|
|
100
95
|
import {PrepareNextSlotScheduler} from "./prepareNextSlot.js";
|
|
101
|
-
import {
|
|
96
|
+
import {computeNewStateRoot, computePayloadEnvelopeStateRoot} from "./produceBlock/computeNewStateRoot.js";
|
|
102
97
|
import {AssembledBlockType, BlockType, ProduceFullGloas, ProduceResult} from "./produceBlock/index.js";
|
|
103
98
|
import {BlockAttributes, produceBlockBody, produceCommonBlockBody} from "./produceBlock/produceBlockBody.js";
|
|
104
99
|
import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js";
|
|
@@ -388,8 +383,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
388
383
|
const {checkpoint} = anchorState.computeAnchorCheckpoint();
|
|
389
384
|
blockStateCache.add(anchorState);
|
|
390
385
|
blockStateCache.setHeadState(anchorState);
|
|
391
|
-
|
|
392
|
-
checkpointStateCache.add(checkpoint, anchorState, payloadPresent);
|
|
386
|
+
checkpointStateCache.add(checkpoint, anchorState);
|
|
393
387
|
|
|
394
388
|
const forkChoice = initializeForkChoice(
|
|
395
389
|
config,
|
|
@@ -683,7 +677,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
683
677
|
|
|
684
678
|
// TODO GLOAS: Need to revisit the design of this api. Currently we just retrieve FULL state of the checkpoint for backwards compatibility.
|
|
685
679
|
// because pre-gloas we always store FULL checkpoint state.
|
|
686
|
-
const persistedKey = checkpointToDatastoreKey(checkpoint
|
|
680
|
+
const persistedKey = checkpointToDatastoreKey(checkpoint);
|
|
687
681
|
return this.cpStateDatastore.read(persistedKey);
|
|
688
682
|
}
|
|
689
683
|
|
|
@@ -878,6 +872,22 @@ export class BeaconChain implements IBeaconChain {
|
|
|
878
872
|
);
|
|
879
873
|
}
|
|
880
874
|
|
|
875
|
+
async getExecutionPayloadEnvelope(
|
|
876
|
+
blockSlot: Slot,
|
|
877
|
+
blockRootHex: string
|
|
878
|
+
): Promise<gloas.SignedExecutionPayloadEnvelope | null> {
|
|
879
|
+
const payloadInput = this.seenPayloadEnvelopeInputCache.get(blockRootHex);
|
|
880
|
+
if (payloadInput?.hasPayloadEnvelope()) {
|
|
881
|
+
return payloadInput.getPayloadEnvelope();
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return (
|
|
885
|
+
(await this.db.executionPayloadEnvelope.get(fromHex(blockRootHex))) ??
|
|
886
|
+
(await this.db.executionPayloadEnvelopeArchive.get(blockSlot)) ??
|
|
887
|
+
null
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
|
|
881
891
|
async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecar[]> {
|
|
882
892
|
const fork = this.config.getForkName(blockSlot);
|
|
883
893
|
|
|
@@ -1052,7 +1062,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1052
1062
|
body,
|
|
1053
1063
|
} as AssembledBlockType<T>;
|
|
1054
1064
|
|
|
1055
|
-
const {newStateRoot, proposerReward,
|
|
1065
|
+
const {newStateRoot, proposerReward, postBlockState} = computeNewStateRoot(this.metrics, state, block);
|
|
1056
1066
|
block.stateRoot = newStateRoot;
|
|
1057
1067
|
const blockRoot =
|
|
1058
1068
|
produceResult.type === BlockType.Full
|
|
@@ -1076,8 +1086,11 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1076
1086
|
slot,
|
|
1077
1087
|
stateRoot: ZERO_HASH,
|
|
1078
1088
|
};
|
|
1079
|
-
|
|
1080
|
-
|
|
1089
|
+
if (!isStatePostGloas(postBlockState)) {
|
|
1090
|
+
throw Error(`Expected gloas+ post-state for execution payload envelope, got fork=${postBlockState.forkName}`);
|
|
1091
|
+
}
|
|
1092
|
+
const payloadEnvelopeStateRoot = computePayloadEnvelopeStateRoot(this.metrics, postBlockState, envelope);
|
|
1093
|
+
gloasResult.payloadEnvelopeStateRoot = payloadEnvelopeStateRoot;
|
|
1081
1094
|
}
|
|
1082
1095
|
|
|
1083
1096
|
// Track the produced block for consensus broadcast validations, later validation, etc.
|
|
@@ -1404,9 +1417,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1404
1417
|
metrics.chain.blacklistedBlocks.set(this.blacklistedBlocks.size);
|
|
1405
1418
|
|
|
1406
1419
|
const headState = this.getHeadState();
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
if (isForkPostElectra(fork)) {
|
|
1420
|
+
if (isStatePostElectra(headState)) {
|
|
1410
1421
|
metrics.pendingDeposits.set(headState.pendingDepositsCount);
|
|
1411
1422
|
metrics.pendingPartialWithdrawals.set(headState.pendingPartialWithdrawalsCount);
|
|
1412
1423
|
metrics.pendingConsolidations.set(headState.pendingConsolidationsCount);
|
|
@@ -1452,10 +1463,6 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1452
1463
|
private onClockEpoch(epoch: Epoch): void {
|
|
1453
1464
|
this.metrics?.clockEpoch.set(epoch);
|
|
1454
1465
|
|
|
1455
|
-
if (epoch === this.config.GLOAS_FORK_EPOCH) {
|
|
1456
|
-
this.regen.upgradeForGloas(epoch);
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
1466
|
this.seenAttesters.prune(epoch);
|
|
1460
1467
|
this.seenAggregators.prune(epoch);
|
|
1461
1468
|
this.seenPayloadAttesters.prune(epoch);
|
|
@@ -1653,6 +1660,9 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1653
1660
|
}
|
|
1654
1661
|
|
|
1655
1662
|
preState = preState.processSlots(block.slot); // Dial preState's slot to block.slot
|
|
1663
|
+
if (!isStatePostAltair(preState)) {
|
|
1664
|
+
throw new Error("Sync committee rewards are not supported before Altair");
|
|
1665
|
+
}
|
|
1656
1666
|
|
|
1657
1667
|
return preState.computeSyncCommitteeRewards(block, validatorIds ?? []);
|
|
1658
1668
|
}
|
|
@@ -147,6 +147,10 @@ export enum AttestationErrorCode {
|
|
|
147
147
|
* Gloas: Current slot attestation is marking payload as present
|
|
148
148
|
*/
|
|
149
149
|
PREMATURELY_INDICATED_PAYLOAD_PRESENT = "ATTESTATION_ERROR_PREMATURELY_INDICATED_PAYLOAD_PRESENT",
|
|
150
|
+
/**
|
|
151
|
+
* Gloas: index-1 attestation but the execution payload has not been seen yet
|
|
152
|
+
*/
|
|
153
|
+
EXECUTION_PAYLOAD_NOT_SEEN = "ATTESTATION_ERROR_EXECUTION_PAYLOAD_NOT_SEEN",
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
export type AttestationErrorType =
|
|
@@ -185,7 +189,8 @@ export type AttestationErrorType =
|
|
|
185
189
|
| {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}
|
|
186
190
|
| {code: AttestationErrorCode.ATTESTER_NOT_IN_COMMITTEE}
|
|
187
191
|
| {code: AttestationErrorCode.INVALID_PAYLOAD_STATUS_VALUE; attDataIndex: number}
|
|
188
|
-
| {code: AttestationErrorCode.PREMATURELY_INDICATED_PAYLOAD_PRESENT}
|
|
192
|
+
| {code: AttestationErrorCode.PREMATURELY_INDICATED_PAYLOAD_PRESENT}
|
|
193
|
+
| {code: AttestationErrorCode.EXECUTION_PAYLOAD_NOT_SEEN; beaconBlockRoot: RootHex};
|
|
189
194
|
|
|
190
195
|
export class AttestationError extends GossipActionError<AttestationErrorType> {
|
|
191
196
|
getMetadata(): Record<string, string | number | null> {
|
|
@@ -70,6 +70,10 @@ export enum BlockErrorCode {
|
|
|
70
70
|
TOO_MANY_KZG_COMMITMENTS = "BLOCK_ERROR_TOO_MANY_KZG_COMMITMENTS",
|
|
71
71
|
/** Bid parent block root does not match block parent root */
|
|
72
72
|
BID_PARENT_ROOT_MISMATCH = "BLOCK_ERROR_BID_PARENT_ROOT_MISMATCH",
|
|
73
|
+
/** The parent block's execution payload has been verified as invalid */
|
|
74
|
+
PARENT_EXECUTION_INVALID = "BLOCK_ERROR_PARENT_EXECUTION_INVALID",
|
|
75
|
+
/** The block's parent execution payload (defined by bid.parent_block_hash) has not been seen */
|
|
76
|
+
PARENT_PAYLOAD_UNKNOWN = "BLOCK_ERROR_PARENT_PAYLOAD_UNKNOWN",
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
type ExecutionErrorStatus = Exclude<
|
|
@@ -114,7 +118,9 @@ export type BlockErrorType =
|
|
|
114
118
|
| {code: BlockErrorCode.EXECUTION_ENGINE_ERROR; execStatus: ExecutionErrorStatus; errorMessage: string}
|
|
115
119
|
| {code: BlockErrorCode.DATA_UNAVAILABLE}
|
|
116
120
|
| {code: BlockErrorCode.TOO_MANY_KZG_COMMITMENTS; blobKzgCommitmentsLen: number; commitmentLimit: number}
|
|
117
|
-
| {code: BlockErrorCode.BID_PARENT_ROOT_MISMATCH; bidParentRoot: RootHex; blockParentRoot: RootHex}
|
|
121
|
+
| {code: BlockErrorCode.BID_PARENT_ROOT_MISMATCH; bidParentRoot: RootHex; blockParentRoot: RootHex}
|
|
122
|
+
| {code: BlockErrorCode.PARENT_EXECUTION_INVALID; parentRoot: RootHex}
|
|
123
|
+
| {code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN; parentBlockHash: RootHex};
|
|
118
124
|
|
|
119
125
|
export class BlockGossipError extends GossipActionError<BlockErrorType> {}
|
|
120
126
|
|
|
@@ -10,12 +10,14 @@ import {
|
|
|
10
10
|
ForkChoiceOpts as RawForkChoiceOpts,
|
|
11
11
|
getCheckpointPayloadStatus,
|
|
12
12
|
} from "@lodestar/fork-choice";
|
|
13
|
-
import {
|
|
13
|
+
import {ZERO_HASH_HEX} from "@lodestar/params";
|
|
14
14
|
import {
|
|
15
15
|
DataAvailabilityStatus,
|
|
16
16
|
IBeaconStateView,
|
|
17
17
|
computeEpochAtSlot,
|
|
18
18
|
computeStartSlotAtEpoch,
|
|
19
|
+
isStatePostBellatrix,
|
|
20
|
+
isStatePostGloas,
|
|
19
21
|
} from "@lodestar/state-transition";
|
|
20
22
|
import {Slot, ssz} from "@lodestar/types";
|
|
21
23
|
import {Logger, toRootHex} from "@lodestar/utils";
|
|
@@ -142,19 +144,19 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
142
144
|
unrealizedFinalizedEpoch: finalizedCheckpoint.epoch,
|
|
143
145
|
unrealizedFinalizedRoot: toRootHex(finalizedCheckpoint.root),
|
|
144
146
|
|
|
145
|
-
...(state.isExecutionStateType && state.isMergeTransitionComplete
|
|
147
|
+
...(isStatePostBellatrix(state) && state.isExecutionStateType && state.isMergeTransitionComplete
|
|
146
148
|
? {
|
|
147
149
|
executionPayloadBlockHash: toRootHex(state.latestBlockHash),
|
|
148
150
|
// TODO GLOAS: executionPayloadNumber is not tracked in BeaconState post-gloas (EIP-7732 removed
|
|
149
151
|
// latestExecutionPayloadHeader). Using 0 as unavailable fallback until a solution is found.
|
|
150
|
-
executionPayloadNumber:
|
|
152
|
+
executionPayloadNumber: isStatePostGloas(state) ? 0 : state.payloadBlockNumber,
|
|
151
153
|
executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
|
|
152
154
|
}
|
|
153
155
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
154
156
|
|
|
155
157
|
dataAvailabilityStatus: DataAvailabilityStatus.PreData,
|
|
156
158
|
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
|
|
157
|
-
parentBlockHash:
|
|
159
|
+
parentBlockHash: isStatePostGloas(state) ? toRootHex(state.latestBlockHash) : null,
|
|
158
160
|
},
|
|
159
161
|
currentSlot
|
|
160
162
|
),
|
|
@@ -237,20 +239,21 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
237
239
|
unrealizedFinalizedEpoch: finalizedCheckpoint.epoch,
|
|
238
240
|
unrealizedFinalizedRoot: toRootHex(finalizedCheckpoint.root),
|
|
239
241
|
|
|
240
|
-
...(unfinalizedState
|
|
242
|
+
...(isStatePostBellatrix(unfinalizedState) &&
|
|
243
|
+
unfinalizedState.isExecutionStateType &&
|
|
244
|
+
unfinalizedState.isMergeTransitionComplete
|
|
241
245
|
? {
|
|
242
246
|
executionPayloadBlockHash: toRootHex(unfinalizedState.latestBlockHash),
|
|
243
247
|
// TODO GLOAS: executionPayloadNumber is not tracked in BeaconState post-gloas (EIP-7732 removed
|
|
244
248
|
// latestExecutionPayloadHeader). Using 0 as unavailable fallback until a solution is found.
|
|
245
|
-
executionPayloadNumber:
|
|
246
|
-
config.getForkSeq(unfinalizedState.slot) >= ForkSeq.gloas ? 0 : unfinalizedState.payloadBlockNumber,
|
|
249
|
+
executionPayloadNumber: isStatePostGloas(unfinalizedState) ? 0 : unfinalizedState.payloadBlockNumber,
|
|
247
250
|
executionStatus: blockHeader.slot === GENESIS_SLOT ? ExecutionStatus.Valid : ExecutionStatus.Syncing,
|
|
248
251
|
}
|
|
249
252
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
250
253
|
|
|
251
254
|
dataAvailabilityStatus: DataAvailabilityStatus.PreData,
|
|
252
255
|
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
|
|
253
|
-
parentBlockHash:
|
|
256
|
+
parentBlockHash: isStatePostGloas(unfinalizedState) ? toRootHex(unfinalizedState.latestBlockHash) : null,
|
|
254
257
|
};
|
|
255
258
|
|
|
256
259
|
const parentSlot = blockHeader.slot - 1;
|
package/src/chain/interface.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
altair,
|
|
19
19
|
capella,
|
|
20
20
|
deneb,
|
|
21
|
+
gloas,
|
|
21
22
|
phase0,
|
|
22
23
|
rewards,
|
|
23
24
|
} from "@lodestar/types";
|
|
@@ -226,6 +227,10 @@ export interface IBeaconChain {
|
|
|
226
227
|
indices: number[]
|
|
227
228
|
): Promise<(Uint8Array | undefined)[]>;
|
|
228
229
|
getSerializedExecutionPayloadEnvelope(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null>;
|
|
230
|
+
getExecutionPayloadEnvelope(
|
|
231
|
+
blockSlot: Slot,
|
|
232
|
+
blockRootHex: string
|
|
233
|
+
): Promise<gloas.SignedExecutionPayloadEnvelope | null>;
|
|
229
234
|
|
|
230
235
|
produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
|
|
231
236
|
produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
isForkPostElectra,
|
|
22
22
|
} from "@lodestar/params";
|
|
23
23
|
import {
|
|
24
|
-
|
|
24
|
+
type IBeaconStateViewAltair,
|
|
25
25
|
computeStartSlotAtEpoch,
|
|
26
26
|
computeSyncPeriodAtEpoch,
|
|
27
27
|
computeSyncPeriodAtSlot,
|
|
@@ -260,7 +260,11 @@ export class LightClientServer {
|
|
|
260
260
|
* - Persist state witness
|
|
261
261
|
* - Use block's syncAggregate
|
|
262
262
|
*/
|
|
263
|
-
onImportBlockHead(
|
|
263
|
+
onImportBlockHead(
|
|
264
|
+
block: BeaconBlock<ForkPostAltair>,
|
|
265
|
+
postState: IBeaconStateViewAltair,
|
|
266
|
+
parentBlockSlot: Slot
|
|
267
|
+
): void {
|
|
264
268
|
// TEMP: To disable this functionality for fork_choice spec tests.
|
|
265
269
|
// Since the tests have deep-reorgs attested data is not available often printing lots of error logs.
|
|
266
270
|
// While this function is only called for head blocks, best to disable.
|
|
@@ -268,6 +272,14 @@ export class LightClientServer {
|
|
|
268
272
|
return;
|
|
269
273
|
}
|
|
270
274
|
|
|
275
|
+
// TODO GLOAS: Light client updates for gloas are not yet updated in the spec.
|
|
276
|
+
// The block body no longer contains execution payload, so `blockToLightClientHeader`
|
|
277
|
+
// cannot construct a header from a gloas block. Skip all light client processing
|
|
278
|
+
// for post-gloas blocks, revisit once there is a spec for it.
|
|
279
|
+
if (this.config.getForkSeq(block.slot) >= ForkSeq.gloas) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
271
283
|
// What is the syncAggregate signing?
|
|
272
284
|
// From the state-transition
|
|
273
285
|
// ```
|
|
@@ -396,7 +408,7 @@ export class LightClientServer {
|
|
|
396
408
|
|
|
397
409
|
private async persistPostBlockImportData(
|
|
398
410
|
block: BeaconBlock<ForkPostAltair>,
|
|
399
|
-
postState:
|
|
411
|
+
postState: IBeaconStateViewAltair,
|
|
400
412
|
parentBlockSlot: Slot
|
|
401
413
|
): Promise<void> {
|
|
402
414
|
const blockSlot = block.slot;
|
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
computeSlotsSinceEpochStart,
|
|
27
27
|
computeStartSlotAtEpoch,
|
|
28
28
|
getAttestationParticipationStatus,
|
|
29
|
+
isStatePostAltair,
|
|
30
|
+
isStatePostGloas,
|
|
29
31
|
} from "@lodestar/state-transition";
|
|
30
32
|
import {Attestation, Epoch, RootHex, Slot, electra, isElectraAttestation, phase0, ssz} from "@lodestar/types";
|
|
31
33
|
import {MapDef, assert, toRootHex} from "@lodestar/utils";
|
|
@@ -359,7 +361,7 @@ export class AggregatedAttestationPool {
|
|
|
359
361
|
inclusionDistance,
|
|
360
362
|
stateEpoch,
|
|
361
363
|
rootCache,
|
|
362
|
-
|
|
364
|
+
isStatePostGloas(state) ? state.executionPayloadAvailability : null
|
|
363
365
|
);
|
|
364
366
|
|
|
365
367
|
const weight =
|
|
@@ -742,6 +744,9 @@ export function getNotSeenValidatorsFn(
|
|
|
742
744
|
if (config.getForkName(stateSlot) === ForkName.phase0) {
|
|
743
745
|
throw new Error("getNotSeenValidatorsFn is not supported phase0 state");
|
|
744
746
|
}
|
|
747
|
+
if (!isStatePostAltair(state)) {
|
|
748
|
+
throw new Error("Expected Altair state for participation tracking");
|
|
749
|
+
}
|
|
745
750
|
|
|
746
751
|
// altair and future forks
|
|
747
752
|
// Get attestations to be included in an altair block.
|
|
@@ -59,13 +59,13 @@ export class ExecutionPayloadBidPool {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Return the highest-value bid matching slot, parent block
|
|
62
|
+
* Return the highest-value bid matching slot, parent block hash, and parent block root.
|
|
63
63
|
* Used for gossip validation and block production.
|
|
64
64
|
*/
|
|
65
65
|
getBestBid(
|
|
66
|
-
|
|
66
|
+
slot: Slot,
|
|
67
67
|
parentBlockHash: BlockHashHex,
|
|
68
|
-
|
|
68
|
+
parentBlockRoot: BlockRootHex
|
|
69
69
|
): gloas.ExecutionPayloadBid | null {
|
|
70
70
|
const bidByParentHash = this.bidByParentHashByParentRootBySlot.get(slot)?.get(parentBlockRoot);
|
|
71
71
|
return bidByParentHash?.get(parentBlockHash) ?? null;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
StateHashTreeRootSource,
|
|
8
8
|
computeEpochAtSlot,
|
|
9
9
|
computeTimeAtSlot,
|
|
10
|
+
isStatePostBellatrix,
|
|
10
11
|
} from "@lodestar/state-transition";
|
|
11
12
|
import {Slot} from "@lodestar/types";
|
|
12
13
|
import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
|
|
@@ -159,6 +160,9 @@ export class PrepareNextSlotScheduler {
|
|
|
159
160
|
const preparationTime =
|
|
160
161
|
computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
|
|
161
162
|
this.metrics?.blockPayload.payloadAdvancePrepTime.observe(preparationTime);
|
|
163
|
+
if (!isStatePostBellatrix(updatedPrepareState)) {
|
|
164
|
+
throw new Error("Expected Bellatrix state for payload preparation");
|
|
165
|
+
}
|
|
162
166
|
|
|
163
167
|
const safeBlockHash = getSafeExecutionBlockHash(this.chain.forkChoice);
|
|
164
168
|
const finalizedBlockHash =
|
|
@@ -183,6 +187,10 @@ export class PrepareNextSlotScheduler {
|
|
|
183
187
|
});
|
|
184
188
|
}
|
|
185
189
|
|
|
190
|
+
if (!isStatePostBellatrix(updatedPrepareState)) {
|
|
191
|
+
throw new Error("Expected Bellatrix state for payload attributes");
|
|
192
|
+
}
|
|
193
|
+
|
|
186
194
|
this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
|
|
187
195
|
|
|
188
196
|
// If emitPayloadAttributes is true emit a SSE payloadAttributes event
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
ExecutionPayloadStatus,
|
|
4
4
|
G2_POINT_AT_INFINITY,
|
|
5
5
|
IBeaconStateView,
|
|
6
|
+
IBeaconStateViewGloas,
|
|
6
7
|
StateHashTreeRootSource,
|
|
7
8
|
} from "@lodestar/state-transition";
|
|
8
9
|
import {BeaconBlock, BlindedBeaconBlock, Gwei, Root, gloas} from "@lodestar/types";
|
|
@@ -18,11 +19,11 @@ export function computeNewStateRoot(
|
|
|
18
19
|
metrics: Metrics | null,
|
|
19
20
|
state: IBeaconStateView,
|
|
20
21
|
block: BeaconBlock | BlindedBeaconBlock
|
|
21
|
-
): {newStateRoot: Root; proposerReward: Gwei;
|
|
22
|
+
): {newStateRoot: Root; proposerReward: Gwei; postBlockState: IBeaconStateView} {
|
|
22
23
|
// Set signature to zero to re-use stateTransition() function which requires the SignedBeaconBlock type
|
|
23
24
|
const blockEmptySig = {message: block, signature: ZERO_HASH};
|
|
24
25
|
|
|
25
|
-
const
|
|
26
|
+
const postBlockState = state.stateTransition(
|
|
26
27
|
blockEmptySig,
|
|
27
28
|
{
|
|
28
29
|
// ExecutionPayloadStatus.valid: Assume payload valid, it has been produced by a trusted EL
|
|
@@ -41,16 +42,16 @@ export function computeNewStateRoot(
|
|
|
41
42
|
{metrics}
|
|
42
43
|
);
|
|
43
44
|
|
|
44
|
-
const {attestations, syncAggregate, slashing} =
|
|
45
|
+
const {attestations, syncAggregate, slashing} = postBlockState.proposerRewards;
|
|
45
46
|
const proposerReward = BigInt(attestations + syncAggregate + slashing);
|
|
46
47
|
|
|
47
48
|
const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({
|
|
48
49
|
source: StateHashTreeRootSource.computeNewStateRoot,
|
|
49
50
|
});
|
|
50
|
-
const newStateRoot =
|
|
51
|
+
const newStateRoot = postBlockState.hashTreeRoot();
|
|
51
52
|
hashTreeRootTimer?.();
|
|
52
53
|
|
|
53
|
-
return {newStateRoot, proposerReward,
|
|
54
|
+
return {newStateRoot, proposerReward, postBlockState};
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
@@ -58,9 +59,9 @@ export function computeNewStateRoot(
|
|
|
58
59
|
* Similar to `computeNewStateRoot` but for payload envelope processing.
|
|
59
60
|
*
|
|
60
61
|
*/
|
|
61
|
-
export function
|
|
62
|
+
export function computePayloadEnvelopeStateRoot(
|
|
62
63
|
metrics: Metrics | null,
|
|
63
|
-
postBlockState:
|
|
64
|
+
postBlockState: IBeaconStateViewGloas,
|
|
64
65
|
envelope: gloas.ExecutionPayloadEnvelope
|
|
65
66
|
): Root {
|
|
66
67
|
const signedEnvelope: gloas.SignedExecutionPayloadEnvelope = {
|
|
@@ -69,7 +70,7 @@ export function computeEnvelopeStateRoot(
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
const processEnvelopeTimer = metrics?.blockPayload.executionPayloadEnvelopeProcessingTime.startTimer();
|
|
72
|
-
const
|
|
73
|
+
const postPayloadState = postBlockState.processExecutionPayloadEnvelope(signedEnvelope, {
|
|
73
74
|
// Signature is zero-ed (G2_POINT_AT_INFINITY), skip verification
|
|
74
75
|
verifySignature: false,
|
|
75
76
|
// State root is being computed here, the envelope doesn't have it yet
|
|
@@ -80,9 +81,9 @@ export function computeEnvelopeStateRoot(
|
|
|
80
81
|
processEnvelopeTimer?.();
|
|
81
82
|
|
|
82
83
|
const hashTreeRootTimer = metrics?.stateHashTreeRootTime.startTimer({
|
|
83
|
-
source: StateHashTreeRootSource.
|
|
84
|
+
source: StateHashTreeRootSource.computePayloadEnvelopeStateRoot,
|
|
84
85
|
});
|
|
85
|
-
const stateRoot =
|
|
86
|
+
const stateRoot = postPayloadState.hashTreeRoot();
|
|
86
87
|
hashTreeRootTimer?.();
|
|
87
88
|
|
|
88
89
|
return stateRoot;
|
|
@@ -14,7 +14,16 @@ import {
|
|
|
14
14
|
isForkPostBellatrix,
|
|
15
15
|
isForkPostGloas,
|
|
16
16
|
} from "@lodestar/params";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
G2_POINT_AT_INFINITY,
|
|
19
|
+
IBeaconStateView,
|
|
20
|
+
type IBeaconStateViewBellatrix,
|
|
21
|
+
computeTimeAtSlot,
|
|
22
|
+
isParentBlockFull,
|
|
23
|
+
isStatePostBellatrix,
|
|
24
|
+
isStatePostCapella,
|
|
25
|
+
isStatePostGloas,
|
|
26
|
+
} from "@lodestar/state-transition";
|
|
18
27
|
import {
|
|
19
28
|
BLSPubkey,
|
|
20
29
|
BLSSignature,
|
|
@@ -103,11 +112,11 @@ export type ProduceFullGloas = {
|
|
|
103
112
|
blobsBundle: BlobsBundle<ForkPostGloas>;
|
|
104
113
|
cells: fulu.Cell[][];
|
|
105
114
|
/**
|
|
106
|
-
* Cached envelope state root computed during block production.
|
|
115
|
+
* Cached payload envelope state root computed during block production.
|
|
107
116
|
* This is the state root after running `processExecutionPayloadEnvelope` on the
|
|
108
117
|
* post-block state, and later used to construct the `ExecutionPayloadEnvelope`.
|
|
109
118
|
*/
|
|
110
|
-
|
|
119
|
+
payloadEnvelopeStateRoot: Root;
|
|
111
120
|
};
|
|
112
121
|
export type ProduceFullFulu = {
|
|
113
122
|
type: BlockType.Full;
|
|
@@ -191,6 +200,10 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
191
200
|
this.logger.verbose("Producing beacon block body", logMeta);
|
|
192
201
|
|
|
193
202
|
if (isForkPostGloas(fork)) {
|
|
203
|
+
if (!isStatePostGloas(currentState)) {
|
|
204
|
+
throw new Error("Expected Gloas state for Gloas block production");
|
|
205
|
+
}
|
|
206
|
+
|
|
194
207
|
// TODO GLOAS: support non self-building here, the block type differentiation between
|
|
195
208
|
// full and blinded no longer makes sense in gloas, it might be a good idea to move
|
|
196
209
|
// this into a completely separate function and have pre/post gloas more separated
|
|
@@ -297,6 +310,10 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
297
310
|
shouldOverrideBuilder,
|
|
298
311
|
});
|
|
299
312
|
} else if (isForkPostBellatrix(fork)) {
|
|
313
|
+
if (!isStatePostBellatrix(currentState)) {
|
|
314
|
+
throw new Error("Expected Bellatrix state for execution block production");
|
|
315
|
+
}
|
|
316
|
+
|
|
300
317
|
const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
|
|
301
318
|
const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
|
|
302
319
|
const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
|
|
@@ -598,7 +615,7 @@ export async function prepareExecutionPayload(
|
|
|
598
615
|
parentBlockRoot: Root,
|
|
599
616
|
safeBlockHash: RootHex,
|
|
600
617
|
finalizedBlockHash: RootHex,
|
|
601
|
-
state:
|
|
618
|
+
state: IBeaconStateViewBellatrix,
|
|
602
619
|
suggestedFeeRecipient: string
|
|
603
620
|
): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
|
|
604
621
|
const parentHash = state.latestBlockHash;
|
|
@@ -666,7 +683,7 @@ async function prepareExecutionPayloadHeader(
|
|
|
666
683
|
config: ChainForkConfig;
|
|
667
684
|
},
|
|
668
685
|
fork: ForkPostBellatrix,
|
|
669
|
-
state:
|
|
686
|
+
state: IBeaconStateViewBellatrix,
|
|
670
687
|
proposerPubKey: BLSPubkey
|
|
671
688
|
): Promise<{
|
|
672
689
|
header: ExecutionPayloadHeader;
|
|
@@ -693,7 +710,7 @@ export function getPayloadAttributesForSSE(
|
|
|
693
710
|
prepareSlot,
|
|
694
711
|
parentBlockRoot,
|
|
695
712
|
feeRecipient,
|
|
696
|
-
}: {prepareState:
|
|
713
|
+
}: {prepareState: IBeaconStateViewBellatrix; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
|
|
697
714
|
): SSEPayloadAttributes {
|
|
698
715
|
const parentHash = prepareState.latestBlockHash;
|
|
699
716
|
const payloadAttributes = preparePayloadAttributes(fork, chain, {
|
|
@@ -736,7 +753,7 @@ function preparePayloadAttributes(
|
|
|
736
753
|
parentBlockRoot,
|
|
737
754
|
feeRecipient,
|
|
738
755
|
}: {
|
|
739
|
-
prepareState:
|
|
756
|
+
prepareState: IBeaconStateViewBellatrix;
|
|
740
757
|
prepareSlot: Slot;
|
|
741
758
|
parentBlockRoot: Root;
|
|
742
759
|
feeRecipient: string;
|
|
@@ -751,9 +768,22 @@ function preparePayloadAttributes(
|
|
|
751
768
|
};
|
|
752
769
|
|
|
753
770
|
if (ForkSeq[fork] >= ForkSeq.capella) {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
771
|
+
if (!isStatePostCapella(prepareState)) {
|
|
772
|
+
throw new Error("Expected Capella state for withdrawals");
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (isStatePostGloas(prepareState) && !isParentBlockFull(prepareState)) {
|
|
776
|
+
// When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
|
|
777
|
+
// already deducted from CL balances but never credited on the EL (the envelope
|
|
778
|
+
// was not delivered). The next payload must carry those same withdrawals to
|
|
779
|
+
// restore CL/EL consistency, otherwise validators permanently lose that balance.
|
|
780
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
781
|
+
prepareState.payloadExpectedWithdrawals;
|
|
782
|
+
} else {
|
|
783
|
+
// withdrawals logic is now fork aware as it changes on electra fork post capella
|
|
784
|
+
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
|
|
785
|
+
prepareState.getExpectedWithdrawals().expectedWithdrawals;
|
|
786
|
+
}
|
|
757
787
|
}
|
|
758
788
|
|
|
759
789
|
if (ForkSeq[fork] >= ForkSeq.deneb) {
|
|
@@ -54,7 +54,6 @@ export interface IStateRegenerator extends IStateRegeneratorInternal {
|
|
|
54
54
|
addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, payloadPresent: boolean): void;
|
|
55
55
|
updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void;
|
|
56
56
|
updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch, payloadPresent: boolean): number | null;
|
|
57
|
-
upgradeForGloas(epoch: Epoch): void;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
/**
|