diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 309a5c29a6b0..d2317de42c5e 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -103,11 +103,17 @@ describe("getAttestationsForBlock", () => { ); } + let totalBalance = 0; + for (let i = 0; i < originalState.epochCtx.effectiveBalanceIncrements.length; i++) { + totalBalance += originalState.epochCtx.effectiveBalanceIncrements[i]; + } + const fcStore: IForkChoiceStore = { currentSlot: originalState.slot, justified: { checkpoint: {...justifiedCheckpoint, rootHex: toHexString(justifiedCheckpoint.root)}, balances: originalState.epochCtx.effectiveBalanceIncrements, + totalBalance, }, unrealizedJustified: { checkpoint: {...justifiedCheckpoint, rootHex: toHexString(justifiedCheckpoint.root)}, diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index 55587f6e9375..891cda50f175 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -30,8 +30,12 @@ type Types = Record>; // const sszStatic = - (skippedTypes?: string[]) => + (skippedFork: string, skippedTypes?: string[]) => (fork: ForkName, typeName: string, testSuite: string, testSuiteDirpath: string): void => { + if (fork === skippedFork) { + return; + } + // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts if (skippedTypes?.includes(typeName)) { return; @@ -71,6 +75,7 @@ specTestIterator(path.join(ethereumConsensusSpecsTests.outputDir, "tests", ACTIV // eslint-disable-next-line @typescript-eslint/naming-convention ssz_static: { type: RunnerType.custom, - fn: sszStatic(), + // starting from v1.4.0-beta.6, there is "whisk" fork in ssz_static tests but we ignore them + fn: sszStatic("whisk"), }, }); diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index 20125520321d..f47471c15c56 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.4.0-beta.5", + specVersion: "v1.4.0-beta.6", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 396146b193c7..b482bc4c76e4 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -201,7 +201,7 @@ export class ForkChoice implements IForkChoice { if (this.opts?.proposerBoostEnabled && this.proposerBoostRoot) { const proposerBoostScore = this.justifiedProposerBoostScore ?? - computeProposerBoostScoreFromBalances(this.fcStore.justified.balances, { + getProposerScore(this.fcStore.justified.totalBalance, { slotsPerEpoch: SLOTS_PER_EPOCH, proposerScoreBoost: this.config.PROPOSER_SCORE_BOOST, }); @@ -1260,32 +1260,10 @@ export function assertValidTerminalPowBlock( } } -function computeProposerBoostScore( - { - justifiedTotalActiveBalanceByIncrement, - justifiedActiveValidators, - }: {justifiedTotalActiveBalanceByIncrement: number; justifiedActiveValidators: number}, +export function getProposerScore( + justifiedTotalActiveBalanceByIncrement: number, config: {slotsPerEpoch: number; proposerScoreBoost: number} ): number { - const avgBalanceByIncrement = Math.floor(justifiedTotalActiveBalanceByIncrement / justifiedActiveValidators); - const committeeSize = Math.floor(justifiedActiveValidators / config.slotsPerEpoch); - const committeeWeight = committeeSize * avgBalanceByIncrement; - const proposerScore = Math.floor((committeeWeight * config.proposerScoreBoost) / 100); - return proposerScore; -} - -export function computeProposerBoostScoreFromBalances( - justifiedBalances: EffectiveBalanceIncrements, - config: {slotsPerEpoch: number; proposerScoreBoost: number} -): number { - let justifiedTotalActiveBalanceByIncrement = 0, - justifiedActiveValidators = 0; - for (let i = 0; i < justifiedBalances.length; i++) { - if (justifiedBalances[i] > 0) { - justifiedActiveValidators += 1; - // justified balances here are by increment - justifiedTotalActiveBalanceByIncrement += justifiedBalances[i]; - } - } - return computeProposerBoostScore({justifiedTotalActiveBalanceByIncrement, justifiedActiveValidators}, config); + const committeeWeight = Math.floor(justifiedTotalActiveBalanceByIncrement / config.slotsPerEpoch); + return Math.floor((committeeWeight * config.proposerScoreBoost) / 100); } diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index 6d26f17d493b..fffbc3e4007f 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -19,6 +19,10 @@ export type CheckpointHexWithBalance = { balances: EffectiveBalanceIncrements; }; +export type CheckpointHexWithTotalBalance = CheckpointHexWithBalance & { + totalBalance: number; +}; + export enum EpochDifference { current = 0, previous = 1, diff --git a/packages/fork-choice/src/forkChoice/store.ts b/packages/fork-choice/src/forkChoice/store.ts index da831550a584..faf700241fa8 100644 --- a/packages/fork-choice/src/forkChoice/store.ts +++ b/packages/fork-choice/src/forkChoice/store.ts @@ -1,7 +1,7 @@ import {toHexString} from "@chainsafe/ssz"; import {EffectiveBalanceIncrements, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, Slot, RootHex, ValidatorIndex} from "@lodestar/types"; -import {CheckpointHexWithBalance} from "./interface.js"; +import {CheckpointHexWithTotalBalance, CheckpointHexWithBalance} from "./interface.js"; /** * Stores checkpoints in a hybrid format: @@ -37,7 +37,8 @@ export type JustifiedBalancesGetter = ( */ export interface IForkChoiceStore { currentSlot: Slot; - justified: CheckpointHexWithBalance; + get justified(): CheckpointHexWithTotalBalance; + set justified(justified: CheckpointHexWithBalance); unrealizedJustified: CheckpointHexWithBalance; finalizedCheckpoint: CheckpointWithHex; unrealizedFinalizedCheckpoint: CheckpointWithHex; @@ -49,7 +50,7 @@ export interface IForkChoiceStore { * IForkChoiceStore implementer which emits forkChoice events on updated justified and finalized checkpoints. */ export class ForkChoiceStore implements IForkChoiceStore { - private _justified: CheckpointHexWithBalance; + private _justified: CheckpointHexWithTotalBalance; unrealizedJustified: CheckpointHexWithBalance; private _finalizedCheckpoint: CheckpointWithHex; unrealizedFinalizedCheckpoint: CheckpointWithHex; @@ -66,9 +67,10 @@ export class ForkChoiceStore implements IForkChoiceStore { onFinalized: (cp: CheckpointWithHex) => void; } ) { - const justified: CheckpointHexWithBalance = { + const justified = { checkpoint: toCheckpointWithHex(justifiedCheckpoint), balances: justifiedBalances, + totalBalance: computeTotalBalance(justifiedBalances), }; this._justified = justified; this.unrealizedJustified = justified; @@ -76,11 +78,11 @@ export class ForkChoiceStore implements IForkChoiceStore { this.unrealizedFinalizedCheckpoint = this._finalizedCheckpoint; } - get justified(): CheckpointHexWithBalance { + get justified(): CheckpointHexWithTotalBalance { return this._justified; } set justified(justified: CheckpointHexWithBalance) { - this._justified = justified; + this._justified = {...justified, totalBalance: computeTotalBalance(justified.balances)}; this.events?.onJustified(justified.checkpoint); } @@ -108,3 +110,11 @@ export function toCheckpointWithHex(checkpoint: phase0.Checkpoint): CheckpointWi export function equalCheckpointWithHex(a: CheckpointWithHex, b: CheckpointWithHex): boolean { return a.epoch === b.epoch && a.rootHex === b.rootHex; } + +export function computeTotalBalance(balances: EffectiveBalanceIncrements): number { + let totalBalance = 0; + for (let i = 0; i < balances.length; i++) { + totalBalance += balances[i]; + } + return totalBalance; +} diff --git a/packages/fork-choice/src/protoArray/protoArray.ts b/packages/fork-choice/src/protoArray/protoArray.ts index b2c030e17540..62f50b03771c 100644 --- a/packages/fork-choice/src/protoArray/protoArray.ts +++ b/packages/fork-choice/src/protoArray/protoArray.ts @@ -723,22 +723,18 @@ export class ProtoArray { return false; } const currentEpoch = computeEpochAtSlot(currentSlot); - const previousEpoch = currentEpoch - 1; // If block is from a previous epoch, filter using unrealized justification & finalization information // If block is from the current epoch, filter using the head state's justification & finalization information const isFromPrevEpoch = computeEpochAtSlot(node.slot) < currentEpoch; const votingSourceEpoch = isFromPrevEpoch ? node.unrealizedJustifiedEpoch : node.justifiedEpoch; - // The voting source should be at the same height as the store's justified checkpoint - let correctJustified = votingSourceEpoch === this.justifiedEpoch || this.justifiedEpoch === 0; - - // If this is a pulled-up block from the current epoch, also check that - // the unrealized justification is higher than the store's justified checkpoint, and - // the voting source is not more than two epochs ago. - if (!correctJustified && currentEpoch > GENESIS_EPOCH && this.justifiedEpoch === previousEpoch) { - correctJustified = node.unrealizedJustifiedEpoch >= previousEpoch && votingSourceEpoch + 2 >= currentEpoch; - } + // The voting source should be at the same height as the store's justified checkpoint or + // not more than two epochs ago + const correctJustified = + this.justifiedEpoch === GENESIS_EPOCH || + votingSourceEpoch === this.justifiedEpoch || + votingSourceEpoch + 2 >= currentEpoch; const correctFinalized = this.finalizedEpoch === 0 || this.isFinalizedRootOrDescendant(node); return correctJustified && correctFinalized; diff --git a/packages/fork-choice/test/perf/forkChoice/util.ts b/packages/fork-choice/test/perf/forkChoice/util.ts index 4669b03db6d6..1ad97d5b6c54 100644 --- a/packages/fork-choice/test/perf/forkChoice/util.ts +++ b/packages/fork-choice/test/perf/forkChoice/util.ts @@ -1,6 +1,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; import {ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoBlock, ProtoArray} from "../../../src/index.js"; +import {computeTotalBalance} from "../../../src/forkChoice/store.js"; const genesisSlot = 0; const genesisEpoch = 0; @@ -39,6 +40,7 @@ export function initializeForkChoice(opts: Opts): ForkChoice { justified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(genesisRoot), rootHex: genesisRoot}, balances, + totalBalance: computeTotalBalance(balances), }, unrealizedJustified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(genesisRoot), rootHex: genesisRoot}, diff --git a/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts b/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts index 1843ef91c22a..9b51f640d949 100644 --- a/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts +++ b/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts @@ -2,7 +2,6 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsZeroed} from "@lodestar/state-transition"; import {VoteTracker} from "../../../src/protoArray/interface.js"; import {computeDeltas} from "../../../src/protoArray/computeDeltas.js"; -import {computeProposerBoostScoreFromBalances} from "../../../src/forkChoice/forkChoice.js"; describe("computeDeltas", () => { let oldBalances: EffectiveBalanceIncrements; @@ -51,13 +50,4 @@ describe("computeDeltas", () => { }); } } - - for (const numValidator of numValidators) { - itBench({ - id: `computeProposerBoostScoreFromBalances ${numValidator} validators`, - fn: () => { - computeProposerBoostScoreFromBalances(newBalances, {slotsPerEpoch: 32, proposerScoreBoost: 70}); - }, - }); - } }); diff --git a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts index fe11532dbb6f..93aa28f8f2e5 100644 --- a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts @@ -51,6 +51,7 @@ describe("Forkchoice", function () { justified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot}, balances: new Uint8Array([32]), + totalBalance: 32, }, unrealizedJustified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot},