Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: eip-6110 deprecate eth1 data poll #7414

Merged
merged 6 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map";
import {CompositeTypeAny, TreeView, Type} from "@chainsafe/ssz";
import {BeaconConfig} from "@lodestar/config";
import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params";
import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH, isForkPostElectra} from "@lodestar/params";
import {
BeaconStateAllForks,
BeaconStateElectra,
CachedBeaconStateAllForks,
EffectiveBalanceIncrements,
EpochShuffling,
Expand Down Expand Up @@ -350,6 +351,16 @@ export class BeaconChain implements IBeaconChain {
this.serializedCache = new SerializedCache();

this.archiver = new Archiver(db, this, logger, signal, opts, metrics);

// Stop polling eth1 data if anchor state is in Electra AND deposit_requests_start_index is reached
const anchorStateFork = this.config.getForkName(anchorState.slot);
if (isForkPostElectra(anchorStateFork)) {
const {eth1DepositIndex, depositRequestsStartIndex} = anchorState as BeaconStateElectra;
if (eth1DepositIndex === Number(depositRequestsStartIndex)) {
this.eth1.stopPollingEth1Data();
}
}

// always run PrepareNextSlotScheduler except for fork_choice spec tests
if (!opts?.disablePrepareNextSlot) {
new PrepareNextSlotScheduler(this, this.config, metrics, this.logger, signal);
Expand Down Expand Up @@ -1143,16 +1154,6 @@ export class BeaconChain implements IBeaconChain {
if (headState === null) {
this.logger.verbose("Head state is null");
}

// TODO-Electra: Deprecating eth1Data poll requires a check on a finalized checkpoint state.
// Will resolve this later
// if (cpEpoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity)) {
// // finalizedState can be safely casted to Electra state since cp is already post-Electra
// if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositRequestsStartIndex) {
// // Signal eth1 to stop polling eth1Data
// this.eth1.stopPollingEth1Data();
// }
// }
}

async updateBeaconProposerData(epoch: Epoch, proposers: ProposerPreparationData[]): Promise<void> {
Expand Down
30 changes: 29 additions & 1 deletion packages/beacon-node/src/chain/prepareNextSlot.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {routes} from "@lodestar/api";
import {ChainForkConfig} from "@lodestar/config";
import {ForkExecution, ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params";
import {ForkExecution, ForkSeq, SLOTS_PER_EPOCH, isForkPostElectra} from "@lodestar/params";
import {
BeaconStateElectra,
CachedBeaconStateAllForks,
CachedBeaconStateExecutions,
StateHashTreeRootSource,
Expand Down Expand Up @@ -214,6 +215,10 @@ export class PrepareNextSlotScheduler {
this.metrics?.precomputeNextEpochTransition.waste.inc();
}
this.metrics?.precomputeNextEpochTransition.hits.set(previousHits ?? 0);

// Check if we can stop polling eth1 data
this.stopEth1Polling();

this.logger.verbose("Completed PrepareNextSlotScheduler epoch transition", {
nextEpoch,
headSlot,
Expand All @@ -240,4 +245,27 @@ export class PrepareNextSlotScheduler {
state.hashTreeRoot();
hashTreeRootTimer?.();
}

/**
* Stop eth1 data polling after eth1_deposit_index has reached deposit_requests_start_index in Electra as described in EIP-6110
*/
stopEth1Polling(): void {
// Only continue if eth1 is still polling and finalized checkpoint is in Electra. State regen is expensive
if (this.chain.eth1.isPollingEth1Data()) {
const finalizedCheckpoint = this.chain.forkChoice.getFinalizedCheckpoint();
const checkpointFork = this.config.getForkInfoAtEpoch(finalizedCheckpoint.epoch).name;

if (isForkPostElectra(checkpointFork)) {
const finalizedState = this.chain.getStateByCheckpoint(finalizedCheckpoint)?.state;

if (
finalizedState !== undefined &&
finalizedState.eth1DepositIndex === Number((finalizedState as BeaconStateElectra).depositRequestsStartIndex)
) {
// Signal eth1 to stop polling eth1Data
this.chain.eth1.stopPollingEth1Data();
}
}
}
}
}
6 changes: 4 additions & 2 deletions packages/beacon-node/src/eth1/eth1DepositDataTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ export class Eth1DepositDataTracker {
this.depositsCache = new Eth1DepositsCache(opts, config, db);
this.eth1DataCache = new Eth1DataCache(config, db);
this.eth1FollowDistance = config.ETH1_FOLLOW_DISTANCE;
// TODO Electra: fix scenario where node starts post-Electra and `stopPolling` will always be false
ensi321 marked this conversation as resolved.
Show resolved Hide resolved
this.stopPolling = false;

this.forcedEth1DataVote = opts.forcedEth1DataVote
Expand Down Expand Up @@ -118,7 +117,10 @@ export class Eth1DepositDataTracker {
}
}

// TODO Electra: Figure out how an elegant way to stop eth1data polling
isPollingEth1Data(): boolean {
return !this.stopPolling;
}

stopPollingEth1Data(): void {
this.stopPolling = true;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/beacon-node/src/eth1/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ export class Eth1ForBlockProduction implements IEth1ForBlockProduction {
this.eth1MergeBlockTracker.startPollingMergeBlock();
}

isPollingEth1Data(): boolean {
return this.eth1DepositDataTracker?.isPollingEth1Data() ?? false;
}

stopPollingEth1Data(): void {
this.eth1DepositDataTracker?.stopPollingEth1Data();
}
Expand Down Expand Up @@ -139,6 +143,10 @@ export class Eth1ForBlockProductionDisabled implements IEth1ForBlockProduction {
return null;
}

isPollingEth1Data(): boolean {
return false;
}

startPollingMergeBlock(): void {
// Ignore
}
Expand Down
2 changes: 2 additions & 0 deletions packages/beacon-node/src/eth1/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export interface IEth1ForBlockProduction {
*/
startPollingMergeBlock(): void;

isPollingEth1Data(): boolean;

/**
* Should stop polling eth1Data after a Electra block is finalized AND deposit_requests_start_index is reached
*/
Expand Down
12 changes: 10 additions & 2 deletions packages/beacon-node/src/eth1/utils/eth1Vote.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ChainForkConfig} from "@lodestar/config";
import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params";
import {BeaconStateAllForks, computeTimeAtSlot} from "@lodestar/state-transition";
import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH, isForkPostElectra} from "@lodestar/params";
import {BeaconStateAllForks, BeaconStateElectra, computeTimeAtSlot} from "@lodestar/state-transition";
import {RootHex, phase0} from "@lodestar/types";
import {toRootHex} from "@lodestar/utils";

Expand All @@ -15,6 +15,14 @@ export async function getEth1VotesToConsider(
state: BeaconStateAllForks,
eth1DataGetter: Eth1DataGetter
): Promise<phase0.Eth1Data[]> {
const fork = config.getForkName(state.slot);
if (isForkPostElectra(fork)) {
const {eth1DepositIndex, depositRequestsStartIndex} = state as BeaconStateElectra;
if (eth1DepositIndex === Number(depositRequestsStartIndex)) {
return state.eth1DataVotes.getAllReadonly();
}
}

const periodStart = votingPeriodStartTime(config, state);
const {SECONDS_PER_ETH1_BLOCK, ETH1_FOLLOW_DISTANCE} = config;

Expand Down
Loading