Skip to content

Commit 48fd2e1

Browse files
committed
feat: enhance importBlock() for gloas
1 parent dc9b13e commit 48fd2e1

3 files changed

Lines changed: 38 additions & 18 deletions

File tree

packages/beacon-node/src/chain/blocks/importBlock.ts

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export async function importBlock(
8484
fullyVerifiedBlock: FullyVerifiedBlock,
8585
opts: ImportBlockOpts
8686
): Promise<void> {
87-
const {blockInput, postState, parentBlockSlot, executionStatus, dataAvailabilityStatus, indexedAttestations} =
87+
const {blockInput, postBlockState, parentBlockSlot, executionStatus, dataAvailabilityStatus, indexedAttestations} =
8888
fullyVerifiedBlock;
8989
const block = blockInput.getBlock();
9090
const source = blockInput.getBlockSource();
@@ -96,7 +96,7 @@ export async function importBlock(
9696
const blockEpoch = computeEpochAtSlot(blockSlot);
9797
const prevFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
9898
const blockDelaySec =
99-
fullyVerifiedBlock.seenTimestampSec - computeTimeAtSlot(this.config, blockSlot, postState.genesisTime);
99+
fullyVerifiedBlock.seenTimestampSec - computeTimeAtSlot(this.config, blockSlot, postBlockState.genesisTime);
100100
const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000);
101101
const fork = this.config.getForkSeq(blockSlot);
102102

@@ -119,10 +119,10 @@ export async function importBlock(
119119
// 2. Import block to fork choice
120120

121121
// Should compute checkpoint balances before forkchoice.onBlock
122-
this.checkpointBalancesCache.processState(blockRootHex, postState);
122+
this.checkpointBalancesCache.processState(blockRootHex, postBlockState);
123123
const blockSummary = this.forkChoice.onBlock(
124124
block.message,
125-
postState,
125+
postBlockState,
126126
blockDelaySec,
127127
currentSlot,
128128
executionStatus,
@@ -135,7 +135,7 @@ export async function importBlock(
135135
// Post-Gloas: blockSummary.payloadStatus is always PENDING, so payloadPresent = false (block state only, no payload processing yet)
136136
const payloadPresent = !isGloasBlock(blockSummary);
137137
// processState manages both block state and payload state variants together for memory/disk management
138-
this.regen.processBlockState(blockRootHex, postState);
138+
this.regen.processBlockState(blockRootHex, postBlockState);
139139

140140
// For Gloas blocks, create PayloadEnvelopeInput so it's available for later payload import
141141
if (fork >= ForkSeq.gloas) {
@@ -154,6 +154,23 @@ export async function importBlock(
154154
});
155155
}
156156

157+
// For Gloas blocks whose envelope was pre-verified during state transition (sync/batch path),
158+
// immediately transition the block to FULL status in fork choice and cache the payload state.
159+
// Mirrors steps 6–7 of importExecutionPayload, but reuses the already-computed postEnvelopeState.
160+
if (fullyVerifiedBlock.postEnvelopeState !== null) {
161+
// TODO GLOAS: this.unfinalizedPayloadEnvelopeWrites.push(payloadInput)
162+
// need a payloadInput in fullyVerifiedBlock
163+
const {postEnvelopeState} = fullyVerifiedBlock;
164+
this.regen.processPayloadState(postEnvelopeState);
165+
this.forkChoice.onExecutionPayload(
166+
blockRootHex,
167+
toRootHex(postEnvelopeState.latestBlockHash),
168+
// TODO GLOAS: this is not right but we don't need to track it as part of consensus spec, lighthouse also does not track it
169+
0,
170+
toRootHex(postEnvelopeState.hashTreeRoot())
171+
);
172+
}
173+
157174
this.metrics?.importBlock.bySource.inc({source: source.source});
158175
this.logger.verbose("Added block to forkchoice and state cache", {slot: blockSlot, root: blockRootHex});
159176

@@ -171,7 +188,7 @@ export async function importBlock(
171188
(opts.importAttestations !== AttestationImportOpt.Skip && blockEpoch >= currentEpoch - FORK_CHOICE_ATT_EPOCH_LIMIT)
172189
) {
173190
const attestations = block.message.body.attestations;
174-
const rootCache = new RootCache(postState);
191+
const rootCache = new RootCache(postBlockState);
175192
const invalidAttestationErrorsByCode = new Map<string, {error: Error; count: number}>();
176193

177194
const addAttestation = fork >= ForkSeq.electra ? addAttestationPostElectra : addAttestationPreElectra;
@@ -185,7 +202,7 @@ export async function importBlock(
185202
const attDataRoot = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(indexedAttestation.data));
186203
addAttestation.call(
187204
this,
188-
postState,
205+
postBlockState,
189206
target,
190207
attDataRoot,
191208
attestation as Attestation<ForkPostElectra>,
@@ -300,7 +317,7 @@ export async function importBlock(
300317

301318
if (newHead.blockRoot !== oldHead.blockRoot) {
302319
// Set head state as strong reference
303-
this.regen.updateHeadState(newHead, postState);
320+
this.regen.updateHeadState(newHead, postBlockState);
304321

305322
try {
306323
this.emitter.emit(routes.events.EventType.head, {
@@ -372,7 +389,7 @@ export async function importBlock(
372389
try {
373390
this.lightClientServer?.onImportBlockHead(
374391
block.message as BeaconBlock<ForkPostAltair>,
375-
postState,
392+
postBlockState,
376393
parentBlockSlot
377394
);
378395
} catch (e) {
@@ -393,11 +410,11 @@ export async function importBlock(
393410
// and the block is weak and can potentially be reorged out.
394411
let shouldOverrideFcu = false;
395412

396-
if (blockSlot >= currentSlot && postState.isExecutionStateType) {
413+
if (blockSlot >= currentSlot && postBlockState.isExecutionStateType) {
397414
let notOverrideFcuReason = NotReorgedReason.Unknown;
398415
const proposalSlot = blockSlot + 1;
399416
try {
400-
const proposerIndex = postState.getBeaconProposer(proposalSlot);
417+
const proposerIndex = postBlockState.getBeaconProposer(proposalSlot);
401418
const feeRecipient = this.beaconProposerCache.get(proposerIndex);
402419

403420
if (feeRecipient) {
@@ -477,20 +494,20 @@ export async function importBlock(
477494
}
478495
}
479496

480-
if (!postState.isStateValidatorsNodesPopulated()) {
481-
this.logger.verbose("After importBlock caching postState without SSZ cache", {slot: postState.slot});
497+
if (!postBlockState.isStateValidatorsNodesPopulated()) {
498+
this.logger.verbose("After importBlock caching postBlockState without SSZ cache", {slot: postBlockState.slot});
482499
}
483500

484501
// Cache shufflings when crossing an epoch boundary
485502
const parentEpoch = computeEpochAtSlot(parentBlockSlot);
486503
if (parentEpoch < blockEpoch) {
487-
this.shufflingCache.processState(postState);
504+
this.shufflingCache.processState(postBlockState);
488505
this.logger.verbose("Processed shuffling for next epoch", {parentEpoch, blockEpoch, slot: blockSlot});
489506
}
490507

491508
if (blockSlot % SLOTS_PER_EPOCH === 0) {
492509
// Cache state to preserve epoch transition work
493-
const checkpointState = postState;
510+
const checkpointState = postBlockState;
494511
const cp = getCheckpointFromState(checkpointState);
495512
this.regen.addCheckpointState(cp, checkpointState, payloadPresent);
496513
// consumers should not mutate state ever
@@ -584,7 +601,7 @@ export async function importBlock(
584601
this.validatorMonitor?.registerSyncAggregateInBlock(
585602
blockEpoch,
586603
(block as altair.SignedBeaconBlock).message.body.syncAggregate,
587-
fullyVerifiedBlock.postState.currentSyncCommitteeIndexed.validatorIndices
604+
fullyVerifiedBlock.postBlockState.currentSyncCommitteeIndexed.validatorIndices
588605
);
589606
}
590607

packages/beacon-node/src/chain/blocks/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export async function processBlocks(
8787
proposerBalanceDeltas,
8888
segmentExecStatus,
8989
indexedAttestationsByBlock,
90+
postEnvelopeStates,
9091
} = await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, envelopes, opts);
9192

9293
// If segmentExecStatus has lvhForkchoice then, the entire segment should be invalid
@@ -102,7 +103,8 @@ export async function processBlocks(
102103
const fullyVerifiedBlocks = relevantBlocks.map(
103104
(block, i): FullyVerifiedBlock => ({
104105
blockInput: block,
105-
postState: postBlockStates[i],
106+
postBlockState: postBlockStates[i],
107+
postEnvelopeState: postEnvelopeStates.get(block.getBlock().message.slot) ?? null,
106108
parentBlockSlot: parentSlots[i],
107109
executionStatus: executionStatuses[i],
108110
// start supporting optimistic syncing/processing

packages/beacon-node/src/chain/blocks/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ export type ImportBlockOpts = {
9393
*/
9494
export type FullyVerifiedBlock = {
9595
blockInput: IBlockInput;
96-
postState: IBeaconStateView;
96+
postBlockState: IBeaconStateView;
97+
postEnvelopeState: IBeaconStateView | null;
9798
parentBlockSlot: Slot;
9899
proposerBalanceDelta: number;
99100
/**

0 commit comments

Comments
 (0)