Skip to content
Open
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
7 changes: 1 addition & 6 deletions packages/beacon-node/src/chain/blocks/importBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,18 +124,13 @@ export async function importBlock(
executionStatus = parentBlock.executionStatus;
}

// getBeaconProposerOrNull will return null if head state is more than one epoch away
// from block slot. We skip proposer boost canonical check as we cannot determine the canonical proposer
const expectedProposerIndex: number | null = this.getHeadState().getBeaconProposerOrNull(blockSlot);

const blockSummary = this.forkChoice.onBlock(
block.message,
postState,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
expectedProposerIndex
dataAvailabilityStatus
);

// This adds the state necessary to process the next block
Expand Down
7 changes: 2 additions & 5 deletions packages/beacon-node/test/spec/utils/gossipValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,6 @@ export async function runGossipValidationTest(
}

const postState = computePostState(parentState, signedBlock, fork);
const expectedProposerIndex: number | null = chain.getHeadState().getBeaconProposerOrNull(slot);

if (blockEntry.failed) {
// payload_status === "VALID" (filtered above)
Expand All @@ -487,8 +486,7 @@ export async function runGossipValidationTest(
0,
slot,
ExecutionStatus.Valid,
getDataAvailabilityStatusForFork(fork),
expectedProposerIndex
getDataAvailabilityStatusForFork(fork)
);
blockStatesByRoot.set(blockRootHex, postState);
continue;
Expand All @@ -503,8 +501,7 @@ export async function runGossipValidationTest(
0,
slot,
ExecutionStatus.Syncing,
getDataAvailabilityStatusForFork(fork),
expectedProposerIndex
getDataAvailabilityStatusForFork(fork)
);
blockStatesByRoot.set(blockRootHex, postState);
invalidateImportedBlock(chain, blockRootHex, parentRootHex);
Expand Down
106 changes: 19 additions & 87 deletions packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,15 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
forkChoice.onBlock(
orphanedBlock.message,
orphanedState,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
let head = forkChoice.getHead();
expect(head.slot).toBe(orphanedBlock.message.slot);
Expand All @@ -127,8 +125,7 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
// tie break condition causes head to be orphaned block (based on hex root comparison)
head = forkChoice.getHead();
Expand All @@ -139,8 +136,7 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
head = forkChoice.getHead();
// without vote, head gets stuck at orphaned block
Expand Down Expand Up @@ -200,75 +196,19 @@ describe("LodestarForkChoice", () => {
const currentSlot = 128;
forkChoice.updateTime(currentSlot);

forkChoice.onBlock(
block08.message,
state08,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
);
forkChoice.onBlock(
block12.message,
state12,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
);
forkChoice.onBlock(
block16.message,
state16,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
);
forkChoice.onBlock(
block20.message,
state20,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
);
forkChoice.onBlock(
block24.message,
state24,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
);
forkChoice.onBlock(
block28.message,
state28,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
);
forkChoice.onBlock(block08.message, state08, blockDelaySec, currentSlot, executionStatus, dataAvailabilityStatus);
forkChoice.onBlock(block12.message, state12, blockDelaySec, currentSlot, executionStatus, dataAvailabilityStatus);
forkChoice.onBlock(block16.message, state16, blockDelaySec, currentSlot, executionStatus, dataAvailabilityStatus);
forkChoice.onBlock(block20.message, state20, blockDelaySec, currentSlot, executionStatus, dataAvailabilityStatus);
forkChoice.onBlock(block24.message, state24, blockDelaySec, currentSlot, executionStatus, dataAvailabilityStatus);
forkChoice.onBlock(block28.message, state28, blockDelaySec, currentSlot, executionStatus, dataAvailabilityStatus);
expect(forkChoice.getAllAncestorBlocks(hashBlock(block16.message), PayloadStatus.FULL)).toHaveLength(4);
expect(forkChoice.getAllAncestorBlocks(hashBlock(block24.message), PayloadStatus.FULL)).toHaveLength(6);
expect(forkChoice.getBlockHexDefaultStatus(hashBlock(block08.message))).not.toBeNull();
expect(forkChoice.getBlockHexDefaultStatus(hashBlock(block12.message))).not.toBeNull();
expect(forkChoice.hasBlockHex(hashBlock(block08.message))).toBe(true);
expect(forkChoice.hasBlockHex(hashBlock(block12.message))).toBe(true);
forkChoice.onBlock(
block32.message,
state32,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
);
forkChoice.onBlock(block32.message, state32, blockDelaySec, currentSlot, executionStatus, dataAvailabilityStatus);
forkChoice.prune(hashBlock(block16.message));
expect(forkChoice.getAllAncestorBlocks(hashBlock(block16.message), PayloadStatus.FULL).length).toBeWithMessage(
1,
Expand Down Expand Up @@ -304,35 +244,31 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
forkChoice.onBlock(
orphanedBlock.message,
orphanedState,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
forkChoice.onBlock(
parentBlock.message,
parentState,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
forkChoice.onBlock(
childBlock.message,
childState,
blockDelaySec,
currentSlot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);
const childBlockRoot = toHexString(ssz.phase0.BeaconBlock.hashTreeRoot(childBlock.message));
// the old way to get non canonical blocks
Expand Down Expand Up @@ -379,8 +315,7 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
blockW.message.slot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);

// X
Expand All @@ -392,8 +327,7 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
blockX.message.slot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);

// Y, same epoch to X
Expand All @@ -405,8 +339,7 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
blockY.message.slot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);

// Y and Z are candidates for new head, make more attestations on Y
Expand Down Expand Up @@ -447,8 +380,7 @@ describe("LodestarForkChoice", () => {
blockDelaySec,
blockZ.message.slot,
executionStatus,
dataAvailabilityStatus,
null
dataAvailabilityStatus
);

const head = forkChoice.updateHead();
Expand Down
18 changes: 6 additions & 12 deletions packages/fork-choice/src/forkChoice/forkChoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,7 @@ export class ForkChoice implements IForkChoice {
blockDelaySec: number,
currentSlot: Slot,
executionStatus: BlockExecutionStatus,
dataAvailabilityStatus: DataAvailabilityStatus,
// The expected proposer index on the canonical chain we are following.
// Calculated by our head state. We use it as part of the proposer
// boost decision making. No boost will be set if this is null.
expectedProposerIndex: ValidatorIndex | null
dataAvailabilityStatus: DataAvailabilityStatus
): ProtoBlock {
const {parentRoot, slot} = block;
const parentRootHex = toRootHex(parentRoot);
Expand Down Expand Up @@ -711,8 +707,6 @@ export class ForkChoice implements IForkChoice {
isTimely &&
// only boost the first block we see
this.proposerBoostRoot === null &&
expectedProposerIndex !== null &&
block.proposerIndex === expectedProposerIndex &&
this.isProposerBoostSameDependentRoot(this.head.blockRoot, parentRootHex);
// Candidate boost root used for protoArray.onBlock's best-child weighting. Committed to the
// store only after the insertion succeeds.
Expand Down Expand Up @@ -1505,11 +1499,11 @@ export class ForkChoice implements IForkChoice {
}

/**
* Spec: phase0/fork-choice.md#update_proposer_boost_root (`is_same_dependent_root` condition,
* consensus-specs #5306). Proposer boost is only granted when the imported block shares the same
* proposer-shuffling dependent root for the current epoch as the canonical head computed before
* the block was imported. This withholds the boost from a block built on a different shuffling
* branch than the head.
* Spec: phase0/fork-choice.md#update_proposer_boost_root (`is_same_dependent_root` condition, added in
* https://github.com/ethereum/consensus-specs/pull/5306). Proposer boost is only granted when the imported
* block shares the same proposer-shuffling dependent root for the current epoch as the canonical head
* computed before the block was imported. This withholds the boost from a block built on a different
* shuffling branch than the head.
*
* The block is not yet in the proto-array when this runs, so its dependent root is traced from
* its parent
Expand Down
14 changes: 2 additions & 12 deletions packages/fork-choice/src/forkChoice/interface.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import {DataAvailabilityStatus, EffectiveBalanceIncrements, IBeaconStateView} from "@lodestar/state-transition";
import {
AttesterSlashing,
BeaconBlock,
Epoch,
IndexedAttestation,
Root,
RootHex,
Slot,
ValidatorIndex,
} from "@lodestar/types";
import {AttesterSlashing, BeaconBlock, Epoch, IndexedAttestation, Root, RootHex, Slot} from "@lodestar/types";
import {
BlockExecutionStatus,
LVHExecResponse,
Expand Down Expand Up @@ -160,8 +151,7 @@ export interface IForkChoice {
blockDelaySec: number,
currentSlot: Slot,
executionStatus: BlockExecutionStatus,
dataAvailabilityStatus: DataAvailabilityStatus,
expectedProposerIndex: ValidatorIndex | null
dataAvailabilityStatus: DataAvailabilityStatus
): ProtoBlock;
/**
* Register `attestation` with the fork choice DAG so that it may influence future calls to `getHead`.
Expand Down
8 changes: 0 additions & 8 deletions packages/state-transition/src/stateView/beaconStateView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,14 +515,6 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
return this.cachedState.epochCtx.getBeaconProposer(slot);
}

getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null {
try {
return this.cachedState.epochCtx.getBeaconProposer(slot);
} catch {
return null;
}
}

computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader} {
return computeAnchorCheckpoint(this.config, this.cachedState);
}
Expand Down
1 change: 0 additions & 1 deletion packages/state-transition/src/stateView/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ export interface IBeaconStateView {
currentProposers: ValidatorIndex[];
nextProposers: ValidatorIndex[];
getBeaconProposer(slot: Slot): ValidatorIndex;
getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null;

// Validators and balances
effectiveBalanceIncrements: EffectiveBalanceIncrements;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
private readonly _getBeaconCommitteeCountPerSlot = new Map<Epoch, number>();
private readonly _getShufflingDecisionRoot = new Map<Epoch, RootHex>();
private readonly _getBeaconProposer = new Map<Slot, ValidatorIndex>();
// getBeaconProposerOrNull can return null, so use .has() to distinguish "not cached" from "cached null"
private readonly _getBeaconProposerOrNull = new Map<Slot, ValidatorIndex | null>();
private readonly _getValidator = new Map<ValidatorIndex, phase0.Validator>();
private readonly _getBalance = new Map<number, number>();
private readonly _getIndexedSyncCommitteeAtEpoch = new Map<Epoch, SyncCommitteeCache>();
Expand Down Expand Up @@ -411,14 +409,6 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
return cached;
}

getBeaconProposerOrNull(slot: Slot): ValidatorIndex | null {
if (!this._getBeaconProposerOrNull.has(slot)) {
this._getBeaconProposerOrNull.set(slot, this.binding.getBeaconProposerOrNull(slot));
}
// biome-ignore lint/style/noNonNullAssertion: has() check guarantees a value
return this._getBeaconProposerOrNull.get(slot)!;
}

// Validators and balances

get effectiveBalanceIncrements(): EffectiveBalanceIncrements {
Expand Down
Loading