@lodestar/beacon-node 1.43.0-dev.2870b59b6a → 1.43.0-dev.3d6ae250a4
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 +1 -4
- 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/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +1 -4
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/GetBlobsTracker.d.ts +1 -1
- package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
- package/lib/chain/GetBlobsTracker.js +1 -2
- package/lib/chain/GetBlobsTracker.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 +2 -4
- 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 +23 -31
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +15 -14
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +63 -85
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +1 -2
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
- package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeProcessor.js +6 -4
- package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
- package/lib/chain/blocks/types.d.ts +15 -21
- package/lib/chain/blocks/types.d.ts.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/verifyPayloadsDataAvailability.d.ts +14 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
- package/lib/chain/blocks/verifyPayloadsDataAvailability.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 +5 -4
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +23 -32
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +16 -4
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +5 -0
- package/lib/chain/emitter.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 +11 -15
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +4 -3
- 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 +48 -22
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts +3 -9
- package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
- package/lib/chain/produceBlock/computeNewStateRoot.js +5 -32
- package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -8
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +48 -23
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/errors.d.ts +1 -11
- package/lib/chain/regen/errors.d.ts.map +1 -1
- package/lib/chain/regen/errors.js +0 -2
- package/lib/chain/regen/errors.js.map +1 -1
- package/lib/chain/regen/interface.d.ts +6 -11
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/queued.d.ts +6 -10
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +3 -10
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts +0 -5
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +0 -8
- package/lib/chain/regen/regen.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 +1 -7
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +4 -9
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +0 -6
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.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 +20 -10
- 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/network/gossip/topic.d.ts +750 -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 +22 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/node/nodejs.d.ts.map +1 -1
- package/lib/node/nodejs.js +4 -2
- package/lib/node/nodejs.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 +1 -4
- package/src/api/impl/beacon/state/utils.ts +2 -2
- package/src/api/impl/validator/index.ts +3 -6
- package/src/chain/GetBlobsTracker.ts +1 -2
- package/src/chain/archiveStore/archiveStore.ts +5 -5
- package/src/chain/archiveStore/interface.ts +4 -4
- package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +6 -8
- package/src/chain/archiveStore/utils/archiveBlocks.ts +153 -94
- package/src/chain/blocks/importBlock.ts +22 -35
- package/src/chain/blocks/importExecutionPayload.ts +77 -103
- package/src/chain/blocks/index.ts +1 -2
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
- package/src/chain/blocks/payloadEnvelopeProcessor.ts +6 -5
- package/src/chain/blocks/types.ts +15 -26
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
- package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
- package/src/chain/chain.ts +35 -48
- package/src/chain/emitter.ts +15 -3
- package/src/chain/errors/executionPayloadBid.ts +6 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
- package/src/chain/forkChoice/index.ts +8 -20
- package/src/chain/interface.ts +4 -2
- package/src/chain/prepareNextSlot.ts +62 -23
- package/src/chain/produceBlock/computeNewStateRoot.ts +6 -43
- package/src/chain/produceBlock/produceBlockBody.ts +66 -26
- package/src/chain/regen/errors.ts +1 -6
- package/src/chain/regen/interface.ts +6 -11
- package/src/chain/regen/queued.ts +6 -14
- package/src/chain/regen/regen.ts +0 -8
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
- package/src/chain/stateCache/persistentCheckpointsCache.ts +5 -15
- package/src/chain/stateCache/types.ts +0 -3
- package/src/chain/validation/executionPayloadBid.ts +14 -0
- package/src/chain/validation/executionPayloadEnvelope.ts +21 -11
- 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/network/network.ts +1 -1
- package/src/network/processor/gossipHandlers.ts +26 -10
- package/src/node/nodejs.ts +4 -2
- package/src/util/sszBytes.ts +21 -3
package/src/chain/chain.ts
CHANGED
|
@@ -2,10 +2,9 @@ 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
|
-
BUILDER_INDEX_SELF_BUILD,
|
|
9
8
|
EFFECTIVE_BALANCE_INCREMENT,
|
|
10
9
|
type ForkPostFulu,
|
|
11
10
|
type ForkPostGloas,
|
|
@@ -24,7 +23,6 @@ import {
|
|
|
24
23
|
getEffectiveBalancesFromStateBytes,
|
|
25
24
|
isStatePostAltair,
|
|
26
25
|
isStatePostElectra,
|
|
27
|
-
isStatePostGloas,
|
|
28
26
|
} from "@lodestar/state-transition";
|
|
29
27
|
import {
|
|
30
28
|
BeaconBlock,
|
|
@@ -41,6 +39,7 @@ import {
|
|
|
41
39
|
ValidatorIndex,
|
|
42
40
|
Wei,
|
|
43
41
|
deneb,
|
|
42
|
+
electra,
|
|
44
43
|
gloas,
|
|
45
44
|
isBlindedBeaconBlock,
|
|
46
45
|
phase0,
|
|
@@ -93,8 +92,8 @@ import {
|
|
|
93
92
|
} from "./opPools/index.js";
|
|
94
93
|
import {IChainOptions} from "./options.js";
|
|
95
94
|
import {PrepareNextSlotScheduler} from "./prepareNextSlot.js";
|
|
96
|
-
import {computeNewStateRoot
|
|
97
|
-
import {AssembledBlockType, BlockType,
|
|
95
|
+
import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js";
|
|
96
|
+
import {AssembledBlockType, BlockType, ProduceResult} from "./produceBlock/index.js";
|
|
98
97
|
import {BlockAttributes, produceBlockBody, produceCommonBlockBody} from "./produceBlock/produceBlockBody.js";
|
|
99
98
|
import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js";
|
|
100
99
|
import {ReprocessController} from "./reprocess.js";
|
|
@@ -118,7 +117,7 @@ import {DbCPStateDatastore, checkpointToDatastoreKey} from "./stateCache/datasto
|
|
|
118
117
|
import {FileCPStateDatastore} from "./stateCache/datastore/file.js";
|
|
119
118
|
import {CPStateDatastore} from "./stateCache/datastore/types.js";
|
|
120
119
|
import {FIFOBlockStateCache} from "./stateCache/fifoBlockStateCache.js";
|
|
121
|
-
import {PersistentCheckpointStateCache
|
|
120
|
+
import {PersistentCheckpointStateCache} from "./stateCache/persistentCheckpointsCache.js";
|
|
122
121
|
import {CheckpointStateCache} from "./stateCache/types.js";
|
|
123
122
|
import {ValidatorMonitor} from "./validatorMonitor.js";
|
|
124
123
|
|
|
@@ -682,11 +681,11 @@ export class BeaconChain implements IBeaconChain {
|
|
|
682
681
|
}
|
|
683
682
|
|
|
684
683
|
getStateByCheckpoint(
|
|
685
|
-
checkpoint:
|
|
684
|
+
checkpoint: CheckpointWithHex
|
|
686
685
|
): {state: IBeaconStateView; executionOptimistic: boolean; finalized: boolean} | null {
|
|
687
686
|
// finalized or justified checkpoint states maynot be available with PersistentCheckpointStateCache, use getCheckpointStateOrBytes() api to get Uint8Array
|
|
688
|
-
const
|
|
689
|
-
const cachedStateCtx = this.regen.getCheckpointStateSync(
|
|
687
|
+
const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
|
|
688
|
+
const cachedStateCtx = this.regen.getCheckpointStateSync(checkpointHex);
|
|
690
689
|
if (cachedStateCtx) {
|
|
691
690
|
const block = this.forkChoice.getBlockDefaultStatus(
|
|
692
691
|
ssz.phase0.BeaconBlockHeader.hashTreeRoot(cachedStateCtx.latestBlockHeader)
|
|
@@ -703,10 +702,10 @@ export class BeaconChain implements IBeaconChain {
|
|
|
703
702
|
}
|
|
704
703
|
|
|
705
704
|
async getStateOrBytesByCheckpoint(
|
|
706
|
-
checkpoint:
|
|
705
|
+
checkpoint: CheckpointWithHex
|
|
707
706
|
): Promise<{state: IBeaconStateView | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null> {
|
|
708
|
-
const
|
|
709
|
-
const cachedStateCtx = await this.regen.getCheckpointStateOrBytes(
|
|
707
|
+
const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
|
|
708
|
+
const cachedStateCtx = await this.regen.getCheckpointStateOrBytes(checkpointHex);
|
|
710
709
|
if (cachedStateCtx) {
|
|
711
710
|
const block = this.forkChoice.getBlockDefaultStatus(checkpoint.root);
|
|
712
711
|
const finalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
|
|
@@ -888,6 +887,17 @@ export class BeaconChain implements IBeaconChain {
|
|
|
888
887
|
);
|
|
889
888
|
}
|
|
890
889
|
|
|
890
|
+
async getParentExecutionRequests(
|
|
891
|
+
parentBlockSlot: Slot,
|
|
892
|
+
parentBlockRootHex: RootHex
|
|
893
|
+
): Promise<electra.ExecutionRequests> {
|
|
894
|
+
const envelope = await this.getExecutionPayloadEnvelope(parentBlockSlot, parentBlockRootHex);
|
|
895
|
+
if (envelope === null) {
|
|
896
|
+
throw Error(`Parent execution payload envelope not found slot=${parentBlockSlot}, root=${parentBlockRootHex}`);
|
|
897
|
+
}
|
|
898
|
+
return envelope.message.executionRequests;
|
|
899
|
+
}
|
|
900
|
+
|
|
891
901
|
async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<DataColumnSidecar[]> {
|
|
892
902
|
const fork = this.config.getForkName(blockSlot);
|
|
893
903
|
|
|
@@ -1062,7 +1072,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1062
1072
|
body,
|
|
1063
1073
|
} as AssembledBlockType<T>;
|
|
1064
1074
|
|
|
1065
|
-
const {newStateRoot, proposerReward
|
|
1075
|
+
const {newStateRoot, proposerReward} = computeNewStateRoot(this.metrics, state, block);
|
|
1066
1076
|
block.stateRoot = newStateRoot;
|
|
1067
1077
|
const blockRoot =
|
|
1068
1078
|
produceResult.type === BlockType.Full
|
|
@@ -1071,26 +1081,9 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1071
1081
|
const blockRootHex = toRootHex(blockRoot);
|
|
1072
1082
|
|
|
1073
1083
|
const fork = this.config.getForkName(slot);
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
throw Error(`Unexpected block type=${produceResult.type} for post-gloas fork=${fork}`);
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
const gloasResult = produceResult as ProduceFullGloas;
|
|
1081
|
-
const envelope: gloas.ExecutionPayloadEnvelope = {
|
|
1082
|
-
payload: gloasResult.executionPayload,
|
|
1083
|
-
executionRequests: gloasResult.executionRequests,
|
|
1084
|
-
builderIndex: BUILDER_INDEX_SELF_BUILD,
|
|
1085
|
-
beaconBlockRoot: blockRoot,
|
|
1086
|
-
slot,
|
|
1087
|
-
stateRoot: ZERO_HASH,
|
|
1088
|
-
};
|
|
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;
|
|
1084
|
+
// TODO GLOAS: we should retire BlockType post-gloas, may need a new enum for self vs non-self built
|
|
1085
|
+
if (isForkPostGloas(fork) && produceResult.type !== BlockType.Full) {
|
|
1086
|
+
throw Error(`Unexpected block type=${produceResult.type} for post-gloas fork=${fork}`);
|
|
1094
1087
|
}
|
|
1095
1088
|
|
|
1096
1089
|
// Track the produced block for consensus broadcast validations, later validation, etc.
|
|
@@ -1296,7 +1289,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1296
1289
|
* @param blockState state that declares justified checkpoint `checkpoint`
|
|
1297
1290
|
*/
|
|
1298
1291
|
private justifiedBalancesGetter(
|
|
1299
|
-
checkpoint:
|
|
1292
|
+
checkpoint: CheckpointWithHex,
|
|
1300
1293
|
blockState: IBeaconStateView
|
|
1301
1294
|
): EffectiveBalanceIncrements {
|
|
1302
1295
|
this.metrics?.balancesCache.requests.inc();
|
|
@@ -1335,11 +1328,11 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1335
1328
|
* @param blockState state that declares justified checkpoint `checkpoint`
|
|
1336
1329
|
*/
|
|
1337
1330
|
private closestJustifiedBalancesStateToCheckpoint(
|
|
1338
|
-
checkpoint:
|
|
1331
|
+
checkpoint: CheckpointWithHex,
|
|
1339
1332
|
blockState: IBeaconStateView
|
|
1340
1333
|
): {state: IBeaconStateView; stateId: string; shouldWarn: boolean} {
|
|
1341
|
-
const
|
|
1342
|
-
const state = this.regen.getCheckpointStateSync(
|
|
1334
|
+
const checkpointHex = {epoch: checkpoint.epoch, rootHex: checkpoint.rootHex};
|
|
1335
|
+
const state = this.regen.getCheckpointStateSync(checkpointHex);
|
|
1343
1336
|
if (state) {
|
|
1344
1337
|
return {state, stateId: "checkpoint_state", shouldWarn: false};
|
|
1345
1338
|
}
|
|
@@ -1350,10 +1343,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1350
1343
|
}
|
|
1351
1344
|
|
|
1352
1345
|
// Find a state in the same branch of checkpoint at same epoch. Balances should exactly the same
|
|
1353
|
-
for (const descendantBlock of this.forkChoice.
|
|
1354
|
-
checkpoint.rootHex,
|
|
1355
|
-
checkpoint.payloadStatus
|
|
1356
|
-
)) {
|
|
1346
|
+
for (const descendantBlock of this.forkChoice.forwardIterateDescendantsDefaultStatus(checkpoint.rootHex)) {
|
|
1357
1347
|
if (computeEpochAtSlot(descendantBlock.slot) === checkpoint.epoch) {
|
|
1358
1348
|
const descendantBlockState = this.regen.getStateSync(descendantBlock.stateRoot);
|
|
1359
1349
|
if (descendantBlockState) {
|
|
@@ -1369,10 +1359,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1369
1359
|
|
|
1370
1360
|
// Find a state in the same branch of checkpoint at a latter epoch. Balances are not the same, but should be close
|
|
1371
1361
|
// Note: must call .forwardIterateDescendants() again since nodes are not sorted
|
|
1372
|
-
for (const descendantBlock of this.forkChoice.
|
|
1373
|
-
checkpoint.rootHex,
|
|
1374
|
-
checkpoint.payloadStatus
|
|
1375
|
-
)) {
|
|
1362
|
+
for (const descendantBlock of this.forkChoice.forwardIterateDescendantsDefaultStatus(checkpoint.rootHex)) {
|
|
1376
1363
|
if (computeEpochAtSlot(descendantBlock.slot) > checkpoint.epoch) {
|
|
1377
1364
|
const descendantBlockState = this.regen.getStateSync(descendantBlock.stateRoot);
|
|
1378
1365
|
if (descendantBlockState) {
|
|
@@ -1476,7 +1463,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1476
1463
|
this.seenContributionAndProof.prune(head.slot);
|
|
1477
1464
|
}
|
|
1478
1465
|
|
|
1479
|
-
private onForkChoiceJustified(this: BeaconChain, cp:
|
|
1466
|
+
private onForkChoiceJustified(this: BeaconChain, cp: CheckpointWithHex): void {
|
|
1480
1467
|
this.logger.verbose("Fork choice justified", {epoch: cp.epoch, root: cp.rootHex});
|
|
1481
1468
|
}
|
|
1482
1469
|
|
|
@@ -1487,7 +1474,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1487
1474
|
});
|
|
1488
1475
|
}
|
|
1489
1476
|
|
|
1490
|
-
private async onForkChoiceFinalized(this: BeaconChain, cp:
|
|
1477
|
+
private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
|
|
1491
1478
|
this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
|
|
1492
1479
|
const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
|
|
1493
1480
|
this.seenBlockProposers.prune(finalizedSlot);
|
|
@@ -1528,7 +1515,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
1528
1515
|
}
|
|
1529
1516
|
}
|
|
1530
1517
|
|
|
1531
|
-
private async updateValidatorsCustodyRequirement(finalizedCheckpoint:
|
|
1518
|
+
private async updateValidatorsCustodyRequirement(finalizedCheckpoint: CheckpointWithHex): Promise<void> {
|
|
1532
1519
|
if (this.custodyConfig.targetCustodyGroupCount === this.config.NUMBER_OF_CUSTODY_GROUPS) {
|
|
1533
1520
|
// Custody requirements can only be increased, we can disable dynamic custody updates
|
|
1534
1521
|
// if the node already maintains custody of all custody groups in case it is configured
|
package/src/chain/emitter.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
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";
|
|
8
8
|
import {PeerIdStr} from "../util/peerId.js";
|
|
9
9
|
import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
|
|
10
|
+
import {PayloadEnvelopeInput} from "./blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Important chain events that occur during normal chain operation.
|
|
@@ -76,6 +77,11 @@ export enum ChainEvent {
|
|
|
76
77
|
* cut-off window passes for waiting on gossip
|
|
77
78
|
*/
|
|
78
79
|
incompleteBlockInput = "incompleteBlockInput",
|
|
80
|
+
/**
|
|
81
|
+
* Post-gloas: trigger BlockInputSync for payload envelopes whose envelope and/or sampled columns are partially
|
|
82
|
+
* received via gossip but are not complete by time the cut-off window passes for waiting on gossip
|
|
83
|
+
*/
|
|
84
|
+
incompletePayloadEnvelope = "incompletePayloadEnvelope",
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
export type HeadEventData = routes.events.EventData[routes.events.EventType.head];
|
|
@@ -93,14 +99,19 @@ export type ChainEventData = {
|
|
|
93
99
|
};
|
|
94
100
|
[ChainEvent.unknownBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
|
|
95
101
|
[ChainEvent.incompleteBlockInput]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
|
|
102
|
+
[ChainEvent.incompletePayloadEnvelope]: {
|
|
103
|
+
payloadInput: PayloadEnvelopeInput;
|
|
104
|
+
peer: PeerIdStr;
|
|
105
|
+
source: BlockInputSource;
|
|
106
|
+
};
|
|
96
107
|
[ChainEvent.unknownEnvelopeBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
|
|
97
108
|
};
|
|
98
109
|
|
|
99
110
|
export type IChainEvents = ApiEvents & {
|
|
100
111
|
[ChainEvent.checkpoint]: (checkpoint: phase0.Checkpoint, state: IBeaconStateView) => void;
|
|
101
112
|
|
|
102
|
-
[ChainEvent.forkChoiceJustified]: (checkpoint:
|
|
103
|
-
[ChainEvent.forkChoiceFinalized]: (checkpoint:
|
|
113
|
+
[ChainEvent.forkChoiceJustified]: (checkpoint: CheckpointWithHex) => void;
|
|
114
|
+
[ChainEvent.forkChoiceFinalized]: (checkpoint: CheckpointWithHex) => void;
|
|
104
115
|
|
|
105
116
|
[ChainEvent.updateTargetCustodyGroupCount]: (targetGroupCount: number) => void;
|
|
106
117
|
|
|
@@ -116,6 +127,7 @@ export type IChainEvents = ApiEvents & {
|
|
|
116
127
|
[ChainEvent.envelopeUnknownBlock]: (data: ChainEventData[ChainEvent.envelopeUnknownBlock]) => void;
|
|
117
128
|
[ChainEvent.unknownBlockRoot]: (data: ChainEventData[ChainEvent.unknownBlockRoot]) => void;
|
|
118
129
|
[ChainEvent.incompleteBlockInput]: (data: ChainEventData[ChainEvent.incompleteBlockInput]) => void;
|
|
130
|
+
[ChainEvent.incompletePayloadEnvelope]: (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]) => void;
|
|
119
131
|
[ChainEvent.unknownEnvelopeBlockRoot]: (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]) => void;
|
|
120
132
|
};
|
|
121
133
|
|
|
@@ -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,12 +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 = getCheckpointPayloadStatus(config, state, justifiedCheckpoint.epoch);
|
|
109
|
-
|
|
110
|
-
// Determine finalized checkpoint payload status
|
|
111
|
-
const finalizedPayloadStatus = getCheckpointPayloadStatus(config, state, finalizedCheckpoint.epoch);
|
|
112
|
-
|
|
113
106
|
return new forkchoiceConstructor(
|
|
114
107
|
config,
|
|
115
108
|
|
|
@@ -119,8 +112,6 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
119
112
|
finalizedCheckpoint,
|
|
120
113
|
justifiedBalances,
|
|
121
114
|
justifiedBalancesGetter,
|
|
122
|
-
justifiedPayloadStatus,
|
|
123
|
-
finalizedPayloadStatus,
|
|
124
115
|
{
|
|
125
116
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
126
117
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
@@ -146,7 +137,9 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
146
137
|
|
|
147
138
|
...(isStatePostBellatrix(state) && state.isExecutionStateType && state.isMergeTransitionComplete
|
|
148
139
|
? {
|
|
149
|
-
executionPayloadBlockHash:
|
|
140
|
+
executionPayloadBlockHash: isStatePostGloas(state)
|
|
141
|
+
? toRootHex(state.latestBlockHash)
|
|
142
|
+
: toRootHex(state.latestExecutionPayloadHeader.blockHash),
|
|
150
143
|
// TODO GLOAS: executionPayloadNumber is not tracked in BeaconState post-gloas (EIP-7732 removed
|
|
151
144
|
// latestExecutionPayloadHeader). Using 0 as unavailable fallback until a solution is found.
|
|
152
145
|
executionPayloadNumber: isStatePostGloas(state) ? 0 : state.payloadBlockNumber,
|
|
@@ -155,7 +148,7 @@ export function initializeForkChoiceFromFinalizedState(
|
|
|
155
148
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
156
149
|
|
|
157
150
|
dataAvailabilityStatus: DataAvailabilityStatus.PreData,
|
|
158
|
-
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
151
|
+
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
159
152
|
parentBlockHash: isStatePostGloas(state) ? toRootHex(state.latestBlockHash) : null,
|
|
160
153
|
},
|
|
161
154
|
currentSlot
|
|
@@ -202,19 +195,12 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
202
195
|
|
|
203
196
|
const isForkPostGloas = computeEpochAtSlot(unfinalizedState.slot) >= config.GLOAS_FORK_EPOCH;
|
|
204
197
|
|
|
205
|
-
// For unfinalized state, use getCheckpointPayloadStatus to determine the correct status.
|
|
206
|
-
// It checks state.execution_payload_availability to determine EMPTY vs FULL.
|
|
207
|
-
const justifiedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, justifiedCheckpoint.epoch);
|
|
208
|
-
const finalizedPayloadStatus = getCheckpointPayloadStatus(config, unfinalizedState, finalizedCheckpoint.epoch);
|
|
209
|
-
|
|
210
198
|
const store = new ForkChoiceStore(
|
|
211
199
|
currentSlot,
|
|
212
200
|
justifiedCheckpoint,
|
|
213
201
|
finalizedCheckpoint,
|
|
214
202
|
justifiedBalances,
|
|
215
203
|
justifiedBalancesGetter,
|
|
216
|
-
justifiedPayloadStatus,
|
|
217
|
-
finalizedPayloadStatus,
|
|
218
204
|
{
|
|
219
205
|
onJustified: (cp) => emitter.emit(ChainEvent.forkChoiceJustified, cp),
|
|
220
206
|
onFinalized: (cp) => emitter.emit(ChainEvent.forkChoiceFinalized, cp),
|
|
@@ -243,7 +229,9 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
243
229
|
unfinalizedState.isExecutionStateType &&
|
|
244
230
|
unfinalizedState.isMergeTransitionComplete
|
|
245
231
|
? {
|
|
246
|
-
executionPayloadBlockHash:
|
|
232
|
+
executionPayloadBlockHash: isStatePostGloas(unfinalizedState)
|
|
233
|
+
? toRootHex(unfinalizedState.latestBlockHash)
|
|
234
|
+
: toRootHex(unfinalizedState.latestExecutionPayloadHeader.blockHash),
|
|
247
235
|
// TODO GLOAS: executionPayloadNumber is not tracked in BeaconState post-gloas (EIP-7732 removed
|
|
248
236
|
// latestExecutionPayloadHeader). Using 0 as unavailable fallback until a solution is found.
|
|
249
237
|
executionPayloadNumber: isStatePostGloas(unfinalizedState) ? 0 : unfinalizedState.payloadBlockNumber,
|
|
@@ -252,7 +240,7 @@ export function initializeForkChoiceFromUnfinalizedState(
|
|
|
252
240
|
: {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
|
|
253
241
|
|
|
254
242
|
dataAvailabilityStatus: DataAvailabilityStatus.PreData,
|
|
255
|
-
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
243
|
+
payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL,
|
|
256
244
|
parentBlockHash: isStatePostGloas(unfinalizedState) ? toRootHex(unfinalizedState.latestBlockHash) : null,
|
|
257
245
|
};
|
|
258
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<{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
-
import {
|
|
3
|
+
import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
|
|
4
4
|
import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostBellatrix} from "@lodestar/params";
|
|
5
5
|
import {
|
|
6
6
|
IBeaconStateView,
|
|
@@ -8,8 +8,9 @@ import {
|
|
|
8
8
|
computeEpochAtSlot,
|
|
9
9
|
computeTimeAtSlot,
|
|
10
10
|
isStatePostBellatrix,
|
|
11
|
+
isStatePostGloas,
|
|
11
12
|
} from "@lodestar/state-transition";
|
|
12
|
-
import {Slot} from "@lodestar/types";
|
|
13
|
+
import {Bytes32, Slot, electra} from "@lodestar/types";
|
|
13
14
|
import {Logger, fromHex, isErrorAborted, sleep} from "@lodestar/utils";
|
|
14
15
|
import {GENESIS_SLOT, ZERO_HASH_HEX} from "../constants/constants.js";
|
|
15
16
|
import {BuilderStatus} from "../execution/builder/http.js";
|
|
@@ -81,6 +82,8 @@ export class PrepareNextSlotScheduler {
|
|
|
81
82
|
// calling updateHead() here before we produce a block to reduce reorg possibility
|
|
82
83
|
const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
|
|
83
84
|
const {slot: headSlot, blockRoot: headRoot} = headBlock;
|
|
85
|
+
// may be updated below if we predict a proposer-boost-reorg
|
|
86
|
+
let updatedHead = headBlock;
|
|
84
87
|
|
|
85
88
|
// PS: previously this was comparing slots, but that gave no leway on the skipped
|
|
86
89
|
// slots on epoch bounday. Making it more fluid.
|
|
@@ -123,7 +126,6 @@ export class PrepareNextSlotScheduler {
|
|
|
123
126
|
const proposerIndex = prepareState.getBeaconProposer(prepareSlot);
|
|
124
127
|
const feeRecipient = this.chain.beaconProposerCache.get(proposerIndex);
|
|
125
128
|
let updatedPrepareState = prepareState;
|
|
126
|
-
let updatedHeadRoot = headRoot;
|
|
127
129
|
|
|
128
130
|
if (feeRecipient) {
|
|
129
131
|
// If we are proposing next slot, we need to predict if we can proposer-boost-reorg or not
|
|
@@ -146,7 +148,7 @@ export class PrepareNextSlotScheduler {
|
|
|
146
148
|
{dontTransferCache: !isEpochTransition},
|
|
147
149
|
RegenCaller.predictProposerHead
|
|
148
150
|
);
|
|
149
|
-
|
|
151
|
+
updatedHead = proposerHead;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
// Update the builder status, if enabled shoot an api call to check status
|
|
@@ -156,29 +158,56 @@ export class PrepareNextSlotScheduler {
|
|
|
156
158
|
this.logger.error("Builder disabled as the check status api failed", {prepareSlot}, e as Error);
|
|
157
159
|
});
|
|
158
160
|
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!isStatePostBellatrix(updatedPrepareState)) {
|
|
164
|
+
throw new Error("Expected Bellatrix state for payload attributes");
|
|
165
|
+
}
|
|
159
166
|
|
|
167
|
+
let parentBlockHash: Bytes32;
|
|
168
|
+
let isExtendingPayload = false;
|
|
169
|
+
if (isStatePostGloas(updatedPrepareState)) {
|
|
170
|
+
isExtendingPayload = this.chain.forkChoice.shouldExtendPayload(updatedHead.blockRoot);
|
|
171
|
+
parentBlockHash = isExtendingPayload
|
|
172
|
+
? updatedPrepareState.latestExecutionPayloadBid.blockHash
|
|
173
|
+
: updatedPrepareState.latestExecutionPayloadBid.parentBlockHash;
|
|
174
|
+
} else {
|
|
175
|
+
parentBlockHash = updatedPrepareState.latestExecutionPayloadHeader.blockHash;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Reused by the SSE emit below to avoid a second DB lookup on cache miss
|
|
179
|
+
let parentExecutionRequests: electra.ExecutionRequests | undefined;
|
|
180
|
+
|
|
181
|
+
if (feeRecipient) {
|
|
160
182
|
const preparationTime =
|
|
161
183
|
computeTimeAtSlot(this.config, prepareSlot, this.chain.genesisTime) - Date.now() / 1000;
|
|
162
184
|
this.metrics?.blockPayload.payloadAdvancePrepTime.observe(preparationTime);
|
|
163
|
-
if (!isStatePostBellatrix(updatedPrepareState)) {
|
|
164
|
-
throw new Error("Expected Bellatrix state for payload preparation");
|
|
165
|
-
}
|
|
166
185
|
|
|
167
186
|
const safeBlockHash = getSafeExecutionBlockHash(this.chain.forkChoice);
|
|
168
187
|
const finalizedBlockHash =
|
|
169
188
|
this.chain.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
|
|
189
|
+
|
|
190
|
+
if (isExtendingPayload) {
|
|
191
|
+
parentExecutionRequests = await this.chain.getParentExecutionRequests(
|
|
192
|
+
updatedHead.slot,
|
|
193
|
+
updatedHead.blockRoot
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
170
197
|
// awaiting here instead of throwing an async call because there is no other task
|
|
171
|
-
// left for scheduler and this gives nice
|
|
198
|
+
// left for scheduler and this gives nice semantics to catch and log errors in the
|
|
172
199
|
// try/catch wrapper here.
|
|
173
200
|
await prepareExecutionPayload(
|
|
174
201
|
this.chain,
|
|
175
202
|
this.logger,
|
|
176
203
|
fork as ForkPostBellatrix, // State is of execution type
|
|
177
|
-
fromHex(
|
|
204
|
+
fromHex(updatedHead.blockRoot),
|
|
205
|
+
parentBlockHash,
|
|
178
206
|
safeBlockHash,
|
|
179
207
|
finalizedBlockHash,
|
|
180
208
|
updatedPrepareState,
|
|
181
|
-
feeRecipient
|
|
209
|
+
feeRecipient,
|
|
210
|
+
parentExecutionRequests
|
|
182
211
|
);
|
|
183
212
|
this.logger.verbose("PrepareNextSlotScheduler prepared new payload", {
|
|
184
213
|
prepareSlot,
|
|
@@ -187,24 +216,38 @@ export class PrepareNextSlotScheduler {
|
|
|
187
216
|
});
|
|
188
217
|
}
|
|
189
218
|
|
|
190
|
-
if (
|
|
191
|
-
|
|
219
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
220
|
+
// Cutoff = slot of the parent of the block we'll actually build on (post-reorg).
|
|
221
|
+
// Steady state: cache holds just 2 entries — head (parent for next-slot production)
|
|
222
|
+
// and head.parent (proposer-boost-reorg fallback). Anything older is evicted.
|
|
223
|
+
const updatedHeadParent = this.chain.forkChoice.getBlockHexDefaultStatus(updatedHead.parentRoot);
|
|
224
|
+
if (updatedHeadParent) {
|
|
225
|
+
this.chain.seenPayloadEnvelopeInputCache.pruneBelow(updatedHeadParent.slot);
|
|
226
|
+
}
|
|
192
227
|
}
|
|
193
228
|
|
|
194
229
|
this.computeStateHashTreeRoot(updatedPrepareState, isEpochTransition);
|
|
195
230
|
|
|
196
|
-
// If emitPayloadAttributes is true emit a SSE payloadAttributes event
|
|
231
|
+
// If emitPayloadAttributes is true emit a SSE payloadAttributes event for
|
|
232
|
+
// every slot. Without the flag, only emit the event if we are proposing in the next slot.
|
|
197
233
|
if (
|
|
198
|
-
this.chain.opts.emitPayloadAttributes === true &&
|
|
234
|
+
(feeRecipient || this.chain.opts.emitPayloadAttributes === true) &&
|
|
199
235
|
this.chain.emitter.listenerCount(routes.events.EventType.payloadAttributes)
|
|
200
236
|
) {
|
|
237
|
+
// if we didn't fetch above (not proposing), SSE still needs it here
|
|
238
|
+
if (!parentExecutionRequests && isExtendingPayload) {
|
|
239
|
+
parentExecutionRequests = await this.chain.getParentExecutionRequests(
|
|
240
|
+
updatedHead.slot,
|
|
241
|
+
updatedHead.blockRoot
|
|
242
|
+
);
|
|
243
|
+
}
|
|
201
244
|
const data = getPayloadAttributesForSSE(fork as ForkPostBellatrix, this.chain, {
|
|
202
245
|
prepareState: updatedPrepareState,
|
|
203
246
|
prepareSlot,
|
|
204
|
-
parentBlockRoot: fromHex(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
247
|
+
parentBlockRoot: fromHex(updatedHead.blockRoot),
|
|
248
|
+
parentBlockHash,
|
|
249
|
+
feeRecipient: feeRecipient ?? "0x0000000000000000000000000000000000000000",
|
|
250
|
+
parentExecutionRequests,
|
|
208
251
|
});
|
|
209
252
|
this.chain.emitter.emit(routes.events.EventType.payloadAttributes, {data, version: fork});
|
|
210
253
|
}
|
|
@@ -217,11 +260,7 @@ export class PrepareNextSlotScheduler {
|
|
|
217
260
|
// + if next slot is a skipped slot, it'd help getting target checkpoint state faster to validate attestations
|
|
218
261
|
if (isEpochTransition) {
|
|
219
262
|
this.metrics?.precomputeNextEpochTransition.count.inc({result: "success"}, 1);
|
|
220
|
-
|
|
221
|
-
// Pre-Gloas: payloadStatus is always FULL → payloadPresent = true
|
|
222
|
-
// Post-Gloas: FULL → true, EMPTY → false, PENDING → false (conservative, treat as block state)
|
|
223
|
-
const payloadPresent = headBlock.payloadStatus === PayloadStatus.FULL;
|
|
224
|
-
const previousHits = this.chain.regen.updatePreComputedCheckpoint(headRoot, nextEpoch, payloadPresent);
|
|
263
|
+
const previousHits = this.chain.regen.updatePreComputedCheckpoint(headRoot, nextEpoch);
|
|
225
264
|
if (previousHits === 0) {
|
|
226
265
|
this.metrics?.precomputeNextEpochTransition.waste.inc();
|
|
227
266
|
}
|