From 87c40ec45d5f01da54e3084fb2c4b1bd24a2dde3 Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 8 Aug 2023 17:12:28 +0800 Subject: [PATCH 001/155] Add immutable in the dependencies --- packages/state-transition/package.json | 3 ++- yarn.lock | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 1e263f42dd8..eb3b9f1eaa0 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -67,7 +67,8 @@ "@lodestar/types": "^1.10.0", "@lodestar/utils": "^1.10.0", "bigint-buffer": "^1.1.5", - "buffer-xor": "^2.0.2" + "buffer-xor": "^2.0.2", + "immutable": "^4.3.2" }, "devDependencies": { "@chainsafe/blst": "^0.2.9", diff --git a/yarn.lock b/yarn.lock index 090b220a6ad..c084c658a5e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7859,6 +7859,11 @@ ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +immutable@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.2.tgz#f89d910f8dfb6e15c03b2cae2faaf8c1f66455fe" + integrity sha512-oGXzbEDem9OOpDWZu88jGiYCvIsLHMvGw+8OXlpsvTFvIQplQbjg1B1cvKg8f7Hoch6+NGjpPsH1Fr+Mc2D1aA== + import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" From a9311ad49d6310f79344033a75dc766b66471359 Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 18 Aug 2023 19:10:45 +0800 Subject: [PATCH 002/155] Initial change to pubkeyCache --- .../state-transition/src/cache/epochCache.ts | 7 +++-- .../state-transition/src/cache/pubkeyCache.ts | 29 +++++++++++++++++++ .../state-transition/src/cache/stateCache.ts | 21 ++++++++++++++ .../src/epoch/processRegistryUpdates.ts | 5 ++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index da41631afe2..6f480745c6b 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -84,7 +84,8 @@ export class EpochCache { * * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies - * Warning: may contain pubkeys that do not yet exist in the current state, but do in a later processed state. + * + * New: This would only validators whose deposit is finalized and hence it is insert only. Validators may still be in the activation queue. * * $VALIDATOR_COUNT x 192 char String -> Number Map */ @@ -92,8 +93,8 @@ export class EpochCache { /** * Unique globally shared pubkey registry. There should only exist one for the entire application. * - * Warning: may contain indices that do not yet exist in the current state, but do in a later processed state. - * + * New: This would only validators whose deposit is finalized and hence it is insert only. Validators may still be in the activation queue. + * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ index2pubkey: Index2PubkeyCache; diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 130a9cd29d8..5dd92c2f890 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -2,6 +2,7 @@ import {CoordType, PublicKey} from "@chainsafe/bls/types"; import bls from "@chainsafe/bls"; import {ValidatorIndex} from "@lodestar/types"; import {BeaconStateAllForks} from "./types.js"; +import * as immutable from "immutable"; export type Index2PubkeyCache = PublicKey[]; @@ -26,6 +27,22 @@ function toMemoryEfficientHexStr(hex: Uint8Array | string): string { return Buffer.from(hex).toString("hex"); } +export class UnfinanlizedIndex2PubkeyCache { + private list = immutable.List(); + + get(i: number): PubkeyHex | null { + } + + push(element: PubkeyHex): void { + + } + + length(): number { + + } + +} + export class PubkeyIndexMap { // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address readonly map = new Map(); @@ -46,6 +63,18 @@ export class PubkeyIndexMap { } } +export class UnfinalizedPubkeyIndexMap { + private map = immutable.Map(); + + get(key: Uint8Array | PubkeyHex): ValidatorIndex | undefined { + return this.map.get(toMemoryEfficientHexStr(key)); + } + + set(key: Uint8Array, value: ValidatorIndex): void { + this.map = this.map.set(toMemoryEfficientHexStr(key), value); + } +} + /** * Checks the pubkey indices against a state and adds missing pubkeys * diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index f8ce97d5ffb..bc8f508cd9b 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -9,10 +9,17 @@ import { BeaconStateCapella, BeaconStateDeneb, } from "./types.js"; +import {UnfinalizedPubkeyIndexMap, UnfinanlizedIndex2PubkeyCache} from "./pubkeyCache"; +import {PublicKey} from "@chainsafe/bls/types"; +import {ValidatorIndex} from "@lodestar/types"; export type BeaconStateCache = { config: BeaconConfig; epochCtx: EpochCache; + /** Unfinalized cache for current state */ + unfinalizedPubkeyCache: UnfinanlizedIndex2PubkeyCache; + unfinalizedPubkeyIndexMap: UnfinalizedPubkeyIndexMap; + /** Count of clones created from this BeaconStateCache instance. readonly to prevent accidental usage downstream */ readonly clonedCount: number; readonly clonedCountWithTransferCache: number; @@ -140,6 +147,8 @@ export function createCachedBeaconState( return getCachedBeaconState(state, { config: immutableData.config, epochCtx: EpochCache.createFromState(state, immutableData, opts), + unfinalizedPubkeyCache: new UnfinanlizedIndex2PubkeyCache(), + unfinalizedPubkeyIndexMap: new UnfinalizedPubkeyIndexMap(), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, @@ -177,6 +186,8 @@ export function getCachedBeaconState( return getCachedBeaconState(viewDUCloned, { config: this.config, epochCtx: this.epochCtx.clone(), + unfinalizedPubkeyCache: this.unfinalizedPubkeyCache, + unfinalizedPubkeyIndexMap: new UnfinalizedPubkeyIndexMap(), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: !dontTransferCache, @@ -207,3 +218,13 @@ export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean { return state.balances["nodesPopulated"] === true; } + +export function getPubkeyForAggregation(state: CachedBeaconStateAllForks, index: ValidatorIndex): PublicKey { +} + +export function getPubkeyIndex(state: CachedBeaconStateAllForks, pubkey: Uint8Array): ValidatorIndex | null { +} + +export function addPubkey(state: CachedBeaconStateAllForks, pubkey: Uint8Array, index: ValidatorIndex): void { + +} \ No newline at end of file diff --git a/packages/state-transition/src/epoch/processRegistryUpdates.ts b/packages/state-transition/src/epoch/processRegistryUpdates.ts index 831b3cd8055..29148ccd29d 100644 --- a/packages/state-transition/src/epoch/processRegistryUpdates.ts +++ b/packages/state-transition/src/epoch/processRegistryUpdates.ts @@ -34,6 +34,11 @@ export function processRegistryUpdates(state: CachedBeaconStateAllForks, cache: // set new activation eligibilities for (const index of cache.indicesEligibleForActivationQueue) { validators.get(index).activationEligibilityEpoch = epochCtx.epoch + 1; + // TODO: For all new validators that are eligible to be in the activation queue, we need to move its cache from unfinalized to finalized queue + // const validator = validators.get(index); + // const pubkey = validator.pubkey; + // state.epochCtx.addPubkey(index, pubkey); + } const finalityEpoch = state.finalizedCheckpoint.epoch; From eaca16910400ac2403626fd62d3b4dd09217ba99 Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 18 Aug 2023 19:34:47 +0800 Subject: [PATCH 003/155] Added todos --- .../state-transition/src/block/processDeposit.ts | 1 + packages/state-transition/src/cache/epochCache.ts | 4 ++-- .../state-transition/src/cache/pubkeyCache.ts | 15 --------------- packages/state-transition/src/cache/stateCache.ts | 5 +---- .../src/epoch/processRegistryUpdates.ts | 9 ++++----- 5 files changed, 8 insertions(+), 26 deletions(-) diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index dae37d5d0af..b80fffc32f2 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -89,6 +89,7 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); // now that there is a new validator, update the epoch context with the new pubkey + // TODO: Here we should populate unfinalized cache instead epochCtx.addPubkey(validatorIndex, pubkey); // Only after altair: diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 6f480745c6b..130ae6597c8 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -85,7 +85,7 @@ export class EpochCache { * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies * - * New: This would only validators whose deposit is finalized and hence it is insert only. Validators may still be in the activation queue. + * New: This would only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. * * $VALIDATOR_COUNT x 192 char String -> Number Map */ @@ -93,7 +93,7 @@ export class EpochCache { /** * Unique globally shared pubkey registry. There should only exist one for the entire application. * - * New: This would only validators whose deposit is finalized and hence it is insert only. Validators may still be in the activation queue. + * New: This would only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 5dd92c2f890..c7ac7d003f0 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -27,21 +27,6 @@ function toMemoryEfficientHexStr(hex: Uint8Array | string): string { return Buffer.from(hex).toString("hex"); } -export class UnfinanlizedIndex2PubkeyCache { - private list = immutable.List(); - - get(i: number): PubkeyHex | null { - } - - push(element: PubkeyHex): void { - - } - - length(): number { - - } - -} export class PubkeyIndexMap { // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index bc8f508cd9b..b6c9cd50a95 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -9,7 +9,7 @@ import { BeaconStateCapella, BeaconStateDeneb, } from "./types.js"; -import {UnfinalizedPubkeyIndexMap, UnfinanlizedIndex2PubkeyCache} from "./pubkeyCache"; +import {UnfinalizedPubkeyIndexMap} from "./pubkeyCache"; import {PublicKey} from "@chainsafe/bls/types"; import {ValidatorIndex} from "@lodestar/types"; @@ -17,7 +17,6 @@ export type BeaconStateCache = { config: BeaconConfig; epochCtx: EpochCache; /** Unfinalized cache for current state */ - unfinalizedPubkeyCache: UnfinanlizedIndex2PubkeyCache; unfinalizedPubkeyIndexMap: UnfinalizedPubkeyIndexMap; /** Count of clones created from this BeaconStateCache instance. readonly to prevent accidental usage downstream */ @@ -147,7 +146,6 @@ export function createCachedBeaconState( return getCachedBeaconState(state, { config: immutableData.config, epochCtx: EpochCache.createFromState(state, immutableData, opts), - unfinalizedPubkeyCache: new UnfinanlizedIndex2PubkeyCache(), unfinalizedPubkeyIndexMap: new UnfinalizedPubkeyIndexMap(), clonedCount: 0, clonedCountWithTransferCache: 0, @@ -186,7 +184,6 @@ export function getCachedBeaconState( return getCachedBeaconState(viewDUCloned, { config: this.config, epochCtx: this.epochCtx.clone(), - unfinalizedPubkeyCache: this.unfinalizedPubkeyCache, unfinalizedPubkeyIndexMap: new UnfinalizedPubkeyIndexMap(), clonedCount: 0, clonedCountWithTransferCache: 0, diff --git a/packages/state-transition/src/epoch/processRegistryUpdates.ts b/packages/state-transition/src/epoch/processRegistryUpdates.ts index 29148ccd29d..7db3c5d8a1a 100644 --- a/packages/state-transition/src/epoch/processRegistryUpdates.ts +++ b/packages/state-transition/src/epoch/processRegistryUpdates.ts @@ -34,11 +34,6 @@ export function processRegistryUpdates(state: CachedBeaconStateAllForks, cache: // set new activation eligibilities for (const index of cache.indicesEligibleForActivationQueue) { validators.get(index).activationEligibilityEpoch = epochCtx.epoch + 1; - // TODO: For all new validators that are eligible to be in the activation queue, we need to move its cache from unfinalized to finalized queue - // const validator = validators.get(index); - // const pubkey = validator.pubkey; - // state.epochCtx.addPubkey(index, pubkey); - } const finalityEpoch = state.finalizedCheckpoint.epoch; @@ -54,5 +49,9 @@ export function processRegistryUpdates(state: CachedBeaconStateAllForks, cache: break; } validator.activationEpoch = computeActivationExitEpoch(cache.currentEpoch); + // TODO: For all new validators that are eligible to be in the activation queue, we need to move its cache from unfinalized to finalized queue + // const validator = validators.get(index); + // const pubkey = validator.pubkey; + // state.epochCtx.addPubkey(index, pubkey); } } From cfb0052a122b8629500751d4e9e1f91747fb5de6 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 23 Aug 2023 11:33:27 +0800 Subject: [PATCH 004/155] Moved unfinalized cache to epochCache --- .../state-transition/src/cache/epochCache.ts | 36 ++++++++++++++----- .../state-transition/src/cache/stateCache.ts | 15 -------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 130ae6597c8..e99f71d7d2f 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -29,7 +29,7 @@ import {computeEpochShuffling, EpochShuffling} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, syncPubkeys} from "./pubkeyCache.js"; +import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { computeSyncCommitteeCache, @@ -85,19 +85,26 @@ export class EpochCache { * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies * - * New: This would only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. + * New: This would include only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. * * $VALIDATOR_COUNT x 192 char String -> Number Map */ - pubkey2index: PubkeyIndexMap; + globalPubkey2index: PubkeyIndexMap; /** * Unique globally shared pubkey registry. There should only exist one for the entire application. * - * New: This would only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. + * New: This would include only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ - index2pubkey: Index2PubkeyCache; + globalIndex2pubkey: Index2PubkeyCache; + /** + * Unique pubkey registry shared in the same fork. There should only exist one for the fork. + * + */ + unfinalizedIndex2pubkey: UnfinalizedPubkeyIndexMap; + + /** * Indexes of the block proposers for the current epoch. * @@ -463,12 +470,14 @@ export class EpochCache { afterProcessEpoch( state: BeaconStateAllForks, epochTransitionCache: { + indicesEligibleForActivation: ValidatorIndex[]; nextEpochShufflingActiveValidatorIndices: ValidatorIndex[]; nextEpochTotalActiveBalanceByIncrement: number; } ): void { this.previousShuffling = this.currentShuffling; this.currentShuffling = this.nextShuffling; + const prevEpoch = this.previousShuffling.epoch; const currEpoch = this.currentShuffling.epoch; const nextEpoch = currEpoch + 1; @@ -715,9 +724,19 @@ export class EpochCache { return isAggregatorFromCommitteeLength(committee.length, slotSignature); } - addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - this.pubkey2index.set(pubkey, index); - this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); // Optimize for aggregation + // addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { + // this.pubkey2index.set(pubkey, index); + // this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); // Optimize for aggregation + // } + + getPubkey(index: ValidatorIndex): PublicKey { + } + + getPubkeyIndex(pubkey: Uint8Array): ValidatorIndex | null { + } + + addPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + } getShufflingAtSlot(slot: Slot): EpochShuffling { @@ -799,6 +818,7 @@ export class EpochCache { this.effectiveBalanceIncrements[index] = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); } + } function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index b6c9cd50a95..a42a5ea27e2 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -9,15 +9,12 @@ import { BeaconStateCapella, BeaconStateDeneb, } from "./types.js"; -import {UnfinalizedPubkeyIndexMap} from "./pubkeyCache"; import {PublicKey} from "@chainsafe/bls/types"; import {ValidatorIndex} from "@lodestar/types"; export type BeaconStateCache = { config: BeaconConfig; epochCtx: EpochCache; - /** Unfinalized cache for current state */ - unfinalizedPubkeyIndexMap: UnfinalizedPubkeyIndexMap; /** Count of clones created from this BeaconStateCache instance. readonly to prevent accidental usage downstream */ readonly clonedCount: number; @@ -146,7 +143,6 @@ export function createCachedBeaconState( return getCachedBeaconState(state, { config: immutableData.config, epochCtx: EpochCache.createFromState(state, immutableData, opts), - unfinalizedPubkeyIndexMap: new UnfinalizedPubkeyIndexMap(), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, @@ -184,7 +180,6 @@ export function getCachedBeaconState( return getCachedBeaconState(viewDUCloned, { config: this.config, epochCtx: this.epochCtx.clone(), - unfinalizedPubkeyIndexMap: new UnfinalizedPubkeyIndexMap(), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: !dontTransferCache, @@ -214,14 +209,4 @@ export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean { return state.balances["nodesPopulated"] === true; -} - -export function getPubkeyForAggregation(state: CachedBeaconStateAllForks, index: ValidatorIndex): PublicKey { -} - -export function getPubkeyIndex(state: CachedBeaconStateAllForks, pubkey: Uint8Array): ValidatorIndex | null { -} - -export function addPubkey(state: CachedBeaconStateAllForks, pubkey: Uint8Array, index: ValidatorIndex): void { - } \ No newline at end of file From 6988d8e1fbd7039c799521b62e03852414028ed3 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 23 Aug 2023 11:44:24 +0800 Subject: [PATCH 005/155] Move populating finalized cache to afterProcessEpoch --- packages/state-transition/src/cache/epochCache.ts | 12 ++++++++++++ .../src/epoch/processRegistryUpdates.ts | 4 ---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index e99f71d7d2f..953c613af4b 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -487,6 +487,18 @@ export class EpochCache { nextEpoch ); + // To populate finalized cache with validators that just became pending activated in processEpoch + const expectedActivationEpoch = computeActivationExitEpoch(prevEpoch); + const validators = state.validators; + for (const index of epochTransitionCache.indicesEligibleForActivation) { + const validator = validators.get(index); + if (validator.activationEpoch == expectedActivationEpoch) { + this.addPubkey(validator.pubkey, index); + } else { + break; + } + } + // Roll current proposers into previous proposers for metrics this.proposersPrevEpoch = this.proposers; diff --git a/packages/state-transition/src/epoch/processRegistryUpdates.ts b/packages/state-transition/src/epoch/processRegistryUpdates.ts index 7db3c5d8a1a..831b3cd8055 100644 --- a/packages/state-transition/src/epoch/processRegistryUpdates.ts +++ b/packages/state-transition/src/epoch/processRegistryUpdates.ts @@ -49,9 +49,5 @@ export function processRegistryUpdates(state: CachedBeaconStateAllForks, cache: break; } validator.activationEpoch = computeActivationExitEpoch(cache.currentEpoch); - // TODO: For all new validators that are eligible to be in the activation queue, we need to move its cache from unfinalized to finalized queue - // const validator = validators.get(index); - // const pubkey = validator.pubkey; - // state.epochCtx.addPubkey(index, pubkey); } } From 4c96aa90d3fe2487a33519a13e765f39513f8221 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 23 Aug 2023 15:54:02 +0800 Subject: [PATCH 006/155] Specify unfinalized cache during state cloning --- packages/state-transition/src/cache/pubkeyCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index c7ac7d003f0..d6a46437e4b 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -1,8 +1,8 @@ import {CoordType, PublicKey} from "@chainsafe/bls/types"; import bls from "@chainsafe/bls"; +import * as immutable from "immutable"; import {ValidatorIndex} from "@lodestar/types"; import {BeaconStateAllForks} from "./types.js"; -import * as immutable from "immutable"; export type Index2PubkeyCache = PublicKey[]; From 32d5f1b85b61d74580e9122406f282ccd4ba9c51 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 23 Aug 2023 16:34:45 +0800 Subject: [PATCH 007/155] Move from unfinalized to finalized cache in afterProcessEpoch --- .../state-transition/src/cache/epochCache.ts | 34 ++++++++++++++++--- .../state-transition/src/cache/pubkeyCache.ts | 16 +++++---- packages/state-transition/src/index.ts | 2 +- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 953c613af4b..278bdcaf348 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -29,7 +29,7 @@ import {computeEpochShuffling, EpochShuffling} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys} from "./pubkeyCache.js"; +import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedIndex2PubkeyCache, syncPubkeys} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { computeSyncCommitteeCache, @@ -102,7 +102,7 @@ export class EpochCache { * Unique pubkey registry shared in the same fork. There should only exist one for the fork. * */ - unfinalizedIndex2pubkey: UnfinalizedPubkeyIndexMap; + unfinalizedIndex2pubkey: UnfinalizedIndex2PubkeyCache; /** @@ -200,6 +200,7 @@ export class EpochCache { config: BeaconConfig; pubkey2index: PubkeyIndexMap; index2pubkey: Index2PubkeyCache; + unfinalizedIndex2pubkey: UnfinalizedIndex2PubkeyCache; proposers: number[]; proposersPrevEpoch: number[] | null; proposersNextEpoch: ProposersDeferred; @@ -224,6 +225,7 @@ export class EpochCache { this.config = data.config; this.pubkey2index = data.pubkey2index; this.index2pubkey = data.index2pubkey; + this.unfinalizedIndex2pubkey = data.unfinalizedIndex2pubkey; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; this.proposersNextEpoch = data.proposersNextEpoch; @@ -263,6 +265,8 @@ export class EpochCache { syncPubkeys(state, pubkey2index, index2pubkey); } + const unfinalizedIndex2pubkey = new UnfinalizedIndex2PubkeyCache(); + const currentEpoch = computeEpochAtSlot(state.slot); const isGenesis = currentEpoch === GENESIS_EPOCH; const previousEpoch = isGenesis ? GENESIS_EPOCH : currentEpoch - 1; @@ -400,6 +404,7 @@ export class EpochCache { config, pubkey2index, index2pubkey, + unfinalizedIndex2pubkey, proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics proposersPrevEpoch: null, @@ -436,6 +441,8 @@ export class EpochCache { // Common append-only structures shared with all states, no need to clone pubkey2index: this.pubkey2index, index2pubkey: this.index2pubkey, + // Fork-aware cache needs to be cloned. But due to it being persistent, we don't need to do anything here + unfinalizedIndex2pubkey: this.unfinalizedIndex2pubkey, // Immutable data proposers: this.proposers, proposersPrevEpoch: this.proposersPrevEpoch, @@ -487,13 +494,13 @@ export class EpochCache { nextEpoch ); - // To populate finalized cache with validators that just became pending activated in processEpoch + // To populate finalized cache and prune unfinalized cache with validators that just became pending activated in processEpoch const expectedActivationEpoch = computeActivationExitEpoch(prevEpoch); const validators = state.validators; for (const index of epochTransitionCache.indicesEligibleForActivation) { - const validator = validators.get(index); + const validator = validators.getReadonly(index); if (validator.activationEpoch == expectedActivationEpoch) { - this.addPubkey(validator.pubkey, index); + this.addFinalizedPubkey(validator.pubkey, index); } else { break; } @@ -747,8 +754,25 @@ export class EpochCache { getPubkeyIndex(pubkey: Uint8Array): ValidatorIndex | null { } + /** + * + * Add unfinalized pubkeys + * + */ addPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + } + + /** + * + * Given a validator whose activation_epoch has just been set, we move its pubkey from unfinalized cache to finalized cache + * + */ + addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + this.globalPubkey2index.set(pubkey, index); + // TODO: Verify if we need to re-compute pubkey here or we can grab dirrectly from unfinalizedIndex2pubkey[index] + this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.unfinalizedIndex2pubkey.delete(index); } getShufflingAtSlot(slot: Slot): EpochShuffling { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index d6a46437e4b..672cde9215f 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -48,15 +48,19 @@ export class PubkeyIndexMap { } } -export class UnfinalizedPubkeyIndexMap { - private map = immutable.Map(); +export class UnfinalizedIndex2PubkeyCache { + private list = immutable.List(); - get(key: Uint8Array | PubkeyHex): ValidatorIndex | undefined { - return this.map.get(toMemoryEfficientHexStr(key)); + get(index: number): PublicKey | undefined { + return this.list.get(index); } - set(key: Uint8Array, value: ValidatorIndex): void { - this.map = this.map.set(toMemoryEfficientHexStr(key), value); + push(pubkey: PublicKey): void { + this.list = this.list.push(pubkey); + } + + delete(index: number): void { + this.list = this.list.delete(index); } } diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 98ab4b4fe60..fbc2e2a50be 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -34,7 +34,7 @@ export {EpochCache, EpochCacheImmutableData, createEmptyEpochCacheImmutableData} export {EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures -export {PubkeyIndexMap, Index2PubkeyCache} from "./cache/pubkeyCache.js"; +export {PubkeyIndexMap, Index2PubkeyCache, UnfinalizedIndex2PubkeyCache} from "./cache/pubkeyCache.js"; export { EffectiveBalanceIncrements, From efbfe7383cb71aa87a8045af6380e81915450d7a Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 23 Aug 2023 16:48:40 +0800 Subject: [PATCH 008/155] Confused myself --- .../state-transition/src/cache/epochCache.ts | 15 ++++++------ .../state-transition/src/cache/pubkeyCache.ts | 23 ++++++++++--------- packages/state-transition/src/index.ts | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 278bdcaf348..e08fda65e91 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -29,7 +29,7 @@ import {computeEpochShuffling, EpochShuffling} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedIndex2PubkeyCache, syncPubkeys} from "./pubkeyCache.js"; +import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { computeSyncCommitteeCache, @@ -102,7 +102,7 @@ export class EpochCache { * Unique pubkey registry shared in the same fork. There should only exist one for the fork. * */ - unfinalizedIndex2pubkey: UnfinalizedIndex2PubkeyCache; + unfinalizedPubkey2Index: UnfinalizedPubkeyIndexMap; /** @@ -200,7 +200,7 @@ export class EpochCache { config: BeaconConfig; pubkey2index: PubkeyIndexMap; index2pubkey: Index2PubkeyCache; - unfinalizedIndex2pubkey: UnfinalizedIndex2PubkeyCache; + unfinalizedIndex2pubkey: UnfinalizedPubkeyIndexMap; proposers: number[]; proposersPrevEpoch: number[] | null; proposersNextEpoch: ProposersDeferred; @@ -225,7 +225,7 @@ export class EpochCache { this.config = data.config; this.pubkey2index = data.pubkey2index; this.index2pubkey = data.index2pubkey; - this.unfinalizedIndex2pubkey = data.unfinalizedIndex2pubkey; + this.unfinalizedPubkey2Index = data.unfinalizedIndex2pubkey; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; this.proposersNextEpoch = data.proposersNextEpoch; @@ -265,7 +265,7 @@ export class EpochCache { syncPubkeys(state, pubkey2index, index2pubkey); } - const unfinalizedIndex2pubkey = new UnfinalizedIndex2PubkeyCache(); + const unfinalizedIndex2pubkey = new UnfinalizedPubkeyIndexMap(); const currentEpoch = computeEpochAtSlot(state.slot); const isGenesis = currentEpoch === GENESIS_EPOCH; @@ -442,7 +442,7 @@ export class EpochCache { pubkey2index: this.pubkey2index, index2pubkey: this.index2pubkey, // Fork-aware cache needs to be cloned. But due to it being persistent, we don't need to do anything here - unfinalizedIndex2pubkey: this.unfinalizedIndex2pubkey, + unfinalizedIndex2pubkey: this.unfinalizedPubkey2Index, // Immutable data proposers: this.proposers, proposersPrevEpoch: this.proposersPrevEpoch, @@ -769,10 +769,9 @@ export class EpochCache { */ addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { this.globalPubkey2index.set(pubkey, index); - // TODO: Verify if we need to re-compute pubkey here or we can grab dirrectly from unfinalizedIndex2pubkey[index] this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); - this.unfinalizedIndex2pubkey.delete(index); + this.unfinalizedPubkey2Index.delete(pubkey); } getShufflingAtSlot(slot: Slot): EpochShuffling { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 672cde9215f..bdefcfc1199 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -48,20 +48,21 @@ export class PubkeyIndexMap { } } -export class UnfinalizedIndex2PubkeyCache { - private list = immutable.List(); +export class UnfinalizedPubkeyIndexMap { + private map = immutable.Map(); - get(index: number): PublicKey | undefined { - return this.list.get(index); - } + get(key: Uint8Array | PubkeyHex): ValidatorIndex | undefined { + return this.map.get(toMemoryEfficientHexStr(key)); + } - push(pubkey: PublicKey): void { - this.list = this.list.push(pubkey); - } + set(key: Uint8Array, value: ValidatorIndex): void { + this.map = this.map.set(toMemoryEfficientHexStr(key), value); + } + + delete(key: Uint8Array): void { + this.map = this.map.delete(toMemoryEfficientHexStr(key)); + } - delete(index: number): void { - this.list = this.list.delete(index); - } } /** diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index fbc2e2a50be..32056ad3d41 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -34,7 +34,7 @@ export {EpochCache, EpochCacheImmutableData, createEmptyEpochCacheImmutableData} export {EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures -export {PubkeyIndexMap, Index2PubkeyCache, UnfinalizedIndex2PubkeyCache} from "./cache/pubkeyCache.js"; +export {PubkeyIndexMap, Index2PubkeyCache, UnfinalizedPubkeyIndexMap} from "./cache/pubkeyCache.js"; export { EffectiveBalanceIncrements, From b8068ba8f0c264f1605991beb2889d8c9b7be6d5 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 23 Aug 2023 17:07:14 +0800 Subject: [PATCH 009/155] Clean up --- packages/state-transition/src/block/processDeposit.ts | 1 - packages/state-transition/src/cache/epochCache.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index b80fffc32f2..dae37d5d0af 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -89,7 +89,6 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); // now that there is a new validator, update the epoch context with the new pubkey - // TODO: Here we should populate unfinalized cache instead epochCtx.addPubkey(validatorIndex, pubkey); // Only after altair: diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index e08fda65e91..f3798af4580 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -441,7 +441,7 @@ export class EpochCache { // Common append-only structures shared with all states, no need to clone pubkey2index: this.pubkey2index, index2pubkey: this.index2pubkey, - // Fork-aware cache needs to be cloned. But due to it being persistent, we don't need to do anything here + // Fork-aware cache needs to be cloned. But by the virtue of it being persistent, we don't need to do anything here unfinalizedIndex2pubkey: this.unfinalizedPubkey2Index, // Immutable data proposers: this.proposers, From bc842e673f270960adf1f9f273394d5ff35ee80a Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 23 Aug 2023 18:42:51 +0800 Subject: [PATCH 010/155] Change logic --- packages/state-transition/src/cache/epochCache.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index f3798af4580..3e4c6c7a3bc 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -477,7 +477,7 @@ export class EpochCache { afterProcessEpoch( state: BeaconStateAllForks, epochTransitionCache: { - indicesEligibleForActivation: ValidatorIndex[]; + indicesEligibleForActivationQueue: ValidatorIndex[]; nextEpochShufflingActiveValidatorIndices: ValidatorIndex[]; nextEpochTotalActiveBalanceByIncrement: number; } @@ -494,12 +494,12 @@ export class EpochCache { nextEpoch ); - // To populate finalized cache and prune unfinalized cache with validators that just became pending activated in processEpoch - const expectedActivationEpoch = computeActivationExitEpoch(prevEpoch); + // To populate finalized cache and prune unfinalized cache with validators that just entered the activation queue + const expectedActivationEligibilityEpoch = prevEpoch + 1; const validators = state.validators; - for (const index of epochTransitionCache.indicesEligibleForActivation) { + for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { const validator = validators.getReadonly(index); - if (validator.activationEpoch == expectedActivationEpoch) { + if (validator.activationEpoch == expectedActivationEligibilityEpoch) { this.addFinalizedPubkey(validator.pubkey, index); } else { break; From bb25132cfd44a7aab78cf22dde38e3ca61816d3e Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 18:05:01 +0800 Subject: [PATCH 011/155] Fix cloning issue --- .../src/block/processDeposit.ts | 2 +- .../state-transition/src/cache/epochCache.ts | 36 +++++++++---------- .../state-transition/src/cache/pubkeyCache.ts | 21 +++-------- 3 files changed, 22 insertions(+), 37 deletions(-) diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index dae37d5d0af..611f89429d9 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -43,7 +43,7 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, const pubkey = deposit.data.pubkey; // Drop tree const amount = deposit.data.amount; - const cachedIndex = epochCtx.pubkey2index.get(pubkey); + const cachedIndex = epochCtx.getPubkeyIndex(pubkey); if (cachedIndex === undefined || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { // verify the deposit signature (proof of posession) which is not checked by the deposit contract const depositMessage = { diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 3e4c6c7a3bc..b6716cd2c0d 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,4 +1,4 @@ -import {CoordType} from "@chainsafe/bls/types"; +import {CoordType, PublicKey} from "@chainsafe/bls/types"; import bls from "@chainsafe/bls"; import {BLSSignature, CommitteeIndex, Epoch, Slot, ValidatorIndex, phase0, SyncPeriod} from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainConfig} from "@lodestar/config"; @@ -29,7 +29,7 @@ import {computeEpochShuffling, EpochShuffling} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys} from "./pubkeyCache.js"; +import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { computeSyncCommitteeCache, @@ -198,8 +198,8 @@ export class EpochCache { constructor(data: { config: BeaconConfig; - pubkey2index: PubkeyIndexMap; - index2pubkey: Index2PubkeyCache; + globalPubkey2index: PubkeyIndexMap; + globalIndex2pubkey: Index2PubkeyCache; unfinalizedIndex2pubkey: UnfinalizedPubkeyIndexMap; proposers: number[]; proposersPrevEpoch: number[] | null; @@ -223,8 +223,8 @@ export class EpochCache { syncPeriod: SyncPeriod; }) { this.config = data.config; - this.pubkey2index = data.pubkey2index; - this.index2pubkey = data.index2pubkey; + this.globalPubkey2index = data.globalPubkey2index; + this.globalIndex2pubkey = data.globalIndex2pubkey; this.unfinalizedPubkey2Index = data.unfinalizedIndex2pubkey; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; @@ -265,7 +265,7 @@ export class EpochCache { syncPubkeys(state, pubkey2index, index2pubkey); } - const unfinalizedIndex2pubkey = new UnfinalizedPubkeyIndexMap(); + const unfinalizedIndex2pubkey = newUnfinalizedPubkeyIndexMap(); // TODO: Figure out how to populate it const currentEpoch = computeEpochAtSlot(state.slot); const isGenesis = currentEpoch === GENESIS_EPOCH; @@ -402,8 +402,8 @@ export class EpochCache { return new EpochCache({ config, - pubkey2index, - index2pubkey, + globalPubkey2index: pubkey2index, + globalIndex2pubkey: index2pubkey, unfinalizedIndex2pubkey, proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics @@ -439,8 +439,8 @@ export class EpochCache { return new EpochCache({ config: this.config, // Common append-only structures shared with all states, no need to clone - pubkey2index: this.pubkey2index, - index2pubkey: this.index2pubkey, + globalPubkey2index: this.globalPubkey2index, + globalIndex2pubkey: this.globalIndex2pubkey, // Fork-aware cache needs to be cloned. But by the virtue of it being persistent, we don't need to do anything here unfinalizedIndex2pubkey: this.unfinalizedPubkey2Index, // Immutable data @@ -743,15 +743,12 @@ export class EpochCache { return isAggregatorFromCommitteeLength(committee.length, slotSignature); } - // addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - // this.pubkey2index.set(pubkey, index); - // this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); // Optimize for aggregation - // } - getPubkey(index: ValidatorIndex): PublicKey { + return this.globalIndex2pubkey[index]; } - getPubkeyIndex(pubkey: Uint8Array): ValidatorIndex | null { + getPubkeyIndex(pubkey: Uint8Array): ValidatorIndex | undefined { + return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2Index.get(toMemoryEfficientHexStr(pubkey)); } /** @@ -759,7 +756,8 @@ export class EpochCache { * Add unfinalized pubkeys * */ - addPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { + this.unfinalizedPubkey2Index.set(toMemoryEfficientHexStr(pubkey), index); } /** @@ -771,7 +769,7 @@ export class EpochCache { this.globalPubkey2index.set(pubkey, index); this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); - this.unfinalizedPubkey2Index.delete(pubkey); + this.unfinalizedPubkey2Index.delete(toMemoryEfficientHexStr(pubkey)); } getShufflingAtSlot(slot: Slot): EpochShuffling { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index bdefcfc1199..9ad6dfd3753 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -5,6 +5,7 @@ import {ValidatorIndex} from "@lodestar/types"; import {BeaconStateAllForks} from "./types.js"; export type Index2PubkeyCache = PublicKey[]; +export type UnfinalizedPubkeyIndexMap = immutable.Map; type PubkeyHex = string; @@ -16,7 +17,7 @@ type PubkeyHex = string; * * See https://github.com/ChainSafe/lodestar/issues/3446 */ -function toMemoryEfficientHexStr(hex: Uint8Array | string): string { +export function toMemoryEfficientHexStr(hex: Uint8Array | string): string { if (typeof hex === "string") { if (hex.startsWith("0x")) { hex = hex.slice(2); @@ -48,22 +49,6 @@ export class PubkeyIndexMap { } } -export class UnfinalizedPubkeyIndexMap { - private map = immutable.Map(); - - get(key: Uint8Array | PubkeyHex): ValidatorIndex | undefined { - return this.map.get(toMemoryEfficientHexStr(key)); - } - - set(key: Uint8Array, value: ValidatorIndex): void { - this.map = this.map.set(toMemoryEfficientHexStr(key), value); - } - - delete(key: Uint8Array): void { - this.map = this.map.delete(toMemoryEfficientHexStr(key)); - } - -} /** * Checks the pubkey indices against a state and adds missing pubkeys @@ -71,6 +56,8 @@ export class UnfinalizedPubkeyIndexMap { * Mutates `pubkey2index` and `index2pubkey` * * If pubkey caches are empty: SLOW CODE - 🐢 + * + * TODO: Deal with this */ export function syncPubkeys( state: BeaconStateAllForks, From c0757b4572d1d6a37b896afc0dfd9e76c12a046e Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 18:13:41 +0800 Subject: [PATCH 012/155] Clean up redundant code --- packages/state-transition/src/cache/epochCache.ts | 2 +- packages/state-transition/src/cache/pubkeyCache.ts | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index b6716cd2c0d..ab8dbf19d04 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -29,7 +29,7 @@ import {computeEpochShuffling, EpochShuffling} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr} from "./pubkeyCache.js"; +import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr, newUnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { computeSyncCommitteeCache, diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 9ad6dfd3753..931e9111698 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -28,6 +28,15 @@ export function toMemoryEfficientHexStr(hex: Uint8Array | string): string { return Buffer.from(hex).toString("hex"); } +/** + * + * A wrapper for calling immutable.js + * + */ +export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { + return immutable.Map(); +} + export class PubkeyIndexMap { // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address From 3cf72e39164a20283024e3213054fec11eabdc53 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 19:00:39 +0800 Subject: [PATCH 013/155] Add CarryoverData in epochCtx.createFromState --- packages/beacon-node/src/chain/chain.ts | 3 ++- packages/beacon-node/src/chain/genesis/genesis.ts | 3 ++- .../beacon-node/test/utils/cachedBeaconState.ts | 3 ++- packages/beacon-node/test/utils/state.ts | 7 ++++--- packages/state-transition/src/cache/epochCache.ts | 13 +++++++++++-- packages/state-transition/src/cache/pubkeyCache.ts | 2 +- packages/state-transition/src/cache/stateCache.ts | 5 +++-- packages/state-transition/src/index.ts | 2 +- packages/state-transition/src/util/genesis.ts | 4 ++-- packages/state-transition/test/perf/util.ts | 7 ++++--- .../test/unit/util/cachedBeaconState.test.ts | 4 ++-- packages/state-transition/test/utils/state.ts | 5 +++-- 12 files changed, 37 insertions(+), 21 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 694cb549595..d10b305030b 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -75,6 +75,7 @@ import {BlockAttributes, produceBlockBody} from "./produceBlock/produceBlockBody import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js"; import {BlockInput} from "./blocks/types.js"; import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js"; +import { createEmptyCarryoverData } from "@lodestar/state-transition/src/cache/epochCache.js"; /** * Arbitrary constants, blobs should be consumed immediately in the same slot they are produced. @@ -224,7 +225,7 @@ export class BeaconChain implements IBeaconChain { config, pubkey2index: new PubkeyIndexMap(), index2pubkey: [], - }); + }, createEmptyCarryoverData()); // Persist single global instance of state caches this.pubkey2index = cachedState.epochCtx.pubkey2index; diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 979476c6953..0036ec40157 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -13,6 +13,7 @@ import { BeaconStateAllForks, createEmptyEpochCacheImmutableData, getActiveValidatorIndices, + createEmptyCarryoverData } from "@lodestar/state-transition"; import {Logger} from "@lodestar/utils"; import {IEth1Provider} from "../../eth1/index.js"; @@ -86,7 +87,7 @@ export class GenesisBuilder implements IGenesisBuilder { } // TODO - PENDING: Ensure EpochCacheImmutableData is created only once - this.state = createCachedBeaconState(stateView, createEmptyEpochCacheImmutableData(config, stateView)); + this.state = createCachedBeaconState(stateView, createEmptyEpochCacheImmutableData(config, stateView), createEmptyCarryoverData()); this.config = this.state.config; this.activatedValidatorCount = getActiveValidatorIndices(stateView, GENESIS_EPOCH).length; } diff --git a/packages/beacon-node/test/utils/cachedBeaconState.ts b/packages/beacon-node/test/utils/cachedBeaconState.ts index 3efb16b6250..2a082d0dd14 100644 --- a/packages/beacon-node/test/utils/cachedBeaconState.ts +++ b/packages/beacon-node/test/utils/cachedBeaconState.ts @@ -3,6 +3,7 @@ import { BeaconStateCache, createCachedBeaconState, createEmptyEpochCacheImmutableData, + createEmptyCarryoverData, } from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; @@ -10,5 +11,5 @@ export function createCachedBeaconStateTest( state: T, chainConfig: ChainForkConfig ): T & BeaconStateCache { - return createCachedBeaconState(state, createEmptyEpochCacheImmutableData(chainConfig, state)); + return createCachedBeaconState(state, createEmptyEpochCacheImmutableData(chainConfig, state), createEmptyCarryoverData()); } diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 64c223acf4e..e8e6ea9e6c5 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -7,6 +7,7 @@ import { PubkeyIndexMap, CachedBeaconStateBellatrix, BeaconStateBellatrix, + createEmptyCarryoverData, } from "@lodestar/state-transition"; import {allForks, altair, bellatrix, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; @@ -104,7 +105,7 @@ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAl // This is a performance test, there's no need to have a global shared cache of keys pubkey2index: new PubkeyIndexMap(), index2pubkey: [], - }); + }, createEmptyCarryoverData()); } /** @@ -118,7 +119,7 @@ export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoc // This is a performance test, there's no need to have a global shared cache of keys pubkey2index: new PubkeyIndexMap(), index2pubkey: [], - }); + }, createEmptyCarryoverData()); } /** @@ -132,5 +133,5 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac // This is a performance test, there's no need to have a global shared cache of keys pubkey2index: new PubkeyIndexMap(), index2pubkey: [], - }); + }, createEmptyCarryoverData()); } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index ab8dbf19d04..5f13c790592 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -47,6 +47,10 @@ export type EpochCacheImmutableData = { index2pubkey: Index2PubkeyCache; }; +export type CarryoverData = { + unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; +} + export type EpochCacheOpts = { skipSyncCommitteeCache?: boolean; skipSyncPubkeys?: boolean; @@ -257,6 +261,7 @@ export class EpochCache { static createFromState( state: BeaconStateAllForks, {config, pubkey2index, index2pubkey}: EpochCacheImmutableData, + {unfinalizedPubkey2index}: CarryoverData, opts?: EpochCacheOpts ): EpochCache { // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches @@ -265,8 +270,6 @@ export class EpochCache { syncPubkeys(state, pubkey2index, index2pubkey); } - const unfinalizedIndex2pubkey = newUnfinalizedPubkeyIndexMap(); // TODO: Figure out how to populate it - const currentEpoch = computeEpochAtSlot(state.slot); const isGenesis = currentEpoch === GENESIS_EPOCH; const previousEpoch = isGenesis ? GENESIS_EPOCH : currentEpoch - 1; @@ -892,3 +895,9 @@ export function createEmptyEpochCacheImmutableData( index2pubkey: [], }; } + +export function createEmptyCarryoverData() { + return { + unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap() + }; +} \ No newline at end of file diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 931e9111698..0738ca96935 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -30,7 +30,7 @@ export function toMemoryEfficientHexStr(hex: Uint8Array | string): string { /** * - * A wrapper for calling immutable.js + * A wrapper for calling immutable.js. To abstract the initialization of UnfinalizedPubkeyIndexMap * */ export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index a42a5ea27e2..26d2af992d0 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -1,5 +1,5 @@ import {BeaconConfig} from "@lodestar/config"; -import {EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js"; +import {CarryoverData, EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js"; import { BeaconStateAllForks, BeaconStateExecutions, @@ -138,11 +138,12 @@ export type CachedBeaconStateExecutions = CachedBeaconState( state: T, immutableData: EpochCacheImmutableData, + carryoverData: CarryoverData, opts?: EpochCacheOpts ): T & BeaconStateCache { return getCachedBeaconState(state, { config: immutableData.config, - epochCtx: EpochCache.createFromState(state, immutableData, opts), + epochCtx: EpochCache.createFromState(state, immutableData, carryoverData, opts), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 32056ad3d41..dce7a4c5b2a 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -30,7 +30,7 @@ export { isStateBalancesNodesPopulated, isStateValidatorsNodesPopulated, } from "./cache/stateCache.js"; -export {EpochCache, EpochCacheImmutableData, createEmptyEpochCacheImmutableData} from "./cache/epochCache.js"; +export {EpochCache, EpochCacheImmutableData, createEmptyEpochCacheImmutableData, createEmptyCarryoverData} from "./cache/epochCache.js"; export {EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 1041c33d0eb..ccdd348f264 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -12,7 +12,7 @@ import {Bytes32, phase0, Root, ssz, TimeSeconds} from "@lodestar/types"; import {CachedBeaconStateAllForks, BeaconStateAllForks} from "../types.js"; import {createCachedBeaconState} from "../cache/stateCache.js"; -import {EpochCacheImmutableData} from "../cache/epochCache.js"; +import {EpochCacheImmutableData, createEmptyCarryoverData} from "../cache/epochCache.js"; import {processDeposit} from "../block/processDeposit.js"; import {computeEpochAtSlot} from "./epoch.js"; import {getActiveValidatorIndices} from "./validator.js"; @@ -232,7 +232,7 @@ export function initializeBeaconStateFromEth1( // - 3. interop state: Only supports starting from genesis at phase0 fork // So it's okay to skip syncing the sync committee cache here and expect it to be // populated latter when the altair fork happens for cases 2, 3. - const state = createCachedBeaconState(stateView, immutableData, {skipSyncCommitteeCache: true}); + const state = createCachedBeaconState(stateView, immutableData, createEmptyCarryoverData(), {skipSyncCommitteeCache: true}); applyTimestamp(config, state, eth1Timestamp); applyEth1BlockHash(state, eth1BlockHash); diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 316860fef44..b2b6e3fd5a5 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -20,6 +20,7 @@ import { newFilledArray, createCachedBeaconState, computeCommitteeCount, + createEmptyCarryoverData, } from "../../src/index.js"; import { CachedBeaconStateAllForks, @@ -129,7 +130,7 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean config: createBeaconConfig(config, state.genesisValidatorsRoot), pubkey2index, index2pubkey, - }); + }, createEmptyCarryoverData()); const currentEpoch = computeEpochAtSlot(state.slot - 1); const previousEpoch = currentEpoch - 1; @@ -227,7 +228,7 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), pubkey2index, index2pubkey, - }); + }, createEmptyCarryoverData()); } if (!altairCachedState23638) { altairCachedState23638 = processSlots( @@ -428,5 +429,5 @@ export function generateTestCachedBeaconStateOnlyValidators({ config: createBeaconConfig(config, state.genesisValidatorsRoot), pubkey2index, index2pubkey, - }); + }, createEmptyCarryoverData()); } diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index 1a34e2472b5..4fc781428bc 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -1,7 +1,7 @@ import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {createCachedBeaconState, PubkeyIndexMap} from "../../../src/index.js"; +import {createCachedBeaconState, PubkeyIndexMap, createEmptyCarryoverData} from "../../../src/index.js"; describe("CachedBeaconState", () => { it("Create empty CachedBeaconState", () => { @@ -11,6 +11,6 @@ describe("CachedBeaconState", () => { config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), pubkey2index: new PubkeyIndexMap(), index2pubkey: [], - }); + }, createEmptyCarryoverData()); }); }); diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index 614210e44af..e9b686a4e7e 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -21,7 +21,7 @@ import { PubkeyIndexMap, } from "../../src/index.js"; import {BeaconStateCache} from "../../src/cache/stateCache.js"; -import {EpochCacheOpts} from "../../src/cache/epochCache.js"; +import {EpochCacheOpts, createEmptyCarryoverData} from "../../src/cache/epochCache.js"; /** * Copy of BeaconState, but all fields are marked optional to allow for swapping out variables as needed. @@ -94,7 +94,7 @@ export function generateCachedState( // This is a test state, there's no need to have a global shared cache of keys pubkey2index: new PubkeyIndexMap(), index2pubkey: [], - }); + }, createEmptyCarryoverData()); } export function createCachedBeaconStateTest( @@ -110,6 +110,7 @@ export function createCachedBeaconStateTest( pubkey2index: new PubkeyIndexMap(), index2pubkey: [], }, + createEmptyCarryoverData(), opts ); } From 12e0a13e63743392686cdf6d79379f0f28664ce0 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 19:00:57 +0800 Subject: [PATCH 014/155] Fix typo --- .../state-transition/src/cache/epochCache.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 5f13c790592..af769031e1b 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -106,7 +106,7 @@ export class EpochCache { * Unique pubkey registry shared in the same fork. There should only exist one for the fork. * */ - unfinalizedPubkey2Index: UnfinalizedPubkeyIndexMap; + unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; /** @@ -204,7 +204,7 @@ export class EpochCache { config: BeaconConfig; globalPubkey2index: PubkeyIndexMap; globalIndex2pubkey: Index2PubkeyCache; - unfinalizedIndex2pubkey: UnfinalizedPubkeyIndexMap; + unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; proposers: number[]; proposersPrevEpoch: number[] | null; proposersNextEpoch: ProposersDeferred; @@ -229,7 +229,7 @@ export class EpochCache { this.config = data.config; this.globalPubkey2index = data.globalPubkey2index; this.globalIndex2pubkey = data.globalIndex2pubkey; - this.unfinalizedPubkey2Index = data.unfinalizedIndex2pubkey; + this.unfinalizedPubkey2index = data.unfinalizedPubkey2index; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; this.proposersNextEpoch = data.proposersNextEpoch; @@ -407,7 +407,7 @@ export class EpochCache { config, globalPubkey2index: pubkey2index, globalIndex2pubkey: index2pubkey, - unfinalizedIndex2pubkey, + unfinalizedPubkey2index, proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics proposersPrevEpoch: null, @@ -445,7 +445,7 @@ export class EpochCache { globalPubkey2index: this.globalPubkey2index, globalIndex2pubkey: this.globalIndex2pubkey, // Fork-aware cache needs to be cloned. But by the virtue of it being persistent, we don't need to do anything here - unfinalizedIndex2pubkey: this.unfinalizedPubkey2Index, + unfinalizedPubkey2index: this.unfinalizedPubkey2index, // Immutable data proposers: this.proposers, proposersPrevEpoch: this.proposersPrevEpoch, @@ -751,7 +751,7 @@ export class EpochCache { } getPubkeyIndex(pubkey: Uint8Array): ValidatorIndex | undefined { - return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2Index.get(toMemoryEfficientHexStr(pubkey)); + return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } /** @@ -760,7 +760,7 @@ export class EpochCache { * */ addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - this.unfinalizedPubkey2Index.set(toMemoryEfficientHexStr(pubkey), index); + this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } /** @@ -772,7 +772,7 @@ export class EpochCache { this.globalPubkey2index.set(pubkey, index); this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); - this.unfinalizedPubkey2Index.delete(toMemoryEfficientHexStr(pubkey)); + this.unfinalizedPubkey2index.delete(toMemoryEfficientHexStr(pubkey)); } getShufflingAtSlot(slot: Slot): EpochShuffling { From f4cdc92ab6871c484842b1c18b0e04293ca16a99 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 19:39:57 +0800 Subject: [PATCH 015/155] Update usage of pubkeyCache --- .../src/api/impl/beacon/state/index.ts | 12 ++++++------ .../src/api/impl/beacon/state/utils.ts | 6 +++--- .../beacon-node/src/api/impl/validator/index.ts | 2 +- .../src/chain/validation/aggregateAndProof.ts | 2 +- .../signatureSets/contributionAndProof.ts | 2 +- .../validation/signatureSets/syncCommittee.ts | 2 +- .../signatureSets/syncCommitteeSelectionProof.ts | 2 +- .../syncCommitteeContributionAndProof.ts | 2 +- .../unit/api/impl/beacon/state/utils.test.ts | 16 ++++++++-------- .../state-transition/src/block/processDeposit.ts | 2 +- .../src/block/processSyncCommittee.ts | 2 +- .../state-transition/src/cache/epochCache.ts | 4 ++-- .../state-transition/src/cache/pubkeyCache.ts | 2 +- .../src/signatureSets/attesterSlashings.ts | 4 ++-- .../src/signatureSets/indexedAttestation.ts | 2 +- .../src/signatureSets/proposer.ts | 4 ++-- .../src/signatureSets/proposerSlashings.ts | 2 +- .../state-transition/src/signatureSets/randao.ts | 2 +- .../src/signatureSets/voluntaryExits.ts | 2 +- 19 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 54d663234af..525435ae46b 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -59,12 +59,12 @@ export function getBeaconStateApi({ const {state, executionOptimistic} = await resolveStateId(chain, stateId); const currentEpoch = getCurrentEpoch(state); const {validators, balances} = state; // Get the validators sub tree once for all the loop - const {pubkey2index} = chain.getHeadState().epochCtx; + const pubkey2indexFn = chain.getHeadState().epochCtx.getValidatorIndex; const validatorResponses: routes.beacon.ValidatorResponse[] = []; if (filters?.id) { for (const id of filters.id) { - const resp = getStateValidatorIndex(id, state, pubkey2index); + const resp = getStateValidatorIndex(id, state, pubkey2indexFn); if (resp.valid) { const validatorIndex = resp.validatorIndex; const validator = validators.getReadonly(validatorIndex); @@ -85,7 +85,7 @@ export function getBeaconStateApi({ data: validatorResponses, }; } else if (filters?.status) { - const validatorsByStatus = filterStateValidatorsByStatus(filters.status, state, pubkey2index, currentEpoch); + const validatorsByStatus = filterStateValidatorsByStatus(filters.status, state, pubkey2indexFn, currentEpoch); return { executionOptimistic, data: validatorsByStatus, @@ -108,9 +108,9 @@ export function getBeaconStateApi({ async getStateValidator(stateId, validatorId) { const {state, executionOptimistic} = await resolveStateId(chain, stateId); - const {pubkey2index} = chain.getHeadState().epochCtx; + const pubkey2indexFn = chain.getHeadState().epochCtx.getValidatorIndex; - const resp = getStateValidatorIndex(validatorId, state, pubkey2index); + const resp = getStateValidatorIndex(validatorId, state, pubkey2indexFn); if (!resp.valid) { throw new ApiError(resp.code, resp.reason); } @@ -140,7 +140,7 @@ export function getBeaconStateApi({ } balances.push({index: id, balance: state.balances.get(id)}); } else { - const index = headState.epochCtx.pubkey2index.get(id); + const index = headState.epochCtx.getValidatorIndex(id); if (index != null && index <= state.validators.length) { balances.push({index, balance: state.balances.get(index)}); } diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 3c17fa30ac6..ca540a3f380 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -111,7 +111,7 @@ export function toValidatorResponse( export function filterStateValidatorsByStatus( statuses: string[], state: BeaconStateAllForks, - pubkey2index: PubkeyIndexMap, + pubkey2index: (arg: BLSPubkey) => number | undefined, currentEpoch: Epoch ): routes.beacon.ValidatorResponse[] { const responses: routes.beacon.ValidatorResponse[] = []; @@ -136,7 +136,7 @@ type StateValidatorIndexResponse = {valid: true; validatorIndex: number} | {vali export function getStateValidatorIndex( id: routes.beacon.ValidatorId | BLSPubkey, state: BeaconStateAllForks, - pubkey2index: PubkeyIndexMap + pubkey2indexFn: (arg: BLSPubkey) => number | undefined, ): StateValidatorIndexResponse { let validatorIndex: ValidatorIndex | undefined; if (typeof id === "string") { @@ -161,7 +161,7 @@ export function getStateValidatorIndex( } // typeof id === Uint8Array - validatorIndex = pubkey2index.get(id as BLSPubkey); + validatorIndex = pubkey2indexFn(id as BLSPubkey); if (validatorIndex === undefined) { return {valid: false, code: 404, reason: "Validator pubkey not found in state"}; } diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 2a29c4426ee..07b33e6941a 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -823,7 +823,7 @@ export function getValidatorApi({ const filteredRegistrations = registrations.filter((registration) => { const {pubkey} = registration.message; - const validatorIndex = headState.epochCtx.pubkey2index.get(pubkey); + const validatorIndex = headState.epochCtx.getValidatorIndex(pubkey); if (validatorIndex === undefined) return false; const validator = headState.validators.getReadonly(validatorIndex); diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 0cd96a8278e..31625508f7f 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -185,7 +185,7 @@ async function validateAggregateAndProof( // by the validator with index aggregate_and_proof.aggregator_index. // [REJECT] The aggregator signature, signed_aggregate_and_proof.signature, is valid. // [REJECT] The signature of aggregate is valid. - const aggregator = attHeadState.epochCtx.index2pubkey[aggregateAndProof.aggregatorIndex]; + const aggregator = attHeadState.epochCtx.getPubkey(aggregateAndProof.aggregatorIndex); let indexedAttestationSignatureSet: ISignatureSet; if (cachedAttData) { const {signingRoot} = cachedAttData; diff --git a/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts index 21e447b8367..2a46dd048b0 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts @@ -20,7 +20,7 @@ export function getContributionAndProofSignatureSet( const signingData = signedContributionAndProof.message; return { type: SignatureSetType.single, - pubkey: epochCtx.index2pubkey[signedContributionAndProof.message.aggregatorIndex], + pubkey: epochCtx.getPubkey(signedContributionAndProof.message.aggregatorIndex), signingRoot: computeSigningRoot(ssz.altair.ContributionAndProof, signingData, domain), signature: signedContributionAndProof.signature, }; diff --git a/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts b/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts index ce2b2e2484a..e82382eda5c 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts @@ -15,7 +15,7 @@ export function getSyncCommitteeSignatureSet( return { type: SignatureSetType.single, - pubkey: state.epochCtx.index2pubkey[syncCommittee.validatorIndex], + pubkey: state.epochCtx.getPubkey(syncCommittee.validatorIndex), signingRoot: computeSigningRoot(ssz.Root, syncCommittee.beaconBlockRoot, domain), signature: syncCommittee.signature, }; diff --git a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts index 14fcfad2b92..fe17946dcc0 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts @@ -20,7 +20,7 @@ export function getSyncCommitteeSelectionProofSignatureSet( }; return { type: SignatureSetType.single, - pubkey: epochCtx.index2pubkey[contributionAndProof.aggregatorIndex], + pubkey: epochCtx.getPubkey(contributionAndProof.aggregatorIndex), signingRoot: computeSigningRoot(ssz.altair.SyncAggregatorSelectionData, signingData, domain), signature: contributionAndProof.selectionProof, }; diff --git a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts index 3f9351f2d0d..8bc241afef8 100644 --- a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts +++ b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts @@ -74,7 +74,7 @@ export async function validateSyncCommitteeGossipContributionAndProof( // > Checked in validateGossipSyncCommitteeExceptSig() const participantPubkeys = syncCommitteeParticipantIndices.map( - (validatorIndex) => headState.epochCtx.index2pubkey[validatorIndex] + (validatorIndex) => headState.epochCtx.getPubkey(validatorIndex) ); const signatureSets = [ // [REJECT] The contribution_and_proof.selection_proof is a valid signature of the SyncAggregatorSelectionData diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index 94972be77c4..974c807df00 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -107,39 +107,39 @@ describe("beacon state api utils", function () { describe("getStateValidatorIndex", async function () { const state = generateCachedAltairState(); - const pubkey2index = state.epochCtx.pubkey2index; + const pubkey2indexFn = state.epochCtx.getValidatorIndex; it("should return valid: false on invalid input", () => { - expect(getStateValidatorIndex("foo", state, pubkey2index).valid, "invalid validator id number").to.equal(false); - expect(getStateValidatorIndex("0xfoo", state, pubkey2index).valid, "invalid hex").to.equal(false); + expect(getStateValidatorIndex("foo", state, pubkey2indexFn).valid, "invalid validator id number").to.equal(false); + expect(getStateValidatorIndex("0xfoo", state, pubkey2indexFn).valid, "invalid hex").to.equal(false); }); it("should return valid: false on validator indices / pubkeys not in the state", () => { expect( - getStateValidatorIndex(String(state.validators.length), state, pubkey2index).valid, + getStateValidatorIndex(String(state.validators.length), state, pubkey2indexFn).valid, "validator id not in state" ).to.equal(false); - expect(getStateValidatorIndex("0xabcd", state, pubkey2index).valid, "validator pubkey not in state").to.equal( + expect(getStateValidatorIndex("0xabcd", state, pubkey2indexFn).valid, "validator pubkey not in state").to.equal( false ); }); it("should return valid: true on validator indices / pubkeys in the state", () => { const index = state.validators.length - 1; - const resp1 = getStateValidatorIndex(String(index), state, pubkey2index); + const resp1 = getStateValidatorIndex(String(index), state, pubkey2indexFn); if (resp1.valid) { expect(resp1.validatorIndex).to.equal(index); } else { expect.fail("validator index should be found - validator index input"); } const pubkey = state.validators.get(index).pubkey; - const resp2 = getStateValidatorIndex(pubkey, state, pubkey2index); + const resp2 = getStateValidatorIndex(pubkey, state, pubkey2indexFn); if (resp2.valid) { expect(resp2.validatorIndex).to.equal(index); } else { expect.fail("validator index should be found - Uint8Array input"); } - const resp3 = getStateValidatorIndex(toHexString(pubkey), state, pubkey2index); + const resp3 = getStateValidatorIndex(toHexString(pubkey), state, pubkey2indexFn); if (resp3.valid) { expect(resp3.validatorIndex).to.equal(index); } else { diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 611f89429d9..303c714d42d 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -43,7 +43,7 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, const pubkey = deposit.data.pubkey; // Drop tree const amount = deposit.data.amount; - const cachedIndex = epochCtx.getPubkeyIndex(pubkey); + const cachedIndex = epochCtx.getValidatorIndex(pubkey); if (cachedIndex === undefined || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { // verify the deposit signature (proof of posession) which is not checked by the deposit contract const depositMessage = { diff --git a/packages/state-transition/src/block/processSyncCommittee.ts b/packages/state-transition/src/block/processSyncCommittee.ts index e0bfc318e05..75bd07c4cc5 100644 --- a/packages/state-transition/src/block/processSyncCommittee.ts +++ b/packages/state-transition/src/block/processSyncCommittee.ts @@ -104,7 +104,7 @@ export function getSyncCommitteeSignatureSet( return { type: SignatureSetType.aggregate, - pubkeys: participantIndices.map((i) => epochCtx.index2pubkey[i]), + pubkeys: participantIndices.map((i) => epochCtx.getPubkey(i)), signingRoot: computeSigningRoot(ssz.Root, rootSigned, domain), signature, }; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index af769031e1b..93fad40089c 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -29,7 +29,7 @@ import {computeEpochShuffling, EpochShuffling} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr, newUnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; +import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr, newUnfinalizedPubkeyIndexMap, PubkeyHex} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { computeSyncCommitteeCache, @@ -750,7 +750,7 @@ export class EpochCache { return this.globalIndex2pubkey[index]; } - getPubkeyIndex(pubkey: Uint8Array): ValidatorIndex | undefined { + getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 0738ca96935..34855c7189a 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -7,7 +7,7 @@ import {BeaconStateAllForks} from "./types.js"; export type Index2PubkeyCache = PublicKey[]; export type UnfinalizedPubkeyIndexMap = immutable.Map; -type PubkeyHex = string; +export type PubkeyHex = string; /** * toHexString() creates hex strings via string concatenation, which are very memory inneficient. diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 370d48a7d2f..071b084aef0 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -27,13 +27,13 @@ export function getIndexedAttestationBigintSignatureSet( state: CachedBeaconStateAllForks, indexedAttestation: phase0.IndexedAttestationBigint ): ISignatureSet { - const {index2pubkey} = state.epochCtx; + const index2pubkey = state.epochCtx.getPubkey; const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); return { type: SignatureSetType.aggregate, - pubkeys: indexedAttestation.attestingIndices.map((i) => index2pubkey[i]), + pubkeys: indexedAttestation.attestingIndices.map((i) => index2pubkey(i)), signingRoot: computeSigningRoot(ssz.phase0.AttestationDataBigint, indexedAttestation.data, domain), signature: indexedAttestation.signature, }; diff --git a/packages/state-transition/src/signatureSets/indexedAttestation.ts b/packages/state-transition/src/signatureSets/indexedAttestation.ts index b5c48a20c9d..e600c1c5993 100644 --- a/packages/state-transition/src/signatureSets/indexedAttestation.ts +++ b/packages/state-transition/src/signatureSets/indexedAttestation.ts @@ -24,7 +24,7 @@ export function getAttestationWithIndicesSignatureSet( attestingIndices: number[] ): ISignatureSet { return createAggregateSignatureSetFromComponents( - attestingIndices.map((i) => state.epochCtx.index2pubkey[i]), + attestingIndices.map((i) => state.epochCtx.getPubkey(i)), getAttestationDataSigningRoot(state, attestation.data), attestation.signature ); diff --git a/packages/state-transition/src/signatureSets/proposer.ts b/packages/state-transition/src/signatureSets/proposer.ts index a00bcacc7c9..a98bebf37c6 100644 --- a/packages/state-transition/src/signatureSets/proposer.ts +++ b/packages/state-transition/src/signatureSets/proposer.ts @@ -25,7 +25,7 @@ export function getBlockProposerSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.index2pubkey[signedBlock.message.proposerIndex], + pubkey: epochCtx.getPubkey(signedBlock.message.proposerIndex), signingRoot: computeSigningRoot(blockType, signedBlock.message, domain), signature: signedBlock.signature, }; @@ -42,7 +42,7 @@ export function getBlobProposerSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.index2pubkey[signedBlob.message.proposerIndex], + pubkey: epochCtx.getPubkey(signedBlob.message.proposerIndex), signingRoot: computeSigningRoot(blockType, signedBlob.message, domain), signature: signedBlob.signature, }; diff --git a/packages/state-transition/src/signatureSets/proposerSlashings.ts b/packages/state-transition/src/signatureSets/proposerSlashings.ts index 46be30c0636..68bcdbd7d1f 100644 --- a/packages/state-transition/src/signatureSets/proposerSlashings.ts +++ b/packages/state-transition/src/signatureSets/proposerSlashings.ts @@ -11,7 +11,7 @@ export function getProposerSlashingSignatureSets( proposerSlashing: phase0.ProposerSlashing ): ISignatureSet[] { const {epochCtx} = state; - const pubkey = epochCtx.index2pubkey[proposerSlashing.signedHeader1.message.proposerIndex]; + const pubkey = epochCtx.getPubkey(proposerSlashing.signedHeader1.message.proposerIndex); // In state transition, ProposerSlashing headers are only partially validated. Their slot could be higher than the // clock and the slashing would still be valid. Must use bigint variants to hash correctly to all possible values diff --git a/packages/state-transition/src/signatureSets/randao.ts b/packages/state-transition/src/signatureSets/randao.ts index 4fc8b77e4e3..fc987592538 100644 --- a/packages/state-transition/src/signatureSets/randao.ts +++ b/packages/state-transition/src/signatureSets/randao.ts @@ -27,7 +27,7 @@ export function getRandaoRevealSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.index2pubkey[block.proposerIndex], + pubkey: epochCtx.getPubkey(block.proposerIndex), signingRoot: computeSigningRoot(ssz.Epoch, epoch, domain), signature: block.body.randaoReveal, }; diff --git a/packages/state-transition/src/signatureSets/voluntaryExits.ts b/packages/state-transition/src/signatureSets/voluntaryExits.ts index bb86ef41777..550d8b5dec6 100644 --- a/packages/state-transition/src/signatureSets/voluntaryExits.ts +++ b/packages/state-transition/src/signatureSets/voluntaryExits.ts @@ -28,7 +28,7 @@ export function getVoluntaryExitSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.index2pubkey[signedVoluntaryExit.message.validatorIndex], + pubkey: epochCtx.getPubkey(signedVoluntaryExit.message.validatorIndex), signingRoot: computeSigningRoot(ssz.phase0.VoluntaryExit, signedVoluntaryExit.message, domain), signature: signedVoluntaryExit.signature, }; From fb3efff9c8d4549924eefa6190ee9405006570c0 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 20:06:04 +0800 Subject: [PATCH 016/155] Update pubkeyCache usage --- .../beacon-node/test/perf/api/impl/validator/attester.test.ts | 2 +- packages/state-transition/test/unit/upgradeState.test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts b/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts index 10527fdf94b..6752f3b0224 100644 --- a/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts +++ b/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts @@ -35,7 +35,7 @@ describe("api / impl / validator", () => { noThreshold: true, fn: () => { for (let i = 0; i < reqCount; i++) { - const pubkey = state.epochCtx.index2pubkey[i]; + const pubkey = state.epochCtx.getPubkey(i); pubkey.toBytes(PointFormat.compressed); } }, diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 13ec613d69b..7e78db0ecdd 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; -import {createCachedBeaconState, PubkeyIndexMap} from "@lodestar/state-transition"; +import {createCachedBeaconState, PubkeyIndexMap, createEmptyCarryoverData} from "@lodestar/state-transition"; import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {config as chainConfig} from "@lodestar/config/default"; @@ -18,6 +18,7 @@ describe("upgradeState", () => { pubkey2index: new PubkeyIndexMap(), index2pubkey: [], }, + createEmptyCarryoverData(), {skipSyncCommitteeCache: true} ); const newState = upgradeStateToDeneb(stateView); From bc3dc21d2da2f27b2bbf1855c34765ec43a0898c Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 20:30:38 +0800 Subject: [PATCH 017/155] Fix lint --- .../src/api/impl/beacon/state/utils.ts | 4 +- packages/beacon-node/src/chain/chain.ts | 22 +++++---- .../beacon-node/src/chain/genesis/genesis.ts | 8 +++- .../syncCommitteeContributionAndProof.ts | 4 +- .../test/utils/cachedBeaconState.ts | 6 ++- packages/beacon-node/test/utils/state.ts | 48 ++++++++++++------- .../state-transition/src/cache/epochCache.ts | 38 ++++++++------- .../state-transition/src/cache/pubkeyCache.ts | 8 ++-- .../state-transition/src/cache/stateCache.ts | 4 +- packages/state-transition/src/index.ts | 7 ++- packages/state-transition/src/util/genesis.ts | 4 +- packages/state-transition/test/perf/util.ts | 42 ++++++++++------ .../test/unit/util/cachedBeaconState.test.ts | 14 ++++-- packages/state-transition/test/utils/state.ts | 16 ++++--- 14 files changed, 139 insertions(+), 86 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index ca540a3f380..c67fde5564e 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -1,7 +1,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {routes} from "@lodestar/api"; import {FAR_FUTURE_EPOCH, GENESIS_SLOT} from "@lodestar/params"; -import {BeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; +import {BeaconStateAllForks} from "@lodestar/state-transition"; import {BLSPubkey, phase0} from "@lodestar/types"; import {Epoch, ValidatorIndex} from "@lodestar/types"; import {IBeaconChain, StateGetOpts} from "../../../../chain/index.js"; @@ -136,7 +136,7 @@ type StateValidatorIndexResponse = {valid: true; validatorIndex: number} | {vali export function getStateValidatorIndex( id: routes.beacon.ValidatorId | BLSPubkey, state: BeaconStateAllForks, - pubkey2indexFn: (arg: BLSPubkey) => number | undefined, + pubkey2indexFn: (arg: BLSPubkey) => number | undefined ): StateValidatorIndexResponse { let validatorIndex: ValidatorIndex | undefined; if (typeof id === "string") { diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index d10b305030b..94fa6d3a0ea 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -31,6 +31,7 @@ import {ProcessShutdownCallback} from "@lodestar/validator"; import {Logger, isErrorAborted, pruneSetToMax, sleep, toHex} from "@lodestar/utils"; import {ForkSeq, SLOTS_PER_EPOCH, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; +import {createEmptyCarryoverData} from "@lodestar/state-transition/src/cache/epochCache.js"; import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js"; import {IBeaconDb} from "../db/index.js"; import {Metrics} from "../metrics/index.js"; @@ -75,7 +76,6 @@ import {BlockAttributes, produceBlockBody} from "./produceBlock/produceBlockBody import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js"; import {BlockInput} from "./blocks/types.js"; import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js"; -import { createEmptyCarryoverData } from "@lodestar/state-transition/src/cache/epochCache.js"; /** * Arbitrary constants, blobs should be consumed immediately in the same slot they are produced. @@ -221,15 +221,19 @@ export class BeaconChain implements IBeaconChain { const cachedState = isCachedBeaconState(anchorState) && opts.skipCreateStateCacheIfAvailable ? anchorState - : createCachedBeaconState(anchorState, { - config, - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], - }, createEmptyCarryoverData()); + : createCachedBeaconState( + anchorState, + { + config, + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + createEmptyCarryoverData() + ); // Persist single global instance of state caches - this.pubkey2index = cachedState.epochCtx.pubkey2index; - this.index2pubkey = cachedState.epochCtx.index2pubkey; + this.pubkey2index = cachedState.epochCtx.globalPubkey2index; // TODO: Double check if these two are correct + this.index2pubkey = cachedState.epochCtx.globalIndex2pubkey; const stateCache = new StateContextCache({metrics}); const checkpointStateCache = new CheckpointStateCache({metrics}); @@ -486,7 +490,7 @@ export class BeaconChain implements IBeaconChain { ); const parentBlockRoot = fromHexString(head.blockRoot); const proposerIndex = state.epochCtx.getBeaconProposer(slot); - const proposerPubKey = state.epochCtx.index2pubkey[proposerIndex].toBytes(); + const proposerPubKey = state.epochCtx.getPubkey(proposerIndex).toBytes(); const {body, blobs, blockValue} = await produceBlockBody.call(this, blockType, state, { randaoReveal, diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 0036ec40157..33ea18b3420 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -13,7 +13,7 @@ import { BeaconStateAllForks, createEmptyEpochCacheImmutableData, getActiveValidatorIndices, - createEmptyCarryoverData + createEmptyCarryoverData, } from "@lodestar/state-transition"; import {Logger} from "@lodestar/utils"; import {IEth1Provider} from "../../eth1/index.js"; @@ -87,7 +87,11 @@ export class GenesisBuilder implements IGenesisBuilder { } // TODO - PENDING: Ensure EpochCacheImmutableData is created only once - this.state = createCachedBeaconState(stateView, createEmptyEpochCacheImmutableData(config, stateView), createEmptyCarryoverData()); + this.state = createCachedBeaconState( + stateView, + createEmptyEpochCacheImmutableData(config, stateView), + createEmptyCarryoverData() + ); this.config = this.state.config; this.activatedValidatorCount = getActiveValidatorIndices(stateView, GENESIS_EPOCH).length; } diff --git a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts index 8bc241afef8..58953e5206f 100644 --- a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts +++ b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts @@ -73,8 +73,8 @@ export async function validateSyncCommitteeGossipContributionAndProof( // i.e. state.validators[contribution_and_proof.aggregator_index].pubkey in get_sync_subcommittee_pubkeys(state, contribution.subcommittee_index). // > Checked in validateGossipSyncCommitteeExceptSig() - const participantPubkeys = syncCommitteeParticipantIndices.map( - (validatorIndex) => headState.epochCtx.getPubkey(validatorIndex) + const participantPubkeys = syncCommitteeParticipantIndices.map((validatorIndex) => + headState.epochCtx.getPubkey(validatorIndex) ); const signatureSets = [ // [REJECT] The contribution_and_proof.selection_proof is a valid signature of the SyncAggregatorSelectionData diff --git a/packages/beacon-node/test/utils/cachedBeaconState.ts b/packages/beacon-node/test/utils/cachedBeaconState.ts index 2a082d0dd14..818ec1a11af 100644 --- a/packages/beacon-node/test/utils/cachedBeaconState.ts +++ b/packages/beacon-node/test/utils/cachedBeaconState.ts @@ -11,5 +11,9 @@ export function createCachedBeaconStateTest( state: T, chainConfig: ChainForkConfig ): T & BeaconStateCache { - return createCachedBeaconState(state, createEmptyEpochCacheImmutableData(chainConfig, state), createEmptyCarryoverData()); + return createCachedBeaconState( + state, + createEmptyEpochCacheImmutableData(chainConfig, state), + createEmptyCarryoverData() + ); } diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index e8e6ea9e6c5..801787983ec 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -100,12 +100,16 @@ export function generateState( export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAllForks { const config = getConfig(ForkName.phase0); const state = generateState(opts, config); - return createCachedBeaconState(state, { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a performance test, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], - }, createEmptyCarryoverData()); + return createCachedBeaconState( + state, + { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a performance test, there's no need to have a global shared cache of keys + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + createEmptyCarryoverData() + ); } /** @@ -114,12 +118,16 @@ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAl export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoch = 0): CachedBeaconStateAllForks { const config = getConfig(ForkName.altair, altairForkEpoch); const state = generateState(opts, config); - return createCachedBeaconState(state, { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a performance test, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], - }, createEmptyCarryoverData()); + return createCachedBeaconState( + state, + { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a performance test, there's no need to have a global shared cache of keys + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + createEmptyCarryoverData() + ); } /** @@ -128,10 +136,14 @@ export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoc export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeaconStateBellatrix { const config = getConfig(ForkName.bellatrix); const state = generateState(opts, config); - return createCachedBeaconState(state as BeaconStateBellatrix, { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a performance test, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], - }, createEmptyCarryoverData()); + return createCachedBeaconState( + state as BeaconStateBellatrix, + { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a performance test, there's no need to have a global shared cache of keys + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + createEmptyCarryoverData() + ); } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 93fad40089c..420f132d863 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -29,7 +29,15 @@ import {computeEpochShuffling, EpochShuffling} from "../util/epochShuffling.js"; import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; -import {Index2PubkeyCache, PubkeyIndexMap, UnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr, newUnfinalizedPubkeyIndexMap, PubkeyHex} from "./pubkeyCache.js"; +import { + Index2PubkeyCache, + PubkeyIndexMap, + UnfinalizedPubkeyIndexMap, + syncPubkeys, + toMemoryEfficientHexStr, + newUnfinalizedPubkeyIndexMap, + PubkeyHex, +} from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { computeSyncCommitteeCache, @@ -49,7 +57,7 @@ export type EpochCacheImmutableData = { export type CarryoverData = { unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; -} +}; export type EpochCacheOpts = { skipSyncCommitteeCache?: boolean; @@ -88,7 +96,7 @@ export class EpochCache { * * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies - * + * * New: This would include only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. * * $VALIDATOR_COUNT x 192 char String -> Number Map @@ -98,17 +106,16 @@ export class EpochCache { * Unique globally shared pubkey registry. There should only exist one for the entire application. * * New: This would include only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. - * + * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ globalIndex2pubkey: Index2PubkeyCache; /** * Unique pubkey registry shared in the same fork. There should only exist one for the fork. - * + * */ unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; - /** * Indexes of the block proposers for the current epoch. * @@ -755,22 +762,22 @@ export class EpochCache { } /** - * + * * Add unfinalized pubkeys - * + * */ addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); + this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } /** - * + * * Given a validator whose activation_epoch has just been set, we move its pubkey from unfinalized cache to finalized cache - * + * */ addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { this.globalPubkey2index.set(pubkey, index); - this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); this.unfinalizedPubkey2index.delete(toMemoryEfficientHexStr(pubkey)); } @@ -854,7 +861,6 @@ export class EpochCache { this.effectiveBalanceIncrements[index] = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); } - } function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { @@ -896,8 +902,8 @@ export function createEmptyEpochCacheImmutableData( }; } -export function createEmptyCarryoverData() { +export function createEmptyCarryoverData(): CarryoverData { return { - unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap() + unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), }; -} \ No newline at end of file +} diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 34855c7189a..93ff4ba5e71 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -29,15 +29,14 @@ export function toMemoryEfficientHexStr(hex: Uint8Array | string): string { } /** - * + * * A wrapper for calling immutable.js. To abstract the initialization of UnfinalizedPubkeyIndexMap - * + * */ export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { return immutable.Map(); } - export class PubkeyIndexMap { // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address readonly map = new Map(); @@ -58,14 +57,13 @@ export class PubkeyIndexMap { } } - /** * Checks the pubkey indices against a state and adds missing pubkeys * * Mutates `pubkey2index` and `index2pubkey` * * If pubkey caches are empty: SLOW CODE - 🐢 - * + * * TODO: Deal with this */ export function syncPubkeys( diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 26d2af992d0..30dc5aec733 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -9,8 +9,6 @@ import { BeaconStateCapella, BeaconStateDeneb, } from "./types.js"; -import {PublicKey} from "@chainsafe/bls/types"; -import {ValidatorIndex} from "@lodestar/types"; export type BeaconStateCache = { config: BeaconConfig; @@ -210,4 +208,4 @@ export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean { return state.balances["nodesPopulated"] === true; -} \ No newline at end of file +} diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index dce7a4c5b2a..ecc46fe4d74 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -30,7 +30,12 @@ export { isStateBalancesNodesPopulated, isStateValidatorsNodesPopulated, } from "./cache/stateCache.js"; -export {EpochCache, EpochCacheImmutableData, createEmptyEpochCacheImmutableData, createEmptyCarryoverData} from "./cache/epochCache.js"; +export { + EpochCache, + EpochCacheImmutableData, + createEmptyEpochCacheImmutableData, + createEmptyCarryoverData, +} from "./cache/epochCache.js"; export {EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index ccdd348f264..e16b43625d6 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -232,7 +232,9 @@ export function initializeBeaconStateFromEth1( // - 3. interop state: Only supports starting from genesis at phase0 fork // So it's okay to skip syncing the sync committee cache here and expect it to be // populated latter when the altair fork happens for cases 2, 3. - const state = createCachedBeaconState(stateView, immutableData, createEmptyCarryoverData(), {skipSyncCommitteeCache: true}); + const state = createCachedBeaconState(stateView, immutableData, createEmptyCarryoverData(), { + skipSyncCommitteeCache: true, + }); applyTimestamp(config, state, eth1Timestamp); applyEth1BlockHash(state, eth1BlockHash); diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index b2b6e3fd5a5..90dbe886c0c 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -126,11 +126,15 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean if (!phase0CachedState23637) { const state = phase0State.clone(); state.slot -= 1; - phase0CachedState23637 = createCachedBeaconState(state, { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - pubkey2index, - index2pubkey, - }, createEmptyCarryoverData()); + phase0CachedState23637 = createCachedBeaconState( + state, + { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + pubkey2index, + index2pubkey, + }, + createEmptyCarryoverData() + ); const currentEpoch = computeEpochAtSlot(state.slot - 1); const previousEpoch = currentEpoch - 1; @@ -224,11 +228,15 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean if (!altairCachedState23637) { const state = origState.clone(); state.slot -= 1; - altairCachedState23637 = createCachedBeaconState(state, { - config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), - pubkey2index, - index2pubkey, - }, createEmptyCarryoverData()); + altairCachedState23637 = createCachedBeaconState( + state, + { + config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), + pubkey2index, + index2pubkey, + }, + createEmptyCarryoverData() + ); } if (!altairCachedState23638) { altairCachedState23638 = processSlots( @@ -425,9 +433,13 @@ export function generateTestCachedBeaconStateOnlyValidators({ throw Error(`Wrong number of validators in the state: ${state.validators.length} !== ${vc}`); } - return createCachedBeaconState(state, { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - pubkey2index, - index2pubkey, - }, createEmptyCarryoverData()); + return createCachedBeaconState( + state, + { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + pubkey2index, + index2pubkey, + }, + createEmptyCarryoverData() + ); } diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index 4fc781428bc..03da46235b5 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -7,10 +7,14 @@ describe("CachedBeaconState", () => { it("Create empty CachedBeaconState", () => { const emptyState = ssz.phase0.BeaconState.defaultViewDU(); - createCachedBeaconState(emptyState, { - config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], - }, createEmptyCarryoverData()); + createCachedBeaconState( + emptyState, + { + config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + createEmptyCarryoverData() + ); }); }); diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index e9b686a4e7e..60a9523c50e 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -89,12 +89,16 @@ export function generateCachedState( opts: TestBeaconState = {} ): CachedBeaconStateAllForks { const state = generateState(opts); - return createCachedBeaconState(state, { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a test state, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], - }, createEmptyCarryoverData()); + return createCachedBeaconState( + state, + { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a test state, there's no need to have a global shared cache of keys + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + createEmptyCarryoverData() + ); } export function createCachedBeaconStateTest( From b611312a0265ab27446af22f10c63f1d498a8083 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 5 Sep 2023 20:32:05 +0800 Subject: [PATCH 018/155] Fix lint --- packages/state-transition/src/cache/pubkeyCache.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 93ff4ba5e71..416d165f0df 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -37,6 +37,8 @@ export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { return immutable.Map(); } + + export class PubkeyIndexMap { // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address readonly map = new Map(); @@ -55,6 +57,7 @@ export class PubkeyIndexMap { set(key: Uint8Array, value: ValidatorIndex): void { this.map.set(toMemoryEfficientHexStr(key), value); } + } /** From 03184735ac1c68a7913ccdc01407c5dada4f0a88 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 14 Sep 2023 16:43:17 +0800 Subject: [PATCH 019/155] Add 6110 to ChainConfig --- packages/config/src/chainConfig/presets/mainnet.ts | 4 ++++ packages/config/src/chainConfig/presets/minimal.ts | 3 +++ packages/config/src/chainConfig/types.ts | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/packages/config/src/chainConfig/presets/mainnet.ts b/packages/config/src/chainConfig/presets/mainnet.ts index dcce1d82cf9..16f532d540b 100644 --- a/packages/config/src/chainConfig/presets/mainnet.ts +++ b/packages/config/src/chainConfig/presets/mainnet.ts @@ -45,6 +45,10 @@ export const chainConfig: ChainConfig = { DENEB_FORK_VERSION: b("0x04000000"), DENEB_FORK_EPOCH: Infinity, + // EIP-6110 + EIP6110_FORK_VERSION: b("0x05000000"), + EIP6110_FORK_EPOCH: Infinity, + // Time parameters // --------------------------------------------------------------- // 12 seconds diff --git a/packages/config/src/chainConfig/presets/minimal.ts b/packages/config/src/chainConfig/presets/minimal.ts index fc72cbff72d..428eab1e499 100644 --- a/packages/config/src/chainConfig/presets/minimal.ts +++ b/packages/config/src/chainConfig/presets/minimal.ts @@ -42,6 +42,9 @@ export const chainConfig: ChainConfig = { // Deneb DENEB_FORK_VERSION: b("0x04000001"), DENEB_FORK_EPOCH: Infinity, + // EIP-6110 + EIP6110_FORK_VERSION: b("0x05000000"), + EIP6110_FORK_EPOCH: Infinity, // Time parameters // --------------------------------------------------------------- diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index b2568d6fba5..4765373c171 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -40,6 +40,9 @@ export type ChainConfig = { // DENEB DENEB_FORK_VERSION: Uint8Array; DENEB_FORK_EPOCH: number; + // EIP-6110 + EIP6110_FORK_VERSION: Uint8Array; + EIP6110_FORK_EPOCH: number; // Time parameters SECONDS_PER_SLOT: number; @@ -92,6 +95,9 @@ export const chainConfigTypes: SpecTypes = { // DENEB DENEB_FORK_VERSION: "bytes", DENEB_FORK_EPOCH: "number", + // EIP-6110 + EIP6110_FORK_VERSION: "bytes", + EIP6110_FORK_EPOCH: "number", // Time parameters SECONDS_PER_SLOT: "number", From 7319af56c6baeedb01af13b0b72133c689977126 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 14 Sep 2023 16:44:36 +0800 Subject: [PATCH 020/155] Add 6110 to BeaconPreset --- packages/config/src/forkConfig/index.ts | 10 +++++++++- packages/params/src/forkName.ts | 2 ++ packages/params/src/index.ts | 2 ++ packages/params/src/presets/mainnet.ts | 3 +++ packages/params/src/presets/minimal.ts | 3 +++ packages/params/src/types.ts | 6 ++++++ 6 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index d630f1ddfc8..ffadb64a4d7 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -55,10 +55,18 @@ export function createForkConfig(config: ChainConfig): ForkConfig { prevVersion: config.CAPELLA_FORK_VERSION, prevForkName: ForkName.capella, }; + const eip6110: ForkInfo = { + name: ForkName.eip6110, + seq: ForkSeq.eip6110, + epoch: config.EIP6110_FORK_EPOCH, + version: config.EIP6110_FORK_VERSION, + prevVersion: config.DENEB_FORK_VERSION, + prevForkName: ForkName.deneb, + }; /** Forks in order order of occurence, `phase0` first */ // Note: Downstream code relies on proper ordering. - const forks = {phase0, altair, bellatrix, capella, deneb}; + const forks = {phase0, altair, bellatrix, capella, deneb, eip6110}; // Prevents allocating an array on every getForkInfo() call const forksAscendingEpochOrder = Object.values(forks); diff --git a/packages/params/src/forkName.ts b/packages/params/src/forkName.ts index a8b3579c611..08bbf5ed48c 100644 --- a/packages/params/src/forkName.ts +++ b/packages/params/src/forkName.ts @@ -7,6 +7,7 @@ export enum ForkName { bellatrix = "bellatrix", capella = "capella", deneb = "deneb", + eip6110 = "eip6110", } /** @@ -18,6 +19,7 @@ export enum ForkSeq { bellatrix = 2, capella = 3, deneb = 4, + eip6110 = 5, } export type ForkLightClient = Exclude; diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index b167f25ffd9..115aa98b350 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -100,6 +100,8 @@ export const { FIELD_ELEMENTS_PER_BLOB, MAX_BLOB_COMMITMENTS_PER_BLOCK, MAX_BLOBS_PER_BLOCK, + + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, } = activePreset; //////////// diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index f29b1668ac4..928a8fb388c 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -115,4 +115,7 @@ export const mainnetPreset: BeaconPreset = { FIELD_ELEMENTS_PER_BLOB: 4096, MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096, MAX_BLOBS_PER_BLOCK: 6, + + // EIP6110 + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 34d69004511..5ca74b0554d 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -122,4 +122,7 @@ export const minimalPreset: BeaconPreset = { FIELD_ELEMENTS_PER_BLOB: 4, MAX_BLOB_COMMITMENTS_PER_BLOCK: 16, MAX_BLOBS_PER_BLOCK: 6, + + // EIP6110 + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 67d258bdd0c..a941d695556 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -81,6 +81,9 @@ export type BeaconPreset = { FIELD_ELEMENTS_PER_BLOB: number; MAX_BLOB_COMMITMENTS_PER_BLOCK: number; MAX_BLOBS_PER_BLOCK: number; + + // EIP6110 + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number; }; /** @@ -165,6 +168,9 @@ export const beaconPresetTypes: BeaconPresetTypes = { FIELD_ELEMENTS_PER_BLOB: "number", MAX_BLOB_COMMITMENTS_PER_BLOCK: "number", MAX_BLOBS_PER_BLOCK: "number", + + // EIP6110 + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number", }; type BeaconPresetTypes = { From a6d04401144c08209b18ad6ac48483e5548bd4b5 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 14 Sep 2023 16:45:13 +0800 Subject: [PATCH 021/155] Define 6110 fork and container --- .../beacon-node/test/spec/presets/genesis.ts | 4 +- packages/state-transition/src/cache/types.ts | 6 +- packages/state-transition/src/util/genesis.ts | 1 + packages/types/package.json | 3 + packages/types/src/allForks/sszTypes.ts | 39 +++ packages/types/src/allForks/types.ts | 98 ++++--- packages/types/src/eip6110/index.ts | 3 + packages/types/src/eip6110/sszTypes.ts | 264 ++++++++++++++++++ packages/types/src/eip6110/types.ts | 33 +++ packages/types/src/primitive/sszTypes.ts | 1 + packages/types/src/sszTypes.ts | 1 + packages/types/src/types.ts | 1 + packages/validator/src/util/params.ts | 7 + 13 files changed, 421 insertions(+), 40 deletions(-) create mode 100644 packages/types/src/eip6110/index.ts create mode 100644 packages/types/src/eip6110/sszTypes.ts create mode 100644 packages/types/src/eip6110/types.ts diff --git a/packages/beacon-node/test/spec/presets/genesis.ts b/packages/beacon-node/test/spec/presets/genesis.ts index d80b56dbe65..3c5a47757d7 100644 --- a/packages/beacon-node/test/spec/presets/genesis.ts +++ b/packages/beacon-node/test/spec/presets/genesis.ts @@ -1,5 +1,5 @@ import {expect} from "chai"; -import {phase0, Root, ssz, TimeSeconds, allForks, deneb} from "@lodestar/types"; +import {phase0, Root, ssz, TimeSeconds, allForks, eip6110} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; import { BeaconStateAllForks, @@ -54,7 +54,7 @@ const genesisInitialization: TestRunnerFn; export type BeaconStateBellatrix = CompositeViewDU; export type BeaconStateCapella = CompositeViewDU; export type BeaconStateDeneb = CompositeViewDU; +export type BeaconStateEIP6110 = CompositeViewDU; // Union at the TreeViewDU level // - Works well as function argument and as generic type for allForks functions @@ -17,6 +18,7 @@ export type BeaconStateAllForks = | BeaconStateAltair | BeaconStateBellatrix | BeaconStateCapella - | BeaconStateDeneb; + | BeaconStateDeneb + | BeaconStateEIP6110; -export type BeaconStateExecutions = BeaconStateBellatrix | BeaconStateCapella | BeaconStateDeneb; +export type BeaconStateExecutions = BeaconStateBellatrix | BeaconStateCapella | BeaconStateDeneb | BeaconStateEIP6110; diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index e16b43625d6..87547e5f2a1 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -214,6 +214,7 @@ export function initializeBeaconStateFromEth1( | typeof ssz.bellatrix.ExecutionPayloadHeader | typeof ssz.capella.ExecutionPayloadHeader | typeof ssz.deneb.ExecutionPayloadHeader + | typeof ssz.eip6110.ExecutionPayloadHeader > ): CachedBeaconStateAllForks { const stateView = getGenesisBeaconState( diff --git a/packages/types/package.json b/packages/types/package.json index 522b1a56ab2..0cc8ad26e84 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -32,6 +32,9 @@ "./deneb": { "import": "./lib/deneb/index.js" }, + "./eip6110": { + "import": "./lib/eip6110/index.js" + }, "./phase0": { "import": "./lib/phase0/index.js" } diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 721416fd509..ce37dbf4b66 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -3,6 +3,7 @@ import {ssz as altair} from "../altair/index.js"; import {ssz as bellatrix} from "../bellatrix/index.js"; import {ssz as capella} from "../capella/index.js"; import {ssz as deneb} from "../deneb/index.js"; +import {ssz as eip6110} from "../eip6110/index.js"; /** * Index the ssz types that differ by fork @@ -44,6 +45,13 @@ export const allForks = { BeaconState: deneb.BeaconState, Metadata: altair.Metadata, }, + eip6110: { + BeaconBlockBody: eip6110.BeaconBlockBody, + BeaconBlock: eip6110.BeaconBlock, + SignedBeaconBlock: eip6110.SignedBeaconBlock, + BeaconState: eip6110.BeaconState, + Metadata: altair.Metadata, + }, }; /** @@ -85,6 +93,17 @@ export const allForksExecution = { SignedBuilderBid: deneb.SignedBuilderBid, SSEPayloadAttributes: deneb.SSEPayloadAttributes, }, + eip6110: { + BeaconBlockBody: eip6110.BeaconBlockBody, + BeaconBlock: eip6110.BeaconBlock, + SignedBeaconBlock: eip6110.SignedBeaconBlock, + BeaconState: eip6110.BeaconState, + ExecutionPayload: eip6110.ExecutionPayload, + ExecutionPayloadHeader: eip6110.ExecutionPayloadHeader, + BuilderBid: eip6110.BuilderBid, + SignedBuilderBid: eip6110.SignedBuilderBid, + SSEPayloadAttributes: eip6110.SSEPayloadAttributes, + }, }; /** @@ -107,6 +126,11 @@ export const allForksBlinded = { BeaconBlock: deneb.BlindedBeaconBlock, SignedBeaconBlock: deneb.SignedBlindedBeaconBlock, }, + eip6110: { + BeaconBlockBody: eip6110.BlindedBeaconBlockBody, + BeaconBlock: eip6110.BlindedBeaconBlock, + SignedBeaconBlock: eip6110.SignedBlindedBeaconBlock, + }, }; export const allForksLightClient = { @@ -150,6 +174,16 @@ export const allForksLightClient = { LightClientOptimisticUpdate: deneb.LightClientOptimisticUpdate, LightClientStore: deneb.LightClientStore, }, + eip6110: { + BeaconBlock: eip6110.BeaconBlock, + BeaconBlockBody: eip6110.BeaconBlockBody, + LightClientHeader: eip6110.LightClientHeader, + LightClientBootstrap: eip6110.LightClientBootstrap, + LightClientUpdate: eip6110.LightClientUpdate, + LightClientFinalityUpdate: eip6110.LightClientFinalityUpdate, + LightClientOptimisticUpdate: eip6110.LightClientOptimisticUpdate, + LightClientStore: eip6110.LightClientStore, + }, }; export const allForksBlobs = { @@ -158,4 +192,9 @@ export const allForksBlobs = { BlobSidecar: deneb.BlobSidecar, BlindedBlobSidecar: deneb.BlindedBlobSidecar, }, + eip6110: { + SignedBeaconBlockAndBlobSidecars: eip6110.SignedBeaconBlockAndBlobSidecars, + BlobSidecar: deneb.BlobSidecar, + BlindedBlobSidecar: deneb.BlindedBlobSidecar, + }, }; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index d6a0556c9be..baca3b7e389 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -4,12 +4,14 @@ import {ts as altair} from "../altair/index.js"; import {ts as bellatrix} from "../bellatrix/index.js"; import {ts as capella} from "../capella/index.js"; import {ts as deneb} from "../deneb/index.js"; +import {ts as eip6110} from "../eip6110/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; +import {ssz as eip6110Ssz} from "../eip6110/index.js"; // Re-export union types for types that are _known_ to differ @@ -18,47 +20,54 @@ export type BeaconBlockBody = | altair.BeaconBlockBody | bellatrix.BeaconBlockBody | capella.BeaconBlockBody - | deneb.BeaconBlockBody; + | deneb.BeaconBlockBody + | eip6110.BeaconBlockBody; export type BeaconBlock = | phase0.BeaconBlock | altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock - | deneb.BeaconBlock; + | deneb.BeaconBlock + | eip6110.BeaconBlock; export type SignedBeaconBlock = | phase0.SignedBeaconBlock | altair.SignedBeaconBlock | bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock - | deneb.SignedBeaconBlock; + | deneb.SignedBeaconBlock + | eip6110.SignedBeaconBlock; export type BeaconState = | phase0.BeaconState | altair.BeaconState | bellatrix.BeaconState | capella.BeaconState - | deneb.BeaconState; + | deneb.BeaconState + | eip6110.BeaconState; export type Metadata = phase0.Metadata | altair.Metadata; // For easy reference in the assemble block for building payloads -export type ExecutionBlockBody = bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody; +export type ExecutionBlockBody = bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody | eip6110.BeaconBlockBody; // These two additional types will also change bellatrix forward -export type ExecutionPayload = bellatrix.ExecutionPayload | capella.ExecutionPayload | deneb.ExecutionPayload; +export type ExecutionPayload = bellatrix.ExecutionPayload | capella.ExecutionPayload | deneb.ExecutionPayload | eip6110.ExecutionPayload; export type ExecutionPayloadHeader = | bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader - | deneb.ExecutionPayloadHeader; + | deneb.ExecutionPayloadHeader + | eip6110.ExecutionPayloadHeader; // Blinded types that will change across forks export type BlindedBeaconBlockBody = | bellatrix.BlindedBeaconBlockBody | capella.BlindedBeaconBlockBody - | deneb.BlindedBeaconBlockBody; -export type BlindedBeaconBlock = bellatrix.BlindedBeaconBlock | capella.BlindedBeaconBlock | deneb.BlindedBeaconBlock; + | deneb.BlindedBeaconBlockBody + | eip6110.BlindedBeaconBlockBody; +export type BlindedBeaconBlock = bellatrix.BlindedBeaconBlock | capella.BlindedBeaconBlock | deneb.BlindedBeaconBlock | eip6110.BlindedBeaconBlock; export type SignedBlindedBeaconBlock = | bellatrix.SignedBlindedBeaconBlock | capella.SignedBlindedBeaconBlock - | deneb.SignedBlindedBeaconBlock; + | deneb.SignedBlindedBeaconBlock + | eip6110.SignedBlindedBeaconBlock; // Full or blinded types export type FullOrBlindedExecutionPayload = @@ -68,36 +77,40 @@ export type FullOrBlindedBeaconBlockBody = BeaconBlockBody | BlindedBeaconBlockB export type FullOrBlindedBeaconBlock = BeaconBlock | BlindedBeaconBlock; export type FullOrBlindedSignedBeaconBlock = SignedBeaconBlock | SignedBlindedBeaconBlock; -export type FullOrBlindedBlobSidecar = deneb.BlobSidecar | deneb.BlindedBlobSidecar; +export type FullOrBlindedBlobSidecar = deneb.BlobSidecar | deneb.BlindedBlobSidecar ; export type FullOrBlindedSignedBlobSidecar = deneb.SignedBlobSidecar | deneb.SignedBlindedBlobSidecar; export type FullOrBlindedBlobSidecars = deneb.BlobSidecars | deneb.BlindedBlobSidecars; -export type BuilderBid = bellatrix.BuilderBid | capella.BuilderBid | deneb.BuilderBid; -export type SignedBuilderBid = bellatrix.SignedBuilderBid | capella.SignedBuilderBid | deneb.SignedBuilderBid; +export type BuilderBid = bellatrix.BuilderBid | capella.BuilderBid | deneb.BuilderBid | eip6110.BuilderBid; +export type SignedBuilderBid = bellatrix.SignedBuilderBid | capella.SignedBuilderBid | deneb.SignedBuilderBid | eip6110.SignedBuilderBid; -export type LightClientHeader = altair.LightClientHeader | capella.LightClientHeader | deneb.LightClientHeader; +export type LightClientHeader = altair.LightClientHeader | capella.LightClientHeader | deneb.LightClientHeader | eip6110.LightClientHeader; export type LightClientBootstrap = | altair.LightClientBootstrap | capella.LightClientBootstrap - | deneb.LightClientBootstrap; -export type LightClientUpdate = altair.LightClientUpdate | capella.LightClientUpdate | deneb.LightClientUpdate; + | deneb.LightClientBootstrap + | eip6110.LightClientBootstrap; +export type LightClientUpdate = altair.LightClientUpdate | capella.LightClientUpdate | deneb.LightClientUpdate | eip6110.LightClientUpdate; export type LightClientFinalityUpdate = | altair.LightClientFinalityUpdate | capella.LightClientFinalityUpdate - | deneb.LightClientFinalityUpdate; + | deneb.LightClientFinalityUpdate + | eip6110.LightClientFinalityUpdate; export type LightClientOptimisticUpdate = | altair.LightClientOptimisticUpdate | capella.LightClientOptimisticUpdate - | deneb.LightClientOptimisticUpdate; -export type LightClientStore = altair.LightClientStore | capella.LightClientStore | deneb.LightClientStore; + | deneb.LightClientOptimisticUpdate + | eip6110.LightClientOptimisticUpdate; +export type LightClientStore = altair.LightClientStore | capella.LightClientStore | deneb.LightClientStore | eip6110.LightClientStore; -export type SignedBeaconBlockAndBlobSidecars = deneb.SignedBeaconBlockAndBlobSidecars; +export type SignedBeaconBlockAndBlobSidecars = deneb.SignedBeaconBlockAndBlobSidecars | eip6110.SignedBeaconBlockAndBlobSidecars;; export type SSEPayloadAttributes = | bellatrix.SSEPayloadAttributes | capella.SSEPayloadAttributes - | deneb.SSEPayloadAttributes; + | deneb.SSEPayloadAttributes + | eip6110.SSEPayloadAttributes; /** * Types known to change between forks @@ -123,7 +136,7 @@ export type AllForksBlindedTypes = { }; export type AllForksLightClient = { - BeaconBlock: altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock; + BeaconBlock: altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock | eip6110.BeaconBlock; LightClientHeader: LightClientHeader; LightClientBootstrap: LightClientBootstrap; LightClientUpdate: LightClientUpdate; @@ -133,8 +146,8 @@ export type AllForksLightClient = { }; export type AllForksExecution = { - BeaconBlock: bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock; - BeaconBlockBody: bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody; + BeaconBlock: bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock | eip6110.BeaconBlock; + BeaconBlockBody: bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody | eip6110.BeaconBlockBody; }; /** @@ -173,6 +186,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + | typeof eip6110Ssz.BeaconBlockBody >; BeaconBlock: AllForksTypeOf< | typeof phase0Ssz.BeaconBlock @@ -180,6 +194,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock + | typeof eip6110Ssz.BeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof phase0Ssz.SignedBeaconBlock @@ -187,6 +202,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock + | typeof eip6110Ssz.SignedBeaconBlock >; BeaconState: AllForksTypeOf< | typeof phase0Ssz.BeaconState @@ -194,41 +210,44 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState + | typeof eip6110Ssz.BeaconState >; Metadata: AllForksTypeOf; }; export type AllForksExecutionSSZTypes = { BeaconBlockBody: AllForksTypeOf< - typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody | typeof eip6110Ssz.BeaconBlockBody >; BeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock + typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock | typeof eip6110Ssz.BeaconBlock >; SignedBeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock + typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock | typeof eip6110Ssz.SignedBeaconBlock >; BeaconState: AllForksTypeOf< - typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState + typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState | typeof eip6110Ssz.BeaconState >; ExecutionPayload: AllForksTypeOf< - typeof bellatrixSsz.ExecutionPayload | typeof capellaSsz.ExecutionPayload | typeof denebSsz.ExecutionPayload + typeof bellatrixSsz.ExecutionPayload | typeof capellaSsz.ExecutionPayload | typeof denebSsz.ExecutionPayload | typeof eip6110Ssz.ExecutionPayload >; ExecutionPayloadHeader: AllForksTypeOf< | typeof bellatrixSsz.ExecutionPayloadHeader | typeof capellaSsz.ExecutionPayloadHeader | typeof denebSsz.ExecutionPayloadHeader + | typeof eip6110Ssz.ExecutionPayloadHeader >; BuilderBid: AllForksTypeOf< - typeof bellatrixSsz.BuilderBid | typeof capellaSsz.BuilderBid | typeof denebSsz.BuilderBid + typeof bellatrixSsz.BuilderBid | typeof capellaSsz.BuilderBid | typeof denebSsz.BuilderBid | typeof eip6110Ssz.BuilderBid >; SignedBuilderBid: AllForksTypeOf< - typeof bellatrixSsz.SignedBuilderBid | typeof capellaSsz.SignedBuilderBid | typeof denebSsz.SignedBuilderBid + typeof bellatrixSsz.SignedBuilderBid | typeof capellaSsz.SignedBuilderBid | typeof denebSsz.SignedBuilderBid | typeof eip6110Ssz.SignedBuilderBid >; SSEPayloadAttributes: AllForksTypeOf< | typeof bellatrixSsz.SSEPayloadAttributes | typeof capellaSsz.SSEPayloadAttributes | typeof denebSsz.SSEPayloadAttributes + | typeof eip6110Ssz.SSEPayloadAttributes >; }; @@ -237,14 +256,16 @@ export type AllForksBlindedSSZTypes = { | typeof bellatrixSsz.BlindedBeaconBlockBody | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock + | typeof eip6110Ssz.BlindedBeaconBlock >; BeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.BlindedBeaconBlock | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock + typeof bellatrixSsz.BlindedBeaconBlock | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock | typeof eip6110Ssz.BlindedBeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof bellatrixSsz.SignedBlindedBeaconBlock | typeof capellaSsz.SignedBlindedBeaconBlock | typeof denebSsz.SignedBlindedBeaconBlock + | typeof eip6110Ssz.SignedBlindedBeaconBlock >; }; @@ -254,41 +275,46 @@ export type AllForksLightClientSSZTypes = { | typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock + | typeof eip6110Ssz.BeaconBlock >; BeaconBlockBody: AllForksTypeOf< | typeof altairSsz.BeaconBlockBody | typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + | typeof eip6110Ssz.BeaconBlockBody >; LightClientHeader: AllForksTypeOf< - typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader + typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader | typeof eip6110Ssz.LightClientHeader >; LightClientBootstrap: AllForksTypeOf< | typeof altairSsz.LightClientBootstrap | typeof capellaSsz.LightClientBootstrap | typeof denebSsz.LightClientBootstrap + | typeof eip6110Ssz.LightClientBootstrap >; LightClientUpdate: AllForksTypeOf< - typeof altairSsz.LightClientUpdate | typeof capellaSsz.LightClientUpdate | typeof denebSsz.LightClientUpdate + typeof altairSsz.LightClientUpdate | typeof capellaSsz.LightClientUpdate | typeof denebSsz.LightClientUpdate | typeof eip6110Ssz.LightClientUpdate >; LightClientFinalityUpdate: AllForksTypeOf< | typeof altairSsz.LightClientFinalityUpdate | typeof capellaSsz.LightClientFinalityUpdate | typeof denebSsz.LightClientFinalityUpdate + | typeof eip6110Ssz.LightClientFinalityUpdate >; LightClientOptimisticUpdate: AllForksTypeOf< | typeof altairSsz.LightClientOptimisticUpdate | typeof capellaSsz.LightClientOptimisticUpdate | typeof denebSsz.LightClientOptimisticUpdate + | typeof eip6110Ssz.LightClientOptimisticUpdate >; LightClientStore: AllForksTypeOf< - typeof altairSsz.LightClientStore | typeof capellaSsz.LightClientStore | typeof denebSsz.LightClientStore + typeof altairSsz.LightClientStore | typeof capellaSsz.LightClientStore | typeof denebSsz.LightClientStore | typeof eip6110Ssz.LightClientStore >; }; export type AllForksBlobsSSZTypes = { - SignedBeaconBlockAndBlobSidecars: AllForksTypeOf; + SignedBeaconBlockAndBlobSidecars: AllForksTypeOf; BlobSidecar: AllForksTypeOf; BlindedBlobSidecar: AllForksTypeOf; }; diff --git a/packages/types/src/eip6110/index.ts b/packages/types/src/eip6110/index.ts new file mode 100644 index 00000000000..7856cd72962 --- /dev/null +++ b/packages/types/src/eip6110/index.ts @@ -0,0 +1,3 @@ +export * from "./types.js"; +export * as ts from "./types.js"; +export * as ssz from "./sszTypes.js"; diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts new file mode 100644 index 00000000000..b61d92c3f30 --- /dev/null +++ b/packages/types/src/eip6110/sszTypes.ts @@ -0,0 +1,264 @@ +import {ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; +import { + HISTORICAL_ROOTS_LIMIT, + BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + SLOTS_PER_EPOCH, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, +} from "@lodestar/params"; +import {ssz as primitiveSsz} from "../primitive/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as altairSsz} from "../altair/index.js"; +import {ssz as bellatrixSsz} from "../bellatrix/index.js"; +import {ssz as capellaSsz} from "../capella/index.js"; +import {ssz as denebSsz} from "../deneb/index.js"; + +const { + UintNum64, + Slot, + Root, + BLSSignature, + UintBn256, + Bytes32, + BLSPubkey, + ValidatorIndex, + DepositIndex, + Gwei, +} = primitiveSsz; + + +export const DepositReceipt = new ContainerType( //good + { + pubkey: BLSPubkey, + withdrawalCredentials: Bytes32, + amount: Gwei, + signature: BLSSignature, + index: DepositIndex, + validatorIndex: ValidatorIndex, + }, + {typeName: "DepositReceipt", jsonCase: "eth2"} +); + +export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); + + +export const ExecutionPayload = new ContainerType( // good + { + ...denebSsz.ExecutionPayload.fields, + depositReceipts: DepositReceipts, // New in EIP6110 + }, + {typeName: "ExecutionPayload", jsonCase: "eth2"} +); + +export const ExecutionPayloadHeader = new ContainerType( // good + { + ...denebSsz.ExecutionPayloadHeader.fields, + depositReceiptsRoot: Root, // New in EIP6110 + }, + {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} +); + +// We have to preserve Fields ordering while changing the type of ExecutionPayload +export const BeaconBlockBody = new ContainerType( // good + { + ...altairSsz.BeaconBlockBody.fields, + executionPayload: ExecutionPayload, // Modified in EIP6110 + blsToExecutionChanges: denebSsz.BeaconBlockBody.fields.blsToExecutionChanges, + blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, + }, + {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const BeaconBlock = new ContainerType( // good + { + ...denebSsz.BeaconBlock.fields, + body: BeaconBlockBody, // Modified in EIP6110 + }, + {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedBeaconBlock = new ContainerType( // good + { + message: BeaconBlock, // Modified in EIP6110 + signature: BLSSignature, + }, + {typeName: "SignedBeaconBlock", jsonCase: "eth2"} +); + + +export const SignedBeaconBlockAndBlobSidecars = new ContainerType( // good + { + beaconBlock: SignedBeaconBlock, // Modified in EIP6110 + blobSidecars: denebSsz.SignedBeaconBlockAndBlobSidecars.fields.blobSidecars, + }, + {typeName: "SignedBeaconBlockAndBlobSidecars", jsonCase: "eth2"} +); + +export const BlindedBeaconBlockBody = new ContainerType( // good + { + ...altairSsz.BeaconBlockBody.fields, + executionPayloadHeader: ExecutionPayloadHeader, // Modified in EIP6110 + blsToExecutionChanges: denebSsz.BeaconBlockBody.fields.blsToExecutionChanges, + blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, + }, + {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const BlindedBeaconBlock = new ContainerType( // good + { + ...denebSsz.BlindedBeaconBlock.fields, + body: BlindedBeaconBlockBody, // Modified in EIP6110 + }, + {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedBlindedBeaconBlock = new ContainerType( // good + { + message: BlindedBeaconBlock, // Modified in EIP6110 + signature: BLSSignature, + }, + {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} +); + +export const BuilderBid = new ContainerType( // good + { + header: ExecutionPayloadHeader, // Modified in EIP6110 + value: UintBn256, + pubkey: BLSPubkey, + blobKzgCommitments: denebSsz.BuilderBid.fields.blobKzgCommitments, + }, + {typeName: "BuilderBid", jsonCase: "eth2"} +); + +export const SignedBuilderBid = new ContainerType( // good + { + message: BuilderBid, + signature: BLSSignature, + }, + {typeName: "SignedBuilderBid", jsonCase: "eth2"} +); + +// We don't spread deneb.BeaconState fields since we need to replace +// latestExecutionPayloadHeader and we cannot keep order doing that +export const BeaconState = new ContainerType( // good + { + genesisTime: UintNum64, + genesisValidatorsRoot: Root, + slot: primitiveSsz.Slot, + fork: phase0Ssz.Fork, + // History + latestBlockHeader: phase0Ssz.BeaconBlockHeader, + blockRoots: phase0Ssz.HistoricalBlockRoots, + stateRoots: phase0Ssz.HistoricalStateRoots, + // historical_roots Frozen in Capella, replaced by historical_summaries + historicalRoots: new ListCompositeType(Root, HISTORICAL_ROOTS_LIMIT), + // Eth1 + eth1Data: phase0Ssz.Eth1Data, + eth1DataVotes: phase0Ssz.Eth1DataVotes, + eth1DepositIndex: UintNum64, + // Registry + validators: phase0Ssz.Validators, + balances: phase0Ssz.Balances, + randaoMixes: phase0Ssz.RandaoMixes, + // Slashings + slashings: phase0Ssz.Slashings, + // Participation + previousEpochParticipation: altairSsz.EpochParticipation, + currentEpochParticipation: altairSsz.EpochParticipation, + // Finality + justificationBits: phase0Ssz.JustificationBits, + previousJustifiedCheckpoint: phase0Ssz.Checkpoint, + currentJustifiedCheckpoint: phase0Ssz.Checkpoint, + finalizedCheckpoint: phase0Ssz.Checkpoint, + // Inactivity + inactivityScores: altairSsz.InactivityScores, + // Sync + currentSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommittee: altairSsz.SyncCommittee, + // Execution + latestExecutionPayloadHeader: ExecutionPayloadHeader, // Modified in EIP6110 + // Withdrawals + nextWithdrawalIndex: capellaSsz.BeaconState.fields.nextWithdrawalIndex, + nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, + // Deep history valid from Capella onwards + historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, + depositReceiptsStartIndex: UintNum64, // New in EIP6110 + }, + {typeName: "BeaconState", jsonCase: "eth2"} +); + +export const LightClientHeader = new ContainerType( // good + { + beacon: phase0Ssz.BeaconBlockHeader, + execution: ExecutionPayloadHeader, // Modified in EIP6110 + executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), + }, + {typeName: "LightClientHeader", jsonCase: "eth2"} +); + +export const LightClientBootstrap = new ContainerType( // good + { + header: LightClientHeader, + currentSyncCommittee: altairSsz.SyncCommittee, + currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, + }, + {typeName: "LightClientBootstrap", jsonCase: "eth2"} +); + +export const LightClientUpdate = new ContainerType( // good + { + attestedHeader: LightClientHeader, + nextSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientUpdate", jsonCase: "eth2"} +); + +export const LightClientFinalityUpdate = new ContainerType( // good + { + attestedHeader: LightClientHeader, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} +); + +export const LightClientOptimisticUpdate = new ContainerType( //good + { + attestedHeader: LightClientHeader, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} +); + +export const LightClientStore = new ContainerType( //good + { + snapshot: LightClientBootstrap, + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), + }, + {typeName: "LightClientStore", jsonCase: "eth2"} +); + +// PayloadAttributes primarily for SSE event +export const PayloadAttributes = new ContainerType( //good + { + ...capellaSsz.PayloadAttributes.fields, + parentBeaconBlockRoot: Root, + }, + {typeName: "PayloadAttributes", jsonCase: "eth2"} +); + +export const SSEPayloadAttributes = new ContainerType( //good + { + ...bellatrixSsz.SSEPayloadAttributesCommon.fields, + payloadAttributes: PayloadAttributes, + }, + {typeName: "SSEPayloadAttributes", jsonCase: "eth2"} +); diff --git a/packages/types/src/eip6110/types.ts b/packages/types/src/eip6110/types.ts new file mode 100644 index 00000000000..dcb20382dcc --- /dev/null +++ b/packages/types/src/eip6110/types.ts @@ -0,0 +1,33 @@ +import {ValueOf} from "@chainsafe/ssz"; +import * as ssz from "./sszTypes.js"; + +export type DepositReceipt = ValueOf; +export type DepositReceipts = ValueOf; + +export type ExecutionPayload = ValueOf; +export type ExecutionPayloadHeader = ValueOf; + +export type BeaconBlockBody = ValueOf; +export type BeaconBlock = ValueOf; +export type SignedBeaconBlock = ValueOf; + +export type SignedBeaconBlockAndBlobSidecars = ValueOf; + +export type BeaconState = ValueOf; + +export type BlindedBeaconBlockBody = ValueOf; +export type BlindedBeaconBlock = ValueOf; +export type SignedBlindedBeaconBlock = ValueOf; + +export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadHeader; + +export type BuilderBid = ValueOf; +export type SignedBuilderBid = ValueOf; +export type SSEPayloadAttributes = ValueOf; + +export type LightClientHeader = ValueOf; +export type LightClientBootstrap = ValueOf; +export type LightClientUpdate = ValueOf; +export type LightClientFinalityUpdate = ValueOf; +export type LightClientOptimisticUpdate = ValueOf; +export type LightClientStore = ValueOf; diff --git a/packages/types/src/primitive/sszTypes.ts b/packages/types/src/primitive/sszTypes.ts index 65c81d1247b..42c7b32ae0d 100644 --- a/packages/types/src/primitive/sszTypes.ts +++ b/packages/types/src/primitive/sszTypes.ts @@ -49,6 +49,7 @@ export const SubcommitteeIndex = UintNum64; */ export const ValidatorIndex = UintNum64; export const WithdrawalIndex = UintNum64; +export const DepositIndex = UintNum64; export const Gwei = UintBn64; export const Wei = UintBn256; export const Root = new ByteVectorType(32); diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index 2a7df948a44..9f0ebec9bff 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -4,6 +4,7 @@ export {ssz as altair} from "./altair/index.js"; export {ssz as bellatrix} from "./bellatrix/index.js"; export {ssz as capella} from "./capella/index.js"; export {ssz as deneb} from "./deneb/index.js"; +export {ssz as eip6110} from "./eip6110/index.js"; import {ssz as allForksSsz} from "./allForks/index.js"; export const allForks = allForksSsz.allForks; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index e2e416fa366..256b45b8585 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -6,6 +6,7 @@ export {ts as altair} from "./altair/index.js"; export {ts as bellatrix} from "./bellatrix/index.js"; export {ts as capella} from "./capella/index.js"; export {ts as deneb} from "./deneb/index.js"; +export {ts as eip6110} from "./eip6110/index.js"; export {ts as allForks} from "./allForks/index.js"; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 61034c13302..ada25155ac1 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -73,6 +73,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Thu, 14 Sep 2023 17:51:47 +0800 Subject: [PATCH 022/155] Add V6110 api to execution engine --- .../beacon-node/src/execution/engine/http.ts | 10 ++- .../src/execution/engine/interface.ts | 4 +- .../beacon-node/src/execution/engine/mock.ts | 4 ++ .../src/execution/engine/payloadIdCache.ts | 8 +++ .../beacon-node/src/execution/engine/types.ts | 62 +++++++++++++++++-- 5 files changed, 78 insertions(+), 10 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index 331e24fa795..d82545254df 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -176,7 +176,9 @@ export class ExecutionEngineHttp implements IExecutionEngine { parentBlockRoot?: Root ): Promise { const method = - ForkSeq[fork] >= ForkSeq.deneb + ForkSeq[fork] >= ForkSeq.eip6110 + ? "engine_newPayloadV6110" + : ForkSeq[fork] >= ForkSeq.deneb ? "engine_newPayloadV3" : ForkSeq[fork] >= ForkSeq.capella ? "engine_newPayloadV2" @@ -196,7 +198,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { const serializedVersionedHashes = serializeVersionedHashes(versionedHashes); const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot); - const method = "engine_newPayloadV3"; + const method = ForkSeq[fork] >= ForkSeq.eip6110 ? "engine_newPayloadV6110" : "engine_newPayloadV3"; engineRequest = { method, params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot], @@ -365,7 +367,9 @@ export class ExecutionEngineHttp implements IExecutionEngine { payloadId: PayloadId ): Promise<{executionPayload: allForks.ExecutionPayload; blockValue: Wei; blobsBundle?: BlobsBundle}> { const method = - ForkSeq[fork] >= ForkSeq.deneb + ForkSeq[fork] >= ForkSeq.eip6110 + ? "engine_getPayloadV6110" + : ForkSeq[fork] >= ForkSeq.deneb ? "engine_getPayloadV3" : ForkSeq[fork] >= ForkSeq.capella ? "engine_getPayloadV2" diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index f2ce00e43a4..d1ee41e5e70 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -3,10 +3,10 @@ import {KZGCommitment, Blob, KZGProof} from "@lodestar/types/deneb"; import {Root, RootHex, allForks, capella, Wei} from "@lodestar/types"; import {DATA, QUANTITY} from "../../eth1/provider/utils.js"; -import {PayloadIdCache, PayloadId, WithdrawalV1} from "./payloadIdCache.js"; +import {PayloadIdCache, PayloadId, WithdrawalV1, DepositReceiptV1} from "./payloadIdCache.js"; import {ExecutionPayloadBody} from "./types.js"; -export {PayloadIdCache, PayloadId, WithdrawalV1}; +export {PayloadIdCache, PayloadId, WithdrawalV1, DepositReceiptV1}; export enum ExecutionPayloadStatus { /** given payload is valid */ diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index c64528552ea..110a96f7d3f 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -35,6 +35,7 @@ export type ExecutionEngineMockOpts = { onlyPredefinedResponses?: boolean; capellaForkTimestamp?: number; denebForkTimestamp?: number; + eip6110ForkTimestamp?: number; }; type ExecutionBlock = { @@ -88,12 +89,14 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_newPayloadV1: this.notifyNewPayload.bind(this), engine_newPayloadV2: this.notifyNewPayload.bind(this), engine_newPayloadV3: this.notifyNewPayload.bind(this), + engine_newPayloadV6110: this.notifyNewPayload.bind(this), engine_forkchoiceUpdatedV1: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV2: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV3: this.notifyForkchoiceUpdate.bind(this), engine_getPayloadV1: this.getPayload.bind(this), engine_getPayloadV2: this.getPayload.bind(this), engine_getPayloadV3: this.getPayload.bind(this), + engine_getPayloadV6110: this.getPayload.bind(this), engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), }; @@ -387,6 +390,7 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { } private timestampToFork(timestamp: number): ForkExecution { + if (timestamp > (this.opts.eip6110ForkTimestamp ?? Infinity)) return ForkName.eip6110; if (timestamp > (this.opts.denebForkTimestamp ?? Infinity)) return ForkName.deneb; if (timestamp > (this.opts.capellaForkTimestamp ?? Infinity)) return ForkName.capella; return ForkName.bellatrix; diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index 6270474ca9d..86df0057777 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -18,6 +18,14 @@ export type WithdrawalV1 = { amount: QUANTITY; }; +export type DepositReceiptV1 = { + pubkey: DATA; + withdrawalCredentials: DATA; + amount: QUANTITY; + signature: DATA; + index: QUANTITY; +} + type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit; export class PayloadIdCache { diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index d400df03a58..a54bb760dea 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -1,4 +1,4 @@ -import {allForks, capella, deneb, Wei, bellatrix, Root} from "@lodestar/types"; +import {allForks, capella, deneb, Wei, bellatrix, Root, eip6110} from "@lodestar/types"; import { BYTES_PER_LOGS_BLOOM, FIELD_ELEMENTS_PER_BLOB, @@ -17,7 +17,7 @@ import { quantityToBigint, } from "../../eth1/provider/utils.js"; import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js"; -import {WithdrawalV1} from "./payloadIdCache.js"; +import {WithdrawalV1, DepositReceiptV1} from "./payloadIdCache.js"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -28,6 +28,7 @@ export type EngineApiRpcParamTypes = { engine_newPayloadV1: [ExecutionPayloadRpc]; engine_newPayloadV2: [ExecutionPayloadRpc]; engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; + engine_newPayloadV6110: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; /** * 1. Object - Payload validity status with respect to the consensus rules: * - blockHash: DATA, 32 Bytes - block hash value of the payload @@ -51,6 +52,7 @@ export type EngineApiRpcParamTypes = { engine_getPayloadV1: [QUANTITY]; engine_getPayloadV2: [QUANTITY]; engine_getPayloadV3: [QUANTITY]; + engine_getPayloadV6110: [QUANTITY]; /** * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure @@ -78,6 +80,7 @@ export type EngineApiRpcReturnTypes = { engine_newPayloadV1: PayloadStatus; engine_newPayloadV2: PayloadStatus; engine_newPayloadV3: PayloadStatus; + engine_newPayloadV6110: PayloadStatus; engine_forkchoiceUpdatedV1: { payloadStatus: PayloadStatus; payloadId: QUANTITY | null; @@ -96,6 +99,7 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadV1: ExecutionPayloadRpc; engine_getPayloadV2: ExecutionPayloadResponse; engine_getPayloadV3: ExecutionPayloadResponse; + engine_getPayloadV6110: ExecutionPayloadResponse; engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[]; @@ -109,9 +113,9 @@ type ExecutionPayloadRpcWithBlockValue = { }; type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithBlockValue; -export type ExecutionPayloadBodyRpc = {transactions: DATA[]; withdrawals: WithdrawalV1[] | null}; +export type ExecutionPayloadBodyRpc = {transactions: DATA[]; withdrawals: WithdrawalV1[] | null; depositReceipts: DepositReceiptV1[] | null}; -export type ExecutionPayloadBody = {transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null}; +export type ExecutionPayloadBody = {transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; depositReceipts: eip6110.DepositReceipts | null}; export type ExecutionPayloadRpc = { parentHash: DATA; // 32 bytes @@ -132,6 +136,7 @@ export type ExecutionPayloadRpc = { blobGasUsed?: QUANTITY; // DENEB excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB + depositReceipts?: DepositReceiptRpc[]; // EIP6110 }; export type WithdrawalRpc = { @@ -141,6 +146,14 @@ export type WithdrawalRpc = { amount: QUANTITY; }; +export type DepositReceiptRpc = { + pubkey: DATA; + withdrawalCredentials: DATA; + amount: QUANTITY; + signature: DATA; + index: QUANTITY; +}; + export type VersionedHashesRpc = DATA[]; export type PayloadAttributesRpc = { @@ -186,12 +199,18 @@ export function serializeExecutionPayload(fork: ForkName, data: allForks.Executi } // DENEB adds blobGasUsed & excessBlobGas to the ExecutionPayload - if (ForkSeq[fork] >= ForkSeq.deneb) { + if (ForkSeq[fork] >= ForkSeq.deneb) { const {blobGasUsed, excessBlobGas} = data as deneb.ExecutionPayload; payload.blobGasUsed = numToQuantity(blobGasUsed); payload.excessBlobGas = numToQuantity(excessBlobGas); } + // EIP6110 adds depositReceipts to the ExecutionPayload + if (ForkSeq[fork] >= ForkSeq.eip6110) { + const {depositReceipts} = data as eip6110.ExecutionPayload; + payload.depositReceipts = depositReceipts.map(serializeDepositReceipt); + } + return payload; } @@ -268,6 +287,17 @@ export function parseExecutionPayload( (executionPayload as deneb.ExecutionPayload).excessBlobGas = quantityToBigint(excessBlobGas); } + if (ForkSeq[fork] >= ForkSeq.eip6110) { + const {depositReceipts} = data; + // Geth can also reply with null + if (depositReceipts == null) { + throw Error( + `depositReceipts missing for ${fork} >= eip6110 executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` + ); + } + (executionPayload as eip6110.ExecutionPayload).depositReceipts = depositReceipts.map((d) => deserializeDepositReceipts(d)); + } + return {executionPayload, blockValue, blobsBundle}; } @@ -334,11 +364,32 @@ export function deserializeWithdrawal(serialized: WithdrawalRpc): capella.Withdr } as capella.Withdrawal; } +export function serializeDepositReceipt(depositReceipt: eip6110.DepositReceipt): DepositReceiptRpc { + return { + pubkey: bytesToData(depositReceipt.pubkey), + withdrawalCredentials: bytesToData(depositReceipt.withdrawalCredentials), + amount: numToQuantity(depositReceipt.amount), + signature: bytesToData(depositReceipt.signature), + index: numToQuantity(depositReceipt.index), + }; +} + +export function deserializeDepositReceipts(serialized: DepositReceiptRpc): eip6110.DepositReceipt { + return { + pubkey: dataToBytes(serialized.pubkey, 48), + withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), + amount: quantityToBigint(serialized.amount), + signature: dataToBytes(serialized.signature, 96), + index: quantityToNum(serialized.index), + } as eip6110.DepositReceipt; +} + export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null { return data ? { transactions: data.transactions.map((tran) => dataToBytes(tran, null)), withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null, + depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipts) : null, } : null; } @@ -348,6 +399,7 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null) ? { transactions: data.transactions.map((tran) => bytesToData(tran)), withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null, + depositReceipts: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null, } : null; } From 480c47228c13f08f0a5fc2a8e3ad5e9b6b5acbf2 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 14 Sep 2023 17:55:17 +0800 Subject: [PATCH 023/155] Update test --- packages/beacon-node/test/utils/config.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/test/utils/config.ts b/packages/beacon-node/test/utils/config.ts index 54c058d3072..d960feb96f3 100644 --- a/packages/beacon-node/test/utils/config.ts +++ b/packages/beacon-node/test/utils/config.ts @@ -24,12 +24,20 @@ export function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: forkEpoch, }); - case ForkName.deneb: + case ForkName.deneb: // TODO return createChainForkConfig({ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: forkEpoch, }); + case ForkName.eip6110: + return createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + EIP6110_FORK_EPOCH: forkEpoch, + }); } } From 8ce4605df68242b663613507a1c10a7c2dedebd8 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 14 Sep 2023 18:03:34 +0800 Subject: [PATCH 024/155] Add depositReceiptsRoot to process_execution_payload --- .../src/block/processExecutionPayload.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 4965c21397b..56fa39d78d9 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -1,5 +1,5 @@ import {toHexString, byteArrayEquals} from "@chainsafe/ssz"; -import {ssz, allForks, capella, deneb} from "@lodestar/types"; +import {ssz, allForks, capella, deneb, eip6110} from "@lodestar/types"; import {ForkSeq, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; import {CachedBeaconStateBellatrix, CachedBeaconStateCapella} from "../types.js"; import {getRandaoMix} from "../util/index.js"; @@ -101,21 +101,29 @@ export function executionPayloadToPayloadHeader( transactionsRoot, }; + const payloadFields = bellatrixPayloadFields; + if (fork >= ForkSeq.capella) { - (bellatrixPayloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot( + (payloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot( (payload as capella.ExecutionPayload).withdrawals ); } if (fork >= ForkSeq.deneb) { // https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#process_execution_payload - (bellatrixPayloadFields as deneb.ExecutionPayloadHeader).blobGasUsed = ( + (payloadFields as deneb.ExecutionPayloadHeader).blobGasUsed = ( payload as deneb.ExecutionPayloadHeader | deneb.ExecutionPayload ).blobGasUsed; - (bellatrixPayloadFields as deneb.ExecutionPayloadHeader).excessBlobGas = ( + (payloadFields as deneb.ExecutionPayloadHeader).excessBlobGas = ( payload as deneb.ExecutionPayloadHeader | deneb.ExecutionPayload ).excessBlobGas; } - return bellatrixPayloadFields; + if (fork >= ForkSeq.eip6110) { + (payloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = ssz.eip6110.DepositReceipts.hashTreeRoot( + (payload as eip6110.ExecutionPayload).depositReceipts + ); + } + + return payloadFields; } From 582d39c7d06403f1c8673a092e25f130253b6850 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 18 Sep 2023 16:49:24 +0800 Subject: [PATCH 025/155] State transitioning to EIP6110 --- packages/params/src/index.ts | 3 ++ .../state-transition/src/cache/stateCache.ts | 2 ++ packages/state-transition/src/slot/index.ts | 1 + .../src/slot/upgradeStateToEIP6110.ts | 35 +++++++++++++++++++ .../state-transition/src/stateTransition.ts | 5 +++ packages/state-transition/src/types.ts | 2 ++ packages/state-transition/src/util/genesis.ts | 9 +++++ .../test/unit/upgradeState.test.ts | 27 +++++++++++++- 8 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 packages/state-transition/src/slot/upgradeStateToEIP6110.ts diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 115aa98b350..e240f3842fe 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -247,3 +247,6 @@ export const INTERVALS_PER_SLOT = 3; export const BYTES_PER_FIELD_ELEMENT = 32; export const BLOB_TX_TYPE = 0x03; export const VERSIONED_HASH_VERSION_KZG = 0x01; + +// EIP-6110 Misc +export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2 ** 64 - 1; \ No newline at end of file diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 30dc5aec733..5abc4beddfe 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -8,6 +8,7 @@ import { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateEIP6110, } from "./types.js"; export type BeaconStateCache = { @@ -127,6 +128,7 @@ export type CachedBeaconStateAltair = CachedBeaconState; export type CachedBeaconStateBellatrix = CachedBeaconState; export type CachedBeaconStateCapella = CachedBeaconState; export type CachedBeaconStateDeneb = CachedBeaconState; +export type CachedBeaconStateEIP6110 = CachedBeaconState; export type CachedBeaconStateAllForks = CachedBeaconState; export type CachedBeaconStateExecutions = CachedBeaconState; diff --git a/packages/state-transition/src/slot/index.ts b/packages/state-transition/src/slot/index.ts index 6c4add1d123..c8d0b5d1605 100644 --- a/packages/state-transition/src/slot/index.ts +++ b/packages/state-transition/src/slot/index.ts @@ -7,6 +7,7 @@ export {upgradeStateToAltair} from "./upgradeStateToAltair.js"; export {upgradeStateToBellatrix} from "./upgradeStateToBellatrix.js"; export {upgradeStateToCapella} from "./upgradeStateToCapella.js"; export {upgradeStateToDeneb} from "./upgradeStateToDeneb.js"; +export {upgradeStateToEIP6110} from "./upgradeStateToEIP6110.js"; /** * Dial state to next slot. Common for all forks diff --git a/packages/state-transition/src/slot/upgradeStateToEIP6110.ts b/packages/state-transition/src/slot/upgradeStateToEIP6110.ts new file mode 100644 index 00000000000..4c852c8b35d --- /dev/null +++ b/packages/state-transition/src/slot/upgradeStateToEIP6110.ts @@ -0,0 +1,35 @@ +import {ssz} from "@lodestar/types"; +import {CachedBeaconStateDeneb} from "../types.js"; +import {CachedBeaconStateEIP6110, getCachedBeaconState} from "../cache/stateCache.js"; +import { UNSET_DEPOSIT_RECEIPTS_START_INDEX } from "@lodestar/params"; + +/** + * Upgrade a state from Capella to Deneb. + */ +export function upgradeStateToEIP6110(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateEIP6110 { + const {config} = stateDeneb; + + const stateEIP6110Node = ssz.deneb.BeaconState.commitViewDU(stateDeneb); + const stateEIP6110View = ssz.eip6110.BeaconState.getViewDU(stateEIP6110Node); + + const stateEIP6110 = getCachedBeaconState(stateEIP6110View, stateDeneb); + + stateEIP6110.fork = ssz.phase0.Fork.toViewDU({ + previousVersion: stateDeneb.fork.currentVersion, + currentVersion: config.EIP6110_FORK_VERSION, + epoch: stateDeneb.epochCtx.epoch, + }); + + + + // latestExecutionPayloadHeader's depositReceiptsRoot set to zeros by default + // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX + stateEIP6110.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + + // Commit new added fields ViewDU to the root node + stateEIP6110.commit(); + // Clear cache to ensure the cache of deneb fields is not used by new EIP6110 fields + stateEIP6110["clearCache"](); + + return stateEIP6110; +} diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index f9e93741fa7..9e04861c123 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -9,6 +9,7 @@ import { CachedBeaconStateAltair, CachedBeaconStateBellatrix, CachedBeaconStateCapella, + CachedBeaconStateDeneb, } from "./types.js"; import {computeEpochAtSlot} from "./util/index.js"; import {verifyProposerSignature} from "./signatureSets/index.js"; @@ -18,6 +19,7 @@ import { upgradeStateToBellatrix, upgradeStateToCapella, upgradeStateToDeneb, + upgradeStateToEIP6110, } from "./slot/index.js"; import {processBlock} from "./block/index.js"; import {processEpoch} from "./epoch/index.js"; @@ -196,6 +198,9 @@ function processSlotsWithTransientCache( if (stateSlot === config.DENEB_FORK_EPOCH) { postState = upgradeStateToDeneb(postState as CachedBeaconStateCapella) as CachedBeaconStateAllForks; } + if (stateSlot === config.EIP6110_FORK_EPOCH) { + postState = upgradeStateToEIP6110(postState as CachedBeaconStateDeneb) as CachedBeaconStateAllForks; + } } else { postState.slot++; } diff --git a/packages/state-transition/src/types.ts b/packages/state-transition/src/types.ts index 3271253ee8d..19118f9955c 100644 --- a/packages/state-transition/src/types.ts +++ b/packages/state-transition/src/types.ts @@ -9,6 +9,7 @@ export { CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, + CachedBeaconStateEIP6110, } from "./cache/stateCache.js"; export { @@ -19,4 +20,5 @@ export { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateEIP6110, } from "./cache/types.js"; diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 87547e5f2a1..7b8178802bf 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -287,6 +287,15 @@ export function initializeBeaconStateFromEth1( ssz.deneb.ExecutionPayloadHeader.defaultViewDU(); } + if (GENESIS_SLOT >= config.EIP6110_FORK_EPOCH) { + const stateEIP6110 = state as CompositeViewDU; + stateEIP6110.fork.previousVersion = config.EIP6110_FORK_VERSION; + stateEIP6110.fork.currentVersion = config.EIP6110_FORK_VERSION; + stateEIP6110.latestExecutionPayloadHeader = + (executionPayloadHeader as CompositeViewDU) ?? + ssz.eip6110.ExecutionPayloadHeader.defaultViewDU(); + } + state.commit(); return state; diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 7e78db0ecdd..15a4534199d 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -6,6 +6,7 @@ import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodes import {config as chainConfig} from "@lodestar/config/default"; import {upgradeStateToDeneb} from "../../src/slot/upgradeStateToDeneb.js"; +import { upgradeStateToEIP6110 } from "../../src/slot/upgradeStateToEIP6110.js"; describe("upgradeState", () => { it("upgradeStateToDeneb", () => { @@ -24,6 +25,22 @@ describe("upgradeState", () => { const newState = upgradeStateToDeneb(stateView); expect(() => newState.toValue()).to.not.throw(); }); + it("upgradeStateToEIP6110", () => { + const denebState = ssz.deneb.BeaconState.defaultViewDU(); + const config = getConfig(ForkName.deneb); + const stateView = createCachedBeaconState( + denebState, + { + config: createBeaconConfig(config, denebState.genesisValidatorsRoot), + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }, + createEmptyCarryoverData(), + {skipSyncCommitteeCache: true} + ); + const newState = upgradeStateToEIP6110(stateView); + expect(() => newState.toValue()).to.not.throw(); + }); }); const ZERO_HASH = Buffer.alloc(32, 0); @@ -48,12 +65,20 @@ function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: forkEpoch, }); - case ForkName.deneb: + case ForkName.deneb: // TODO return createChainForkConfig({ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: forkEpoch, }); + case ForkName.eip6110: + return createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + EIP6110_FORK_EPOCH: forkEpoch, + }); } } From 273795cc87c8c7fd27e505baa6ca24bc090a31ee Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 18 Sep 2023 16:49:55 +0800 Subject: [PATCH 026/155] State transitioning to EIP6110 --- packages/state-transition/test/unit/upgradeState.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 15a4534199d..e8d628464c2 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -65,7 +65,7 @@ function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: forkEpoch, }); - case ForkName.deneb: // TODO + case ForkName.deneb: return createChainForkConfig({ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, From 598bbdbff76f557a03210932cb040edfbda37030 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 18 Sep 2023 17:17:10 +0800 Subject: [PATCH 027/155] Light client change in EIP-6110 --- packages/light-client/src/spec/utils.ts | 19 +++++++++++- .../unit/isValidLightClientHeader.test.ts | 31 +++++++++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 0ff1775f55c..21704c72921 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -8,12 +8,13 @@ import { BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, BLOCK_BODY_EXECUTION_PAYLOAD_INDEX as EXECUTION_PAYLOAD_INDEX, } from "@lodestar/params"; -import {altair, phase0, ssz, allForks, capella, deneb, Slot} from "@lodestar/types"; +import {altair, phase0, ssz, allForks, capella, deneb, Slot, eip6110} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {computeEpochAtSlot} from "@lodestar/state-transition"; import {isValidMerkleBranch, computeSyncPeriodAtSlot} from "../utils/index.js"; import {LightClientStore} from "./store.js"; +import { Root } from "@lodestar/types/lib/sszTypes.js"; export const GENESIS_SLOT = 0; export const ZERO_HASH = new Uint8Array(32); @@ -105,6 +106,14 @@ export function upgradeLightClientHeader( // Break if no further upgradation is required else fall through if (ForkSeq[targetFork] <= ForkSeq.deneb) break; + + // eslint-disable-next-line no-fallthrough + case ForkName.eip6110: + (upgradedHeader as eip6110.LightClientHeader).execution.depositReceiptsRoot = + ssz.eip6110.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); + + // Break if no further upgradation is required else fall through + if (ForkSeq[targetFork] <= ForkSeq.eip6110) break; } return upgradedHeader; } @@ -138,6 +147,14 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: allFor } } + if (epoch < config.EIP6110_FORK_EPOCH) { + if ( + (header as eip6110.LightClientHeader).execution.depositReceiptsRoot && + (header as eip6110.LightClientHeader).execution.depositReceiptsRoot !== Root.defaultValue()) { + return false; + } + } + return isValidMerkleBranch( config .getExecutionForkTypes(header.beacon.slot) diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index a28ac65ff61..c62e15a8f51 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -3,6 +3,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {ssz, allForks} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {isValidLightClientHeader} from "../../src/spec/utils.js"; +import { Root } from "@lodestar/types/lib/sszTypes.js"; describe("isValidLightClientHeader", function () { /* eslint-disable @typescript-eslint/naming-convention */ @@ -10,8 +11,9 @@ describe("isValidLightClientHeader", function () { ...defaultChainConfig, ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, - CAPELLA_FORK_EPOCH: 1, - DENEB_FORK_EPOCH: Infinity, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 1, + EIP6110_FORK_EPOCH: Infinity, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); @@ -35,10 +37,16 @@ describe("isValidLightClientHeader", function () { const altairUpgradedDenebLCHeader = { beacon: altairLCHeader.beacon, - execution: ssz.deneb.LightClientHeader.fields.execution.defaultValue(), + execution: ssz.deneb.LightClientHeader.fields.execution.defaultValue(), // TODO executionBranch: ssz.deneb.LightClientHeader.fields.executionBranch.defaultValue(), }; + const altairUpgradedEIP6110LCHeader = { + beacon: altairLCHeader.beacon, + execution: ssz.eip6110.LightClientHeader.fields.execution.defaultValue(), + executionBranch: ssz.eip6110.LightClientHeader.fields.executionBranch.defaultValue(), + }; + const capellaLCHeader = { beacon: { slot: 100936, @@ -80,12 +88,29 @@ describe("isValidLightClientHeader", function () { executionBranch: capellaLCHeader.executionBranch, }; + const capellaUpgradedEIP6110Header = { + beacon: capellaLCHeader.beacon, + execution: {...capellaLCHeader.execution, blobGasUsed: 0, excessBlobGas: 0, depositReceiptsRoot: Root.defaultValue}, + executionBranch: capellaLCHeader.executionBranch, + }; + + const denebLCHeader = { // TODO-6110: Find a denebLCHeader + }; + + const denebUpgradedEIP6110Header = { // TODO-6110: Find a denebLCHeader + + } + const testCases: [string, allForks.LightClientHeader][] = [ ["altair LC header", altairLCHeader], ["altair upgraded to capella", altairUpgradedCapellaLCHeader], ["altair upgraded to deneb", altairUpgradedDenebLCHeader], + ["altair upgraded to eip6110", altairUpgradedDenebLCHeader], ["capella LC header", capellaLCHeader], ["capella upgraded to deneb LC header", capellaUpgradedDenebHeader], + ["capella upgraded to eip6110 LC header", capellaUpgradedEIP6110Header], + // ["deneb LC header", denebLCHeader], + // ["deneb upgraded to eip6110 LC header", denebUpgradedDenebHeader], ]; testCases.forEach(([name, header]: [string, allForks.LightClientHeader]) => { From 3d3cf068c492706ebf677b5831679ffd8ce0a9a5 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 18 Sep 2023 17:31:47 +0800 Subject: [PATCH 028/155] Update tests --- packages/beacon-node/test/spec/presets/fork.ts | 5 ++++- .../beacon-node/test/spec/presets/transition.ts | 4 +++- .../lightclient/upgradeLightClientHeader.test.ts | 3 +++ .../network/beaconBlocksMaybeBlobsByRange.test.ts | 1 + .../beacon-node/test/unit/network/fork.test.ts | 14 +++++++++++++- packages/beacon-node/test/utils/config.ts | 2 +- .../test/unit/isValidLightClientHeader.test.ts | 4 ++-- 7 files changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/fork.ts b/packages/beacon-node/test/spec/presets/fork.ts index 5fb241c26e8..83d1f18fc91 100644 --- a/packages/beacon-node/test/spec/presets/fork.ts +++ b/packages/beacon-node/test/spec/presets/fork.ts @@ -4,6 +4,7 @@ import { CachedBeaconStateAltair, CachedBeaconStatePhase0, CachedBeaconStateCapella, + CachedBeaconStateDeneb, } from "@lodestar/state-transition"; import * as slotFns from "@lodestar/state-transition/slot"; import {phase0, ssz} from "@lodestar/types"; @@ -30,8 +31,10 @@ export const fork: TestRunnerFn = (forkNext) return slotFns.upgradeStateToBellatrix(preState as CachedBeaconStateAltair); case ForkName.capella: return slotFns.upgradeStateToCapella(preState as CachedBeaconStateBellatrix); - case ForkName.deneb: + case ForkName.deneb: return slotFns.upgradeStateToDeneb(preState as CachedBeaconStateCapella); + case ForkName.eip6110: + return slotFns.upgradeStateToEIP6110(preState as CachedBeaconStateDeneb); } }, options: { diff --git a/packages/beacon-node/test/spec/presets/transition.ts b/packages/beacon-node/test/spec/presets/transition.ts index 323b8bea7a5..10b74af52fb 100644 --- a/packages/beacon-node/test/spec/presets/transition.ts +++ b/packages/beacon-node/test/spec/presets/transition.ts @@ -97,8 +97,10 @@ function getTransitionConfig(fork: ForkName, forkEpoch: number): Partial { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, + EIP6110_FORK_EPOCH: 0, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); diff --git a/packages/beacon-node/test/unit/network/fork.test.ts b/packages/beacon-node/test/unit/network/fork.test.ts index b920870189a..81ca8a60687 100644 --- a/packages/beacon-node/test/unit/network/fork.test.ts +++ b/packages/beacon-node/test/unit/network/fork.test.ts @@ -9,12 +9,14 @@ function getForkConfig({ bellatrix, capella, deneb, + eip6110, }: { phase0: number; altair: number; bellatrix: number; capella: number; deneb: number; + eip6110: number; }): BeaconConfig { const forks: Record = { phase0: { @@ -57,6 +59,14 @@ function getForkConfig({ prevVersion: Buffer.from([0, 0, 0, 3]), prevForkName: ForkName.capella, }, + eip6110: { + name: ForkName.eip6110, + seq: ForkSeq.eip6110, + epoch: eip6110, + version: Buffer.from([0, 0, 0, 5]), + prevVersion: Buffer.from([0, 0, 0, 4]), + prevForkName: ForkName.deneb, + }, }; const forksAscendingEpochOrder = Object.values(forks); const forksDescendingEpochOrder = Object.values(forks).reverse(); @@ -133,10 +143,12 @@ const testScenarios = [ for (const testScenario of testScenarios) { const {phase0, altair, bellatrix, capella, testCases} = testScenario; // TODO DENEB: Is it necessary to test? + // TODO 6110: Revisit this const deneb = Infinity; + const eip6110 = Infinity; describe(`network / fork: phase0: ${phase0}, altair: ${altair}, bellatrix: ${bellatrix} capella: ${capella}`, () => { - const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb}); + const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb, eip6110}); const forks = forkConfig.forks; for (const testCase of testCases) { const {epoch, currentFork, nextFork, activeForks} = testCase; diff --git a/packages/beacon-node/test/utils/config.ts b/packages/beacon-node/test/utils/config.ts index d960feb96f3..6cb300bab55 100644 --- a/packages/beacon-node/test/utils/config.ts +++ b/packages/beacon-node/test/utils/config.ts @@ -24,7 +24,7 @@ export function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: forkEpoch, }); - case ForkName.deneb: // TODO + case ForkName.deneb: return createChainForkConfig({ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index c62e15a8f51..3aa0a987e40 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -94,10 +94,10 @@ describe("isValidLightClientHeader", function () { executionBranch: capellaLCHeader.executionBranch, }; - const denebLCHeader = { // TODO-6110: Find a denebLCHeader + const denebLCHeader = { // TODO 6110: Find a denebLCHeader }; - const denebUpgradedEIP6110Header = { // TODO-6110: Find a denebLCHeader + const denebUpgradedEIP6110Header = { // TODO 6110: Find a denebLCHeader } From a73a7e53d8689c1027061d74d1dfb55395146458 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 18 Sep 2023 17:34:33 +0800 Subject: [PATCH 029/155] produceBlock --- packages/validator/src/services/block.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index 81c749297f4..e8307490e3e 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -385,6 +385,7 @@ export class BlockProposingService { } case ForkName.deneb: + case ForkName.eip6110: default: { const res = await this.api.validator.produceBlockV2(slot, randaoReveal, graffiti, expectedFeeRecipient); ApiError.assert(res, "Failed to produce block: validator.produceBlockV2"); @@ -427,6 +428,7 @@ export class BlockProposingService { } case ForkName.deneb: + case ForkName.eip6110: default: { if (!isBlindedBlockContents(response.data)) { throw Error(`Expected BlockContents response at fork=${fork}`); From 80c77bf4eff22a5435a378850e4f97d8e22aa0a5 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 18 Sep 2023 19:48:26 +0800 Subject: [PATCH 030/155] Refactor processDeposit to match the spec --- .../src/block/processDeposit.ts | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 303c714d42d..6e1cd83ee21 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -1,6 +1,6 @@ import bls from "@chainsafe/bls"; import {CoordType} from "@chainsafe/bls/types"; -import {phase0, ssz} from "@lodestar/types"; +import {BLSPubkey, BLSSignature, Bytes32, UintNum64, phase0, ssz} from "@lodestar/types"; import {verifyMerkleBranch} from "@lodestar/utils"; import { @@ -23,7 +23,6 @@ import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; * PERF: Work depends on number of Deposit per block. On regular networks the average is 0 / block. */ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, deposit: phase0.Deposit): void { - const {config, validators, epochCtx} = state; // verify the merkle branch if ( @@ -41,15 +40,32 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, // deposits must be processed in order state.eth1DepositIndex += 1; - const pubkey = deposit.data.pubkey; // Drop tree - const amount = deposit.data.amount; + applyDeposit( + fork, + state, + deposit.data.pubkey, + deposit.data.withdrawalCredentials, + deposit.data.amount, + deposit.data.signature + ) + +} + +/** + * Adds a new validator into the registry. Or increase balance if already exist. + * Follows applyDeposit() in consensus spec. Will be used by processDeposit() and processDepositReceipt() + * + */ +export function applyDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, pubkey: BLSPubkey, withdrawalCredentials: Bytes32, amount: UintNum64, signature: BLSSignature): void { + const {config, validators, epochCtx} = state; + const cachedIndex = epochCtx.getValidatorIndex(pubkey); if (cachedIndex === undefined || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { // verify the deposit signature (proof of posession) which is not checked by the deposit contract const depositMessage = { - pubkey: deposit.data.pubkey, // Retain tree for hashing - withdrawalCredentials: deposit.data.withdrawalCredentials, // Retain tree for hashing - amount: deposit.data.amount, + pubkey, + withdrawalCredentials, + amount, }; // fork-agnostic domain since deposits are valid across forks const domain = computeDomain(DOMAIN_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH); @@ -57,20 +73,28 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, try { // Pubkeys must be checked for group + inf. This must be done only once when the validator deposit is processed const publicKey = bls.PublicKey.fromBytes(pubkey, CoordType.affine, true); - const signature = bls.Signature.fromBytes(deposit.data.signature, CoordType.affine, true); - if (!signature.verify(publicKey, signingRoot)) { + const computedSignature = bls.Signature.fromBytes(signature, CoordType.affine, true); + if (!computedSignature.verify(publicKey, signingRoot)) { return; } } catch (e) { return; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature } + addValidatorToRegistry(fork, state, pubkey, withdrawalCredentials, amount); + } else { + // increase balance by deposit amount + increaseBalance(state, cachedIndex, amount); + } +} +function addValidatorToRegistry(fork: ForkSeq, state: CachedBeaconStateAllForks, pubkey: BLSPubkey, withdrawalCredentials: Bytes32, amount: UintNum64) : void { + const {validators, epochCtx} = state; // add validator and balance entries const effectiveBalance = Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); validators.push( ssz.phase0.Validator.toViewDU({ pubkey, - withdrawalCredentials: deposit.data.withdrawalCredentials, + withdrawalCredentials, activationEligibilityEpoch: FAR_FUTURE_EPOCH, activationEpoch: FAR_FUTURE_EPOCH, exitEpoch: FAR_FUTURE_EPOCH, @@ -101,8 +125,4 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, stateAltair.previousEpochParticipation.push(0); stateAltair.currentEpochParticipation.push(0); } - } else { - // increase balance by deposit amount - increaseBalance(state, cachedIndex, amount); - } -} +} \ No newline at end of file From 2e86109f077029c055b0709afd6b49ff232f9a33 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 18 Sep 2023 19:57:54 +0800 Subject: [PATCH 031/155] Implement processDepositReceipt --- .../src/block/processDepositReceipt.ts | 25 +++++++++++++++++++ .../src/block/processOperations.ts | 11 ++++++-- packages/types/src/eip6110/sszTypes.ts | 2 +- 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 packages/state-transition/src/block/processDepositReceipt.ts diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositReceipt.ts new file mode 100644 index 00000000000..89132feb12b --- /dev/null +++ b/packages/state-transition/src/block/processDepositReceipt.ts @@ -0,0 +1,25 @@ +import {eip6110} from "@lodestar/types"; +import {ForkSeq, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; + +import {CachedBeaconStateEIP6110} from "../types.js"; +import { applyDeposit } from "./processDeposit.js"; + +export function processDepositReceipt( + fork: ForkSeq, + state: CachedBeaconStateEIP6110, + depositReceipt: eip6110.DepositReceipt +): void { + + if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + state.depositReceiptsStartIndex = depositReceipt.index; + } + + applyDeposit( + fork, + state, + depositReceipt.pubkey, + depositReceipt.withdrawalCredentials, + depositReceipt.amount, + depositReceipt.signature, + ); +} \ No newline at end of file diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index c523f1dad24..e5bcff55670 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -1,13 +1,14 @@ -import {allForks, capella} from "@lodestar/types"; +import {allForks, capella, eip6110} from "@lodestar/types"; import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; -import {CachedBeaconStateAllForks, CachedBeaconStateCapella} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateEIP6110} from "../types.js"; import {processAttestations} from "./processAttestations.js"; import {processProposerSlashing} from "./processProposerSlashing.js"; import {processAttesterSlashing} from "./processAttesterSlashing.js"; import {processDeposit} from "./processDeposit.js"; import {processVoluntaryExit} from "./processVoluntaryExit.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; +import {processDepositReceipt} from "./processDepositReceipt.js"; import {ProcessBlockOpts} from "./types.js"; export { @@ -54,4 +55,10 @@ export function processOperations( processBlsToExecutionChange(state as CachedBeaconStateCapella, blsToExecutionChange); } } + + if (fork >= ForkSeq.eip6110) { + for (const depositReceipt of (body as eip6110.BeaconBlockBody).executionPayload.depositReceipts) { + processDepositReceipt(fork, state as CachedBeaconStateEIP6110, depositReceipt); + } + } } diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index b61d92c3f30..79aea8433fb 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -31,7 +31,7 @@ export const DepositReceipt = new ContainerType( //good { pubkey: BLSPubkey, withdrawalCredentials: Bytes32, - amount: Gwei, + amount: UintNum64, signature: BLSSignature, index: DepositIndex, validatorIndex: ValidatorIndex, From a9c07526710cc4e01157d54ee2914666c7e11bec Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 12 Sep 2023 16:48:51 +0800 Subject: [PATCH 032/155] Implement 6110 fork guard for pubkeyCache --- .../src/block/processDeposit.ts | 2 +- .../state-transition/src/cache/epochCache.ts | 56 +++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 6e1cd83ee21..86c560f9929 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -113,7 +113,7 @@ function addValidatorToRegistry(fork: ForkSeq, state: CachedBeaconStateAllForks, epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); // now that there is a new validator, update the epoch context with the new pubkey - epochCtx.addPubkey(validatorIndex, pubkey); + epochCtx.addPubkey(pubkey, validatorIndex); // Only after altair: if (fork >= ForkSeq.altair) { diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 420f132d863..ab2c52ef59d 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -206,6 +206,7 @@ export class EpochCache { // TODO: Helper stats epoch: Epoch; syncPeriod: SyncPeriod; + isAfterEIP6110: boolean; constructor(data: { config: BeaconConfig; @@ -232,6 +233,7 @@ export class EpochCache { nextSyncCommitteeIndexed: SyncCommitteeCache; epoch: Epoch; syncPeriod: SyncPeriod; + isAfterEIP6110: boolean; }) { this.config = data.config; this.globalPubkey2index = data.globalPubkey2index; @@ -257,6 +259,7 @@ export class EpochCache { this.nextSyncCommitteeIndexed = data.nextSyncCommitteeIndexed; this.epoch = data.epoch; this.syncPeriod = data.syncPeriod; + this.isAfterEIP6110 = data.isAfterEIP6110; } /** @@ -436,6 +439,7 @@ export class EpochCache { nextSyncCommitteeIndexed, epoch: currentEpoch, syncPeriod: computeSyncPeriodAtEpoch(currentEpoch), + isAfterEIP6110: currentEpoch >= (config.EIP6110_FORK_EPOCH ?? Infinity), }); } @@ -477,6 +481,7 @@ export class EpochCache { nextSyncCommitteeIndexed: this.nextSyncCommitteeIndexed, epoch: this.epoch, syncPeriod: this.syncPeriod, + isAfterEIP6110: this.isAfterEIP6110, }); } @@ -504,18 +509,6 @@ export class EpochCache { nextEpoch ); - // To populate finalized cache and prune unfinalized cache with validators that just entered the activation queue - const expectedActivationEligibilityEpoch = prevEpoch + 1; - const validators = state.validators; - for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { - const validator = validators.getReadonly(index); - if (validator.activationEpoch == expectedActivationEligibilityEpoch) { - this.addFinalizedPubkey(validator.pubkey, index); - } else { - break; - } - } - // Roll current proposers into previous proposers for metrics this.proposersPrevEpoch = this.proposers; @@ -568,6 +561,21 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); + this.isAfterEIP6110 = this.epoch >= (this.config.EIP6110_FORK_EPOCH ?? Infinity); + + // To populate finalized cache and prune unfinalized cache with validators that just entered the activation queue + if (this.isAfterEIP6110) { + const expectedActivationEligibilityEpoch = prevEpoch + 1; + const validators = state.validators; + for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { + const validator = validators.getReadonly(index); + if (validator.activationEpoch == expectedActivationEligibilityEpoch) { + this.addFinalizedPubkey(validator.pubkey, index); + } else { + break; + } + } + } } beforeEpochTransition(): void { @@ -758,7 +766,10 @@ export class EpochCache { } getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { - return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + if (this.isAfterEIP6110) { + return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + } + return this.globalPubkey2index.get(pubkey); } /** @@ -766,8 +777,13 @@ export class EpochCache { * Add unfinalized pubkeys * */ - addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); + addPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + if (this.isAfterEIP6110) { + this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); + } else { + this.globalPubkey2index.set(pubkey, index); + this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + } } /** @@ -776,10 +792,18 @@ export class EpochCache { * */ addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + if (!this.isAfterEIP6110) { + throw new Error("addFInalizedPubkey is not available pre EIP-6110") + } + + if (this.globalPubkey2index.get(pubkey)) { + return; // Repeated insert. Should not happen except 6110 activation + } + this.globalPubkey2index.set(pubkey, index); this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); - this.unfinalizedPubkey2index.delete(toMemoryEfficientHexStr(pubkey)); + this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.delete(toMemoryEfficientHexStr(pubkey)); } getShufflingAtSlot(slot: Slot): EpochShuffling { From 4997d9a1c22fdd7a58e47e8c707daa5289b558eb Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 19 Sep 2023 16:50:32 +0800 Subject: [PATCH 033/155] Handle changes in eth1 deposit --- packages/beacon-node/src/eth1/utils/deposits.ts | 6 ++---- .../beacon-node/src/execution/engine/types.ts | 2 +- .../src/block/processOperations.ts | 3 ++- packages/state-transition/src/util/deposit.ts | 17 +++++++++++++++++ packages/state-transition/src/util/index.ts | 1 + 5 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 packages/state-transition/src/util/deposit.ts diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index 19544917ffd..ca12b5b45cf 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -1,11 +1,11 @@ import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; import {toHexString} from "@chainsafe/ssz"; -import {MAX_DEPOSITS} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {FilterOptions} from "@lodestar/db"; import {Eth1Error, Eth1ErrorCode} from "../errors.js"; import {DepositTree} from "../../db/repositories/depositDataRoot.js"; +import { getEth1DepositCount } from "@lodestar/state-transition"; export type DepositGetter = (indexRange: FilterOptions, eth1Data: phase0.Eth1Data) => Promise; @@ -22,9 +22,7 @@ export async function getDeposits( throw new Eth1Error({code: Eth1ErrorCode.DEPOSIT_INDEX_TOO_HIGH, depositIndex, depositCount}); } - // Spec v0.12.2 - // assert len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index) - const depositsLen = Math.min(MAX_DEPOSITS, depositCount - depositIndex); + const depositsLen = getEth1DepositCount(state); const indexRange = {gte: depositIndex, lt: depositIndex + depositsLen}; const deposits = await depositsGetter(indexRange, eth1Data); diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index a54bb760dea..6585f698140 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -378,7 +378,7 @@ export function deserializeDepositReceipts(serialized: DepositReceiptRpc): eip61 return { pubkey: dataToBytes(serialized.pubkey, 48), withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), - amount: quantityToBigint(serialized.amount), + amount: quantityToNum(serialized.amount), signature: dataToBytes(serialized.signature, 96), index: quantityToNum(serialized.index), } as eip6110.DepositReceipt; diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index e5bcff55670..b4a95a77db1 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -10,6 +10,7 @@ import {processVoluntaryExit} from "./processVoluntaryExit.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; import {processDepositReceipt} from "./processDepositReceipt.js"; import {ProcessBlockOpts} from "./types.js"; +import { getEth1DepositCount } from "../util/deposit.js"; export { processProposerSlashing, @@ -27,7 +28,7 @@ export function processOperations( opts: ProcessBlockOpts = {verifySignatures: true} ): void { // verify that outstanding deposits are processed up to the maximum number of deposits - const maxDeposits = Math.min(MAX_DEPOSITS, state.eth1Data.depositCount - state.eth1DepositIndex); + const maxDeposits = getEth1DepositCount(state); if (body.deposits.length !== maxDeposits) { throw new Error( `Block contains incorrect number of deposits: depositCount=${body.deposits.length} expected=${maxDeposits}` diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts new file mode 100644 index 00000000000..67021e6e6be --- /dev/null +++ b/packages/state-transition/src/util/deposit.ts @@ -0,0 +1,17 @@ +import { MAX_DEPOSITS } from "@lodestar/params"; +import { UintNum64 } from "@lodestar/types"; +import { BeaconStateAllForks } from "../types"; + +export function getEth1DepositCount(state: BeaconStateAllForks): UintNum64 { + + const eth1DataIndexLimit = ("depositReceiptsStartIndex" in state) ? + Math.min(state.eth1Data.depositCount, state.depositReceiptsStartIndex) + : + Math.min(state.eth1Data.depositCount, 0); + + if (state.eth1DepositIndex < eth1DataIndexLimit) { + return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); + } + + return 0; + } \ No newline at end of file diff --git a/packages/state-transition/src/util/index.ts b/packages/state-transition/src/util/index.ts index bbc9bf8a865..4323b259ad8 100644 --- a/packages/state-transition/src/util/index.ts +++ b/packages/state-transition/src/util/index.ts @@ -24,3 +24,4 @@ export * from "./slot.js"; export * from "./syncCommittee.js"; export * from "./validator.js"; export * from "./weakSubjectivity.js"; +export * from "./deposit.js"; From ef5024adcb9424817d1ca2709fe777b513476757 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 19 Sep 2023 17:30:37 +0800 Subject: [PATCH 034/155] Update eth1 deposit test --- .../test/unit/eth1/utils/deposits.test.ts | 34 +++++++++++++++++-- packages/beacon-node/test/utils/state.ts | 7 +++- .../config/src/chainConfig/presets/minimal.ts | 2 +- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 7b66a924892..8fa6f891cc5 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -1,6 +1,6 @@ import {expect} from "chai"; import {phase0, ssz} from "@lodestar/types"; -import {MAX_DEPOSITS} from "@lodestar/params"; +import {MAX_DEPOSITS, SLOTS_PER_EPOCH} from "@lodestar/params"; import {verifyMerkleBranch} from "@lodestar/utils"; import {filterBy} from "../../../utils/db.js"; import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; @@ -8,6 +8,7 @@ import {generateState} from "../../../utils/state.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src/eth1/utils/deposits.js"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; +import { minimalChainConfig } from "@lodestar/config/lib/presets.js"; describe("eth1 / util / deposits", function () { describe("getDeposits", () => { @@ -18,6 +19,7 @@ describe("eth1 / util / deposits", function () { depositIndexes: number[]; expectedReturnedIndexes?: number[]; error?: Eth1ErrorCode; + post6110? : boolean; }; const testCases: TestCase[] = [ @@ -70,12 +72,38 @@ describe("eth1 / util / deposits", function () { depositIndexes: [], expectedReturnedIndexes: [], }, + { + id: "No deposits to be included post 6110 after deposit_receipts_start_index", + depositCount: 2030, + eth1DepositIndex: 2025, + depositIndexes: Array.from({length: 2030}, (_, i) => i), + expectedReturnedIndexes: [], + post6110: true, + }, + { + id: "Should return deposits post 6110 before deposit_receipts_start_index", + depositCount: 2022, + eth1DepositIndex: 2018, + depositIndexes: Array.from({length: 2022}, (_, i) => i), + expectedReturnedIndexes: [2018, 2019, 2020, 2021, 2022], + post6110: true, + }, + { + id: "Should return deposits less than MAX_DEPOSITS post 6110 before deposit_receipts_start_index", + depositCount: 10 * MAX_DEPOSITS, + eth1DepositIndex: 0, + depositIndexes: Array.from({length: 10 * MAX_DEPOSITS}, (_, i) => i), + expectedReturnedIndexes: Array.from({length: MAX_DEPOSITS}, (_, i) => i), + post6110: true, + } ]; + const post6110Slot = minimalChainConfig.EIP6110_FORK_EPOCH * SLOTS_PER_EPOCH + 1; + for (const testCase of testCases) { - const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error} = testCase; + const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error, post6110} = testCase; it(id, async function () { - const state = generateState({eth1DepositIndex}); + const state = (post6110) ? generateState({slot: post6110Slot, eth1DepositIndex}) : generateState({eth1DepositIndex}); const eth1Data = generateEth1Data(depositCount); const deposits = depositIndexes.map((index) => generateDepositEvent(index)); const depositsGetter: DepositGetter = async (indexRange) => diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 801787983ec..0445bd8d592 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -9,7 +9,7 @@ import { BeaconStateBellatrix, createEmptyCarryoverData, } from "@lodestar/state-transition"; -import {allForks, altair, bellatrix, ssz} from "@lodestar/types"; +import {allForks, altair, bellatrix, eip6110, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; import {FAR_FUTURE_EPOCH, ForkName, ForkSeq, MAX_EFFECTIVE_BALANCE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; @@ -91,6 +91,11 @@ export function generateState( }; } + if (forkSeq >= ForkSeq.eip6110) { + const stateEIP6110 = state as eip6110.BeaconState; + stateEIP6110.depositReceiptsStartIndex = 2023; + } + return config.getForkTypes(stateSlot).BeaconState.toViewDU(state); } diff --git a/packages/config/src/chainConfig/presets/minimal.ts b/packages/config/src/chainConfig/presets/minimal.ts index 428eab1e499..d8d32fac7a7 100644 --- a/packages/config/src/chainConfig/presets/minimal.ts +++ b/packages/config/src/chainConfig/presets/minimal.ts @@ -43,7 +43,7 @@ export const chainConfig: ChainConfig = { DENEB_FORK_VERSION: b("0x04000001"), DENEB_FORK_EPOCH: Infinity, // EIP-6110 - EIP6110_FORK_VERSION: b("0x05000000"), + EIP6110_FORK_VERSION: b("0x05000001"), EIP6110_FORK_EPOCH: Infinity, // Time parameters From d468312008faeb4fdf53a3a05355f8aa2ab63b84 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 19 Sep 2023 17:50:08 +0800 Subject: [PATCH 035/155] Fix typo --- packages/validator/src/util/params.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index ada25155ac1..2e6f87894c7 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -107,8 +107,8 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Tue, 19 Sep 2023 18:18:04 +0800 Subject: [PATCH 036/155] Lint --- .../beacon-node/src/eth1/utils/deposits.ts | 2 +- .../src/execution/engine/payloadIdCache.ts | 2 +- .../beacon-node/src/execution/engine/types.ts | 18 ++- .../beacon-node/test/spec/presets/fork.ts | 2 +- .../test/spec/presets/transition.ts | 12 +- .../test/unit/eth1/utils/deposits.test.ts | 10 +- packages/light-client/src/spec/utils.ts | 5 +- .../unit/isValidLightClientHeader.test.ts | 11 +- packages/params/src/index.ts | 2 +- .../src/block/processDeposit.ts | 89 ++++++++------ .../src/block/processDepositReceipt.ts | 7 +- .../src/block/processOperations.ts | 4 +- .../state-transition/src/cache/epochCache.ts | 4 +- .../state-transition/src/cache/pubkeyCache.ts | 3 - .../src/slot/upgradeStateToEIP6110.ts | 4 +- packages/state-transition/src/util/deposit.ts | 27 ++--- .../test/unit/upgradeState.test.ts | 2 +- packages/types/src/allForks/types.ts | 112 ++++++++++++++---- packages/types/src/eip6110/sszTypes.ts | 57 +++------ packages/types/src/eip6110/types.ts | 2 - 20 files changed, 223 insertions(+), 152 deletions(-) diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index ca12b5b45cf..fb00db4b50a 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -3,9 +3,9 @@ import {toHexString} from "@chainsafe/ssz"; import {BeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {FilterOptions} from "@lodestar/db"; +import {getEth1DepositCount} from "@lodestar/state-transition"; import {Eth1Error, Eth1ErrorCode} from "../errors.js"; import {DepositTree} from "../../db/repositories/depositDataRoot.js"; -import { getEth1DepositCount } from "@lodestar/state-transition"; export type DepositGetter = (indexRange: FilterOptions, eth1Data: phase0.Eth1Data) => Promise; diff --git a/packages/beacon-node/src/execution/engine/payloadIdCache.ts b/packages/beacon-node/src/execution/engine/payloadIdCache.ts index 86df0057777..3d02648580b 100644 --- a/packages/beacon-node/src/execution/engine/payloadIdCache.ts +++ b/packages/beacon-node/src/execution/engine/payloadIdCache.ts @@ -24,7 +24,7 @@ export type DepositReceiptV1 = { amount: QUANTITY; signature: DATA; index: QUANTITY; -} +}; type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 6585f698140..02f380c91f1 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -113,9 +113,17 @@ type ExecutionPayloadRpcWithBlockValue = { }; type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithBlockValue; -export type ExecutionPayloadBodyRpc = {transactions: DATA[]; withdrawals: WithdrawalV1[] | null; depositReceipts: DepositReceiptV1[] | null}; +export type ExecutionPayloadBodyRpc = { + transactions: DATA[]; + withdrawals: WithdrawalV1[] | null; + depositReceipts: DepositReceiptV1[] | null; +}; -export type ExecutionPayloadBody = {transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; depositReceipts: eip6110.DepositReceipts | null}; +export type ExecutionPayloadBody = { + transactions: bellatrix.Transaction[]; + withdrawals: capella.Withdrawals | null; + depositReceipts: eip6110.DepositReceipts | null; +}; export type ExecutionPayloadRpc = { parentHash: DATA; // 32 bytes @@ -199,7 +207,7 @@ export function serializeExecutionPayload(fork: ForkName, data: allForks.Executi } // DENEB adds blobGasUsed & excessBlobGas to the ExecutionPayload - if (ForkSeq[fork] >= ForkSeq.deneb) { + if (ForkSeq[fork] >= ForkSeq.deneb) { const {blobGasUsed, excessBlobGas} = data as deneb.ExecutionPayload; payload.blobGasUsed = numToQuantity(blobGasUsed); payload.excessBlobGas = numToQuantity(excessBlobGas); @@ -295,7 +303,9 @@ export function parseExecutionPayload( `depositReceipts missing for ${fork} >= eip6110 executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as eip6110.ExecutionPayload).depositReceipts = depositReceipts.map((d) => deserializeDepositReceipts(d)); + (executionPayload as eip6110.ExecutionPayload).depositReceipts = depositReceipts.map((d) => + deserializeDepositReceipts(d) + ); } return {executionPayload, blockValue, blobsBundle}; diff --git a/packages/beacon-node/test/spec/presets/fork.ts b/packages/beacon-node/test/spec/presets/fork.ts index 83d1f18fc91..6c2ad4e464e 100644 --- a/packages/beacon-node/test/spec/presets/fork.ts +++ b/packages/beacon-node/test/spec/presets/fork.ts @@ -31,7 +31,7 @@ export const fork: TestRunnerFn = (forkNext) return slotFns.upgradeStateToBellatrix(preState as CachedBeaconStateAltair); case ForkName.capella: return slotFns.upgradeStateToCapella(preState as CachedBeaconStateBellatrix); - case ForkName.deneb: + case ForkName.deneb: return slotFns.upgradeStateToDeneb(preState as CachedBeaconStateCapella); case ForkName.eip6110: return slotFns.upgradeStateToEIP6110(preState as CachedBeaconStateDeneb); diff --git a/packages/beacon-node/test/spec/presets/transition.ts b/packages/beacon-node/test/spec/presets/transition.ts index 10b74af52fb..b21f9f189c4 100644 --- a/packages/beacon-node/test/spec/presets/transition.ts +++ b/packages/beacon-node/test/spec/presets/transition.ts @@ -97,10 +97,16 @@ function getTransitionConfig(fork: ForkName, forkEpoch: number): Partial { @@ -19,7 +19,7 @@ describe("eth1 / util / deposits", function () { depositIndexes: number[]; expectedReturnedIndexes?: number[]; error?: Eth1ErrorCode; - post6110? : boolean; + post6110?: boolean; }; const testCases: TestCase[] = [ @@ -95,7 +95,7 @@ describe("eth1 / util / deposits", function () { depositIndexes: Array.from({length: 10 * MAX_DEPOSITS}, (_, i) => i), expectedReturnedIndexes: Array.from({length: MAX_DEPOSITS}, (_, i) => i), post6110: true, - } + }, ]; const post6110Slot = minimalChainConfig.EIP6110_FORK_EPOCH * SLOTS_PER_EPOCH + 1; @@ -103,7 +103,9 @@ describe("eth1 / util / deposits", function () { for (const testCase of testCases) { const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error, post6110} = testCase; it(id, async function () { - const state = (post6110) ? generateState({slot: post6110Slot, eth1DepositIndex}) : generateState({eth1DepositIndex}); + const state = post6110 + ? generateState({slot: post6110Slot, eth1DepositIndex}) + : generateState({eth1DepositIndex}); const eth1Data = generateEth1Data(depositCount); const deposits = depositIndexes.map((index) => generateDepositEvent(index)); const depositsGetter: DepositGetter = async (indexRange) => diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 21704c72921..7824046bc26 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -12,9 +12,9 @@ import {altair, phase0, ssz, allForks, capella, deneb, Slot, eip6110} from "@lod import {ChainForkConfig} from "@lodestar/config"; import {computeEpochAtSlot} from "@lodestar/state-transition"; +import {Root} from "@lodestar/types/lib/sszTypes.js"; import {isValidMerkleBranch, computeSyncPeriodAtSlot} from "../utils/index.js"; import {LightClientStore} from "./store.js"; -import { Root } from "@lodestar/types/lib/sszTypes.js"; export const GENESIS_SLOT = 0; export const ZERO_HASH = new Uint8Array(32); @@ -150,7 +150,8 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: allFor if (epoch < config.EIP6110_FORK_EPOCH) { if ( (header as eip6110.LightClientHeader).execution.depositReceiptsRoot && - (header as eip6110.LightClientHeader).execution.depositReceiptsRoot !== Root.defaultValue()) { + (header as eip6110.LightClientHeader).execution.depositReceiptsRoot != Root.defaultValue() + ) { return false; } } diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index 3aa0a987e40..8c6ddd139eb 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -2,8 +2,8 @@ import {expect} from "chai"; import {fromHexString} from "@chainsafe/ssz"; import {ssz, allForks} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {Root} from "@lodestar/types/lib/sszTypes.js"; import {isValidLightClientHeader} from "../../src/spec/utils.js"; -import { Root } from "@lodestar/types/lib/sszTypes.js"; describe("isValidLightClientHeader", function () { /* eslint-disable @typescript-eslint/naming-convention */ @@ -94,12 +94,13 @@ describe("isValidLightClientHeader", function () { executionBranch: capellaLCHeader.executionBranch, }; - const denebLCHeader = { // TODO 6110: Find a denebLCHeader + const denebLCHeader = { + // TODO 6110: Find a denebLCHeader }; - const denebUpgradedEIP6110Header = { // TODO 6110: Find a denebLCHeader - - } + const denebUpgradedEIP6110Header = { + // TODO 6110: Find a denebLCHeader + }; const testCases: [string, allForks.LightClientHeader][] = [ ["altair LC header", altairLCHeader], diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index e240f3842fe..d59b4613ba2 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -249,4 +249,4 @@ export const BLOB_TX_TYPE = 0x03; export const VERSIONED_HASH_VERSION_KZG = 0x01; // EIP-6110 Misc -export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2 ** 64 - 1; \ No newline at end of file +export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2 ** 64 - 1; diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 86c560f9929..9307cb98dfc 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -23,7 +23,6 @@ import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; * PERF: Work depends on number of Deposit per block. On regular networks the average is 0 / block. */ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, deposit: phase0.Deposit): void { - // verify the merkle branch if ( !verifyMerkleBranch( @@ -47,16 +46,22 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, deposit.data.withdrawalCredentials, deposit.data.amount, deposit.data.signature - ) - + ); } /** * Adds a new validator into the registry. Or increase balance if already exist. * Follows applyDeposit() in consensus spec. Will be used by processDeposit() and processDepositReceipt() - * + * */ -export function applyDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, pubkey: BLSPubkey, withdrawalCredentials: Bytes32, amount: UintNum64, signature: BLSSignature): void { +export function applyDeposit( + fork: ForkSeq, + state: CachedBeaconStateAllForks, + pubkey: BLSPubkey, + withdrawalCredentials: Bytes32, + amount: UintNum64, + signature: BLSSignature +): void { const {config, validators, epochCtx} = state; const cachedIndex = epochCtx.getValidatorIndex(pubkey); @@ -87,42 +92,48 @@ export function applyDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, pu } } -function addValidatorToRegistry(fork: ForkSeq, state: CachedBeaconStateAllForks, pubkey: BLSPubkey, withdrawalCredentials: Bytes32, amount: UintNum64) : void { - const {validators, epochCtx} = state; - // add validator and balance entries - const effectiveBalance = Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); - validators.push( - ssz.phase0.Validator.toViewDU({ - pubkey, - withdrawalCredentials, - activationEligibilityEpoch: FAR_FUTURE_EPOCH, - activationEpoch: FAR_FUTURE_EPOCH, - exitEpoch: FAR_FUTURE_EPOCH, - withdrawableEpoch: FAR_FUTURE_EPOCH, - effectiveBalance, - slashed: false, - }) - ); - state.balances.push(amount); +function addValidatorToRegistry( + fork: ForkSeq, + state: CachedBeaconStateAllForks, + pubkey: BLSPubkey, + withdrawalCredentials: Bytes32, + amount: UintNum64 +): void { + const {validators, epochCtx} = state; + // add validator and balance entries + const effectiveBalance = Math.min(amount - (amount % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE); + validators.push( + ssz.phase0.Validator.toViewDU({ + pubkey, + withdrawalCredentials, + activationEligibilityEpoch: FAR_FUTURE_EPOCH, + activationEpoch: FAR_FUTURE_EPOCH, + exitEpoch: FAR_FUTURE_EPOCH, + withdrawableEpoch: FAR_FUTURE_EPOCH, + effectiveBalance, + slashed: false, + }) + ); + state.balances.push(amount); - const validatorIndex = validators.length - 1; - // Updating here is better than updating at once on epoch transition - // - Simplify genesis fn applyDeposits(): effectiveBalanceIncrements is populated immediately - // - Keep related code together to reduce risk of breaking this cache - // - Should have equal performance since it sets a value in a flat array - epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); + const validatorIndex = validators.length - 1; + // Updating here is better than updating at once on epoch transition + // - Simplify genesis fn applyDeposits(): effectiveBalanceIncrements is populated immediately + // - Keep related code together to reduce risk of breaking this cache + // - Should have equal performance since it sets a value in a flat array + epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); - // now that there is a new validator, update the epoch context with the new pubkey - epochCtx.addPubkey(pubkey, validatorIndex); + // now that there is a new validator, update the epoch context with the new pubkey + epochCtx.addPubkey(pubkey, validatorIndex); - // Only after altair: - if (fork >= ForkSeq.altair) { - const stateAltair = state as CachedBeaconStateAltair; + // Only after altair: + if (fork >= ForkSeq.altair) { + const stateAltair = state as CachedBeaconStateAltair; - stateAltair.inactivityScores.push(0); + stateAltair.inactivityScores.push(0); - // add participation caches - stateAltair.previousEpochParticipation.push(0); - stateAltair.currentEpochParticipation.push(0); - } -} \ No newline at end of file + // add participation caches + stateAltair.previousEpochParticipation.push(0); + stateAltair.currentEpochParticipation.push(0); + } +} diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositReceipt.ts index 89132feb12b..7d9210fc6f2 100644 --- a/packages/state-transition/src/block/processDepositReceipt.ts +++ b/packages/state-transition/src/block/processDepositReceipt.ts @@ -2,14 +2,13 @@ import {eip6110} from "@lodestar/types"; import {ForkSeq, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateEIP6110} from "../types.js"; -import { applyDeposit } from "./processDeposit.js"; +import {applyDeposit} from "./processDeposit.js"; export function processDepositReceipt( fork: ForkSeq, state: CachedBeaconStateEIP6110, depositReceipt: eip6110.DepositReceipt ): void { - if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { state.depositReceiptsStartIndex = depositReceipt.index; } @@ -20,6 +19,6 @@ export function processDepositReceipt( depositReceipt.pubkey, depositReceipt.withdrawalCredentials, depositReceipt.amount, - depositReceipt.signature, + depositReceipt.signature ); -} \ No newline at end of file +} diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index b4a95a77db1..dbffad312b7 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -1,7 +1,8 @@ import {allForks, capella, eip6110} from "@lodestar/types"; -import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; +import {ForkSeq} from "@lodestar/params"; import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateEIP6110} from "../types.js"; +import {getEth1DepositCount} from "../util/deposit.js"; import {processAttestations} from "./processAttestations.js"; import {processProposerSlashing} from "./processProposerSlashing.js"; import {processAttesterSlashing} from "./processAttesterSlashing.js"; @@ -10,7 +11,6 @@ import {processVoluntaryExit} from "./processVoluntaryExit.js"; import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js"; import {processDepositReceipt} from "./processDepositReceipt.js"; import {ProcessBlockOpts} from "./types.js"; -import { getEth1DepositCount } from "../util/deposit.js"; export { processProposerSlashing, diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 448eac16591..f00542c23f0 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -784,7 +784,7 @@ export class EpochCache { this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } else { this.globalPubkey2index.set(pubkey, index); - this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); } } @@ -795,7 +795,7 @@ export class EpochCache { */ addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { if (!this.isAfterEIP6110) { - throw new Error("addFInalizedPubkey is not available pre EIP-6110") + throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } if (this.globalPubkey2index.get(pubkey)) { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 416d165f0df..93ff4ba5e71 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -37,8 +37,6 @@ export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { return immutable.Map(); } - - export class PubkeyIndexMap { // We don't really need the full pubkey. We could just use the first 20 bytes like an Ethereum address readonly map = new Map(); @@ -57,7 +55,6 @@ export class PubkeyIndexMap { set(key: Uint8Array, value: ValidatorIndex): void { this.map.set(toMemoryEfficientHexStr(key), value); } - } /** diff --git a/packages/state-transition/src/slot/upgradeStateToEIP6110.ts b/packages/state-transition/src/slot/upgradeStateToEIP6110.ts index 4c852c8b35d..45585449f42 100644 --- a/packages/state-transition/src/slot/upgradeStateToEIP6110.ts +++ b/packages/state-transition/src/slot/upgradeStateToEIP6110.ts @@ -1,7 +1,7 @@ import {ssz} from "@lodestar/types"; +import {UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateDeneb} from "../types.js"; import {CachedBeaconStateEIP6110, getCachedBeaconState} from "../cache/stateCache.js"; -import { UNSET_DEPOSIT_RECEIPTS_START_INDEX } from "@lodestar/params"; /** * Upgrade a state from Capella to Deneb. @@ -20,8 +20,6 @@ export function upgradeStateToEIP6110(stateDeneb: CachedBeaconStateDeneb): Cache epoch: stateDeneb.epochCtx.epoch, }); - - // latestExecutionPayloadHeader's depositReceiptsRoot set to zeros by default // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX stateEIP6110.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 67021e6e6be..747b1cd9dfc 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -1,17 +1,16 @@ -import { MAX_DEPOSITS } from "@lodestar/params"; -import { UintNum64 } from "@lodestar/types"; -import { BeaconStateAllForks } from "../types"; +import {MAX_DEPOSITS} from "@lodestar/params"; +import {UintNum64} from "@lodestar/types"; +import {BeaconStateAllForks} from "../types.js"; export function getEth1DepositCount(state: BeaconStateAllForks): UintNum64 { + const eth1DataIndexLimit = + "depositReceiptsStartIndex" in state + ? Math.min(state.eth1Data.depositCount, state.depositReceiptsStartIndex) + : Math.min(state.eth1Data.depositCount, 0); - const eth1DataIndexLimit = ("depositReceiptsStartIndex" in state) ? - Math.min(state.eth1Data.depositCount, state.depositReceiptsStartIndex) - : - Math.min(state.eth1Data.depositCount, 0); - - if (state.eth1DepositIndex < eth1DataIndexLimit) { - return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); - } - - return 0; - } \ No newline at end of file + if (state.eth1DepositIndex < eth1DataIndexLimit) { + return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); + } + + return 0; +} diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index e8d628464c2..3cdcdd84603 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -6,7 +6,7 @@ import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodes import {config as chainConfig} from "@lodestar/config/default"; import {upgradeStateToDeneb} from "../../src/slot/upgradeStateToDeneb.js"; -import { upgradeStateToEIP6110 } from "../../src/slot/upgradeStateToEIP6110.js"; +import {upgradeStateToEIP6110} from "../../src/slot/upgradeStateToEIP6110.js"; describe("upgradeState", () => { it("upgradeStateToDeneb", () => { diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index d62ad199e5a..9f81e458eb8 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -46,10 +46,18 @@ export type BeaconState = export type Metadata = phase0.Metadata | altair.Metadata; // For easy reference in the assemble block for building payloads -export type ExecutionBlockBody = bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody | eip6110.BeaconBlockBody; +export type ExecutionBlockBody = + | bellatrix.BeaconBlockBody + | capella.BeaconBlockBody + | deneb.BeaconBlockBody + | eip6110.BeaconBlockBody; // These two additional types will also change bellatrix forward -export type ExecutionPayload = bellatrix.ExecutionPayload | capella.ExecutionPayload | deneb.ExecutionPayload | eip6110.ExecutionPayload; +export type ExecutionPayload = + | bellatrix.ExecutionPayload + | capella.ExecutionPayload + | deneb.ExecutionPayload + | eip6110.ExecutionPayload; export type ExecutionPayloadHeader = | bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader @@ -62,7 +70,11 @@ export type BlindedBeaconBlockBody = | capella.BlindedBeaconBlockBody | deneb.BlindedBeaconBlockBody | eip6110.BlindedBeaconBlockBody; -export type BlindedBeaconBlock = bellatrix.BlindedBeaconBlock | capella.BlindedBeaconBlock | deneb.BlindedBeaconBlock | eip6110.BlindedBeaconBlock; +export type BlindedBeaconBlock = + | bellatrix.BlindedBeaconBlock + | capella.BlindedBeaconBlock + | deneb.BlindedBeaconBlock + | eip6110.BlindedBeaconBlock; export type SignedBlindedBeaconBlock = | bellatrix.SignedBlindedBeaconBlock | capella.SignedBlindedBeaconBlock @@ -77,21 +89,33 @@ export type FullOrBlindedBeaconBlockBody = BeaconBlockBody | BlindedBeaconBlockB export type FullOrBlindedBeaconBlock = BeaconBlock | BlindedBeaconBlock; export type FullOrBlindedSignedBeaconBlock = SignedBeaconBlock | SignedBlindedBeaconBlock; -export type FullOrBlindedBlobSidecar = deneb.BlobSidecar | deneb.BlindedBlobSidecar ; +export type FullOrBlindedBlobSidecar = deneb.BlobSidecar | deneb.BlindedBlobSidecar; export type FullOrBlindedSignedBlobSidecar = deneb.SignedBlobSidecar | deneb.SignedBlindedBlobSidecar; export type FullOrBlindedBlobSidecars = deneb.BlobSidecars | deneb.BlindedBlobSidecars; export type BuilderBid = bellatrix.BuilderBid | capella.BuilderBid | deneb.BuilderBid | eip6110.BuilderBid; -export type SignedBuilderBid = bellatrix.SignedBuilderBid | capella.SignedBuilderBid | deneb.SignedBuilderBid | eip6110.SignedBuilderBid; +export type SignedBuilderBid = + | bellatrix.SignedBuilderBid + | capella.SignedBuilderBid + | deneb.SignedBuilderBid + | eip6110.SignedBuilderBid; -export type LightClientHeader = altair.LightClientHeader | capella.LightClientHeader | deneb.LightClientHeader | eip6110.LightClientHeader; +export type LightClientHeader = + | altair.LightClientHeader + | capella.LightClientHeader + | deneb.LightClientHeader + | eip6110.LightClientHeader; export type LightClientBootstrap = | altair.LightClientBootstrap | capella.LightClientBootstrap | deneb.LightClientBootstrap | eip6110.LightClientBootstrap; -export type LightClientUpdate = altair.LightClientUpdate | capella.LightClientUpdate | deneb.LightClientUpdate | eip6110.LightClientUpdate; +export type LightClientUpdate = + | altair.LightClientUpdate + | capella.LightClientUpdate + | deneb.LightClientUpdate + | eip6110.LightClientUpdate; export type LightClientFinalityUpdate = | altair.LightClientFinalityUpdate | capella.LightClientFinalityUpdate @@ -102,7 +126,11 @@ export type LightClientOptimisticUpdate = | capella.LightClientOptimisticUpdate | deneb.LightClientOptimisticUpdate | eip6110.LightClientOptimisticUpdate; -export type LightClientStore = altair.LightClientStore | capella.LightClientStore | deneb.LightClientStore | eip6110.LightClientStore; +export type LightClientStore = + | altair.LightClientStore + | capella.LightClientStore + | deneb.LightClientStore + | eip6110.LightClientStore; export type SSEPayloadAttributes = | bellatrix.SSEPayloadAttributes @@ -133,7 +161,12 @@ export type AllForksBlindedTypes = { }; export type AllForksLightClient = { - BeaconBlock: altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock | eip6110.BeaconBlock; + BeaconBlock: + | altair.BeaconBlock + | bellatrix.BeaconBlock + | capella.BeaconBlock + | deneb.BeaconBlock + | eip6110.BeaconBlock; LightClientHeader: LightClientHeader; LightClientBootstrap: LightClientBootstrap; LightClientUpdate: LightClientUpdate; @@ -144,7 +177,11 @@ export type AllForksLightClient = { export type AllForksExecution = { BeaconBlock: bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock | eip6110.BeaconBlock; - BeaconBlockBody: bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody | eip6110.BeaconBlockBody; + BeaconBlockBody: + | bellatrix.BeaconBlockBody + | capella.BeaconBlockBody + | deneb.BeaconBlockBody + | eip6110.BeaconBlockBody; }; /** @@ -214,19 +251,34 @@ export type AllForksSSZTypes = { export type AllForksExecutionSSZTypes = { BeaconBlockBody: AllForksTypeOf< - typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody | typeof eip6110Ssz.BeaconBlockBody + | typeof bellatrixSsz.BeaconBlockBody + | typeof capellaSsz.BeaconBlockBody + | typeof denebSsz.BeaconBlockBody + | typeof eip6110Ssz.BeaconBlockBody >; BeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock | typeof eip6110Ssz.BeaconBlock + | typeof bellatrixSsz.BeaconBlock + | typeof capellaSsz.BeaconBlock + | typeof denebSsz.BeaconBlock + | typeof eip6110Ssz.BeaconBlock >; SignedBeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock | typeof eip6110Ssz.SignedBeaconBlock + | typeof bellatrixSsz.SignedBeaconBlock + | typeof capellaSsz.SignedBeaconBlock + | typeof denebSsz.SignedBeaconBlock + | typeof eip6110Ssz.SignedBeaconBlock >; BeaconState: AllForksTypeOf< - typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState | typeof eip6110Ssz.BeaconState + | typeof bellatrixSsz.BeaconState + | typeof capellaSsz.BeaconState + | typeof denebSsz.BeaconState + | typeof eip6110Ssz.BeaconState >; ExecutionPayload: AllForksTypeOf< - typeof bellatrixSsz.ExecutionPayload | typeof capellaSsz.ExecutionPayload | typeof denebSsz.ExecutionPayload | typeof eip6110Ssz.ExecutionPayload + | typeof bellatrixSsz.ExecutionPayload + | typeof capellaSsz.ExecutionPayload + | typeof denebSsz.ExecutionPayload + | typeof eip6110Ssz.ExecutionPayload >; ExecutionPayloadHeader: AllForksTypeOf< | typeof bellatrixSsz.ExecutionPayloadHeader @@ -235,10 +287,16 @@ export type AllForksExecutionSSZTypes = { | typeof eip6110Ssz.ExecutionPayloadHeader >; BuilderBid: AllForksTypeOf< - typeof bellatrixSsz.BuilderBid | typeof capellaSsz.BuilderBid | typeof denebSsz.BuilderBid | typeof eip6110Ssz.BuilderBid + | typeof bellatrixSsz.BuilderBid + | typeof capellaSsz.BuilderBid + | typeof denebSsz.BuilderBid + | typeof eip6110Ssz.BuilderBid >; SignedBuilderBid: AllForksTypeOf< - typeof bellatrixSsz.SignedBuilderBid | typeof capellaSsz.SignedBuilderBid | typeof denebSsz.SignedBuilderBid | typeof eip6110Ssz.SignedBuilderBid + | typeof bellatrixSsz.SignedBuilderBid + | typeof capellaSsz.SignedBuilderBid + | typeof denebSsz.SignedBuilderBid + | typeof eip6110Ssz.SignedBuilderBid >; SSEPayloadAttributes: AllForksTypeOf< | typeof bellatrixSsz.SSEPayloadAttributes @@ -256,7 +314,10 @@ export type AllForksBlindedSSZTypes = { | typeof eip6110Ssz.BlindedBeaconBlock >; BeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.BlindedBeaconBlock | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock | typeof eip6110Ssz.BlindedBeaconBlock + | typeof bellatrixSsz.BlindedBeaconBlock + | typeof capellaSsz.BlindedBeaconBlock + | typeof denebSsz.BlindedBeaconBlock + | typeof eip6110Ssz.BlindedBeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof bellatrixSsz.SignedBlindedBeaconBlock @@ -282,7 +343,10 @@ export type AllForksLightClientSSZTypes = { | typeof eip6110Ssz.BeaconBlockBody >; LightClientHeader: AllForksTypeOf< - typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader | typeof eip6110Ssz.LightClientHeader + | typeof altairSsz.LightClientHeader + | typeof capellaSsz.LightClientHeader + | typeof denebSsz.LightClientHeader + | typeof eip6110Ssz.LightClientHeader >; LightClientBootstrap: AllForksTypeOf< | typeof altairSsz.LightClientBootstrap @@ -291,7 +355,10 @@ export type AllForksLightClientSSZTypes = { | typeof eip6110Ssz.LightClientBootstrap >; LightClientUpdate: AllForksTypeOf< - typeof altairSsz.LightClientUpdate | typeof capellaSsz.LightClientUpdate | typeof denebSsz.LightClientUpdate | typeof eip6110Ssz.LightClientUpdate + | typeof altairSsz.LightClientUpdate + | typeof capellaSsz.LightClientUpdate + | typeof denebSsz.LightClientUpdate + | typeof eip6110Ssz.LightClientUpdate >; LightClientFinalityUpdate: AllForksTypeOf< | typeof altairSsz.LightClientFinalityUpdate @@ -306,7 +373,10 @@ export type AllForksLightClientSSZTypes = { | typeof eip6110Ssz.LightClientOptimisticUpdate >; LightClientStore: AllForksTypeOf< - typeof altairSsz.LightClientStore | typeof capellaSsz.LightClientStore | typeof denebSsz.LightClientStore | typeof eip6110Ssz.LightClientStore + | typeof altairSsz.LightClientStore + | typeof capellaSsz.LightClientStore + | typeof denebSsz.LightClientStore + | typeof eip6110Ssz.LightClientStore >; }; diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index 79aea8433fb..8fc9ea7820a 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -13,19 +13,8 @@ import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -const { - UintNum64, - Slot, - Root, - BLSSignature, - UintBn256, - Bytes32, - BLSPubkey, - ValidatorIndex, - DepositIndex, - Gwei, -} = primitiveSsz; - +const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, ValidatorIndex, DepositIndex} = + primitiveSsz; export const DepositReceipt = new ContainerType( //good { @@ -41,8 +30,7 @@ export const DepositReceipt = new ContainerType( //good export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); - -export const ExecutionPayload = new ContainerType( // good +export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, depositReceipts: DepositReceipts, // New in EIP6110 @@ -50,7 +38,7 @@ export const ExecutionPayload = new ContainerType( // good {typeName: "ExecutionPayload", jsonCase: "eth2"} ); -export const ExecutionPayloadHeader = new ContainerType( // good +export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, depositReceiptsRoot: Root, // New in EIP6110 @@ -59,17 +47,17 @@ export const ExecutionPayloadHeader = new ContainerType( // good ); // We have to preserve Fields ordering while changing the type of ExecutionPayload -export const BeaconBlockBody = new ContainerType( // good +export const BeaconBlockBody = new ContainerType( { ...altairSsz.BeaconBlockBody.fields, executionPayload: ExecutionPayload, // Modified in EIP6110 blsToExecutionChanges: denebSsz.BeaconBlockBody.fields.blsToExecutionChanges, - blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, + blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, }, {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const BeaconBlock = new ContainerType( // good +export const BeaconBlock = new ContainerType( { ...denebSsz.BeaconBlock.fields, body: BeaconBlockBody, // Modified in EIP6110 @@ -77,7 +65,7 @@ export const BeaconBlock = new ContainerType( // good {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const SignedBeaconBlock = new ContainerType( // good +export const SignedBeaconBlock = new ContainerType( { message: BeaconBlock, // Modified in EIP6110 signature: BLSSignature, @@ -85,16 +73,7 @@ export const SignedBeaconBlock = new ContainerType( // good {typeName: "SignedBeaconBlock", jsonCase: "eth2"} ); - -export const SignedBeaconBlockAndBlobSidecars = new ContainerType( // good - { - beaconBlock: SignedBeaconBlock, // Modified in EIP6110 - blobSidecars: denebSsz.SignedBeaconBlockAndBlobSidecars.fields.blobSidecars, - }, - {typeName: "SignedBeaconBlockAndBlobSidecars", jsonCase: "eth2"} -); - -export const BlindedBeaconBlockBody = new ContainerType( // good +export const BlindedBeaconBlockBody = new ContainerType( { ...altairSsz.BeaconBlockBody.fields, executionPayloadHeader: ExecutionPayloadHeader, // Modified in EIP6110 @@ -104,7 +83,7 @@ export const BlindedBeaconBlockBody = new ContainerType( // good {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const BlindedBeaconBlock = new ContainerType( // good +export const BlindedBeaconBlock = new ContainerType( { ...denebSsz.BlindedBeaconBlock.fields, body: BlindedBeaconBlockBody, // Modified in EIP6110 @@ -112,7 +91,7 @@ export const BlindedBeaconBlock = new ContainerType( // good {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const SignedBlindedBeaconBlock = new ContainerType( // good +export const SignedBlindedBeaconBlock = new ContainerType( { message: BlindedBeaconBlock, // Modified in EIP6110 signature: BLSSignature, @@ -120,7 +99,7 @@ export const SignedBlindedBeaconBlock = new ContainerType( // good {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} ); -export const BuilderBid = new ContainerType( // good +export const BuilderBid = new ContainerType( { header: ExecutionPayloadHeader, // Modified in EIP6110 value: UintBn256, @@ -130,7 +109,7 @@ export const BuilderBid = new ContainerType( // good {typeName: "BuilderBid", jsonCase: "eth2"} ); -export const SignedBuilderBid = new ContainerType( // good +export const SignedBuilderBid = new ContainerType( { message: BuilderBid, signature: BLSSignature, @@ -140,7 +119,7 @@ export const SignedBuilderBid = new ContainerType( // good // We don't spread deneb.BeaconState fields since we need to replace // latestExecutionPayloadHeader and we cannot keep order doing that -export const BeaconState = new ContainerType( // good +export const BeaconState = new ContainerType( { genesisTime: UintNum64, genesisValidatorsRoot: Root, @@ -187,7 +166,7 @@ export const BeaconState = new ContainerType( // good {typeName: "BeaconState", jsonCase: "eth2"} ); -export const LightClientHeader = new ContainerType( // good +export const LightClientHeader = new ContainerType( { beacon: phase0Ssz.BeaconBlockHeader, execution: ExecutionPayloadHeader, // Modified in EIP6110 @@ -196,7 +175,7 @@ export const LightClientHeader = new ContainerType( // good {typeName: "LightClientHeader", jsonCase: "eth2"} ); -export const LightClientBootstrap = new ContainerType( // good +export const LightClientBootstrap = new ContainerType( { header: LightClientHeader, currentSyncCommittee: altairSsz.SyncCommittee, @@ -205,7 +184,7 @@ export const LightClientBootstrap = new ContainerType( // good {typeName: "LightClientBootstrap", jsonCase: "eth2"} ); -export const LightClientUpdate = new ContainerType( // good +export const LightClientUpdate = new ContainerType( { attestedHeader: LightClientHeader, nextSyncCommittee: altairSsz.SyncCommittee, @@ -218,7 +197,7 @@ export const LightClientUpdate = new ContainerType( // good {typeName: "LightClientUpdate", jsonCase: "eth2"} ); -export const LightClientFinalityUpdate = new ContainerType( // good +export const LightClientFinalityUpdate = new ContainerType( { attestedHeader: LightClientHeader, finalizedHeader: LightClientHeader, diff --git a/packages/types/src/eip6110/types.ts b/packages/types/src/eip6110/types.ts index dcb20382dcc..42d0187309d 100644 --- a/packages/types/src/eip6110/types.ts +++ b/packages/types/src/eip6110/types.ts @@ -11,8 +11,6 @@ export type BeaconBlockBody = ValueOf; export type BeaconBlock = ValueOf; export type SignedBeaconBlock = ValueOf; -export type SignedBeaconBlockAndBlobSidecars = ValueOf; - export type BeaconState = ValueOf; export type BlindedBeaconBlockBody = ValueOf; From 1029aba78612a2602725527ceb2ed5f085127d4a Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 20 Sep 2023 14:06:42 +0800 Subject: [PATCH 037/155] Remove embarassing comments --- packages/types/src/eip6110/sszTypes.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index 8fc9ea7820a..c58f4883926 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -16,7 +16,7 @@ import {ssz as denebSsz} from "../deneb/index.js"; const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, ValidatorIndex, DepositIndex} = primitiveSsz; -export const DepositReceipt = new ContainerType( //good +export const DepositReceipt = new ContainerType( { pubkey: BLSPubkey, withdrawalCredentials: Bytes32, @@ -208,7 +208,7 @@ export const LightClientFinalityUpdate = new ContainerType( {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} ); -export const LightClientOptimisticUpdate = new ContainerType( //good +export const LightClientOptimisticUpdate = new ContainerType( { attestedHeader: LightClientHeader, syncAggregate: altairSsz.SyncAggregate, @@ -217,7 +217,7 @@ export const LightClientOptimisticUpdate = new ContainerType( //good {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} ); -export const LightClientStore = new ContainerType( //good +export const LightClientStore = new ContainerType( { snapshot: LightClientBootstrap, validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), @@ -226,7 +226,7 @@ export const LightClientStore = new ContainerType( //good ); // PayloadAttributes primarily for SSE event -export const PayloadAttributes = new ContainerType( //good +export const PayloadAttributes = new ContainerType( { ...capellaSsz.PayloadAttributes.fields, parentBeaconBlockRoot: Root, @@ -234,7 +234,7 @@ export const PayloadAttributes = new ContainerType( //good {typeName: "PayloadAttributes", jsonCase: "eth2"} ); -export const SSEPayloadAttributes = new ContainerType( //good +export const SSEPayloadAttributes = new ContainerType( { ...bellatrixSsz.SSEPayloadAttributesCommon.fields, payloadAttributes: PayloadAttributes, From c830b0c796b0031e08213e6facec46f5d498ba8c Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 20 Sep 2023 14:07:55 +0800 Subject: [PATCH 038/155] Address comments --- .../test/unit/isValidLightClientHeader.test.ts | 7 +++---- packages/params/src/index.ts | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index 8c6ddd139eb..67fe9bcba3f 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -1,8 +1,7 @@ import {expect} from "chai"; -import {fromHexString} from "@chainsafe/ssz"; +import {ByteVectorType, fromHexString} from "@chainsafe/ssz"; import {ssz, allForks} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {Root} from "@lodestar/types/lib/sszTypes.js"; import {isValidLightClientHeader} from "../../src/spec/utils.js"; describe("isValidLightClientHeader", function () { @@ -37,7 +36,7 @@ describe("isValidLightClientHeader", function () { const altairUpgradedDenebLCHeader = { beacon: altairLCHeader.beacon, - execution: ssz.deneb.LightClientHeader.fields.execution.defaultValue(), // TODO + execution: ssz.deneb.LightClientHeader.fields.execution.defaultValue(), executionBranch: ssz.deneb.LightClientHeader.fields.executionBranch.defaultValue(), }; @@ -90,7 +89,7 @@ describe("isValidLightClientHeader", function () { const capellaUpgradedEIP6110Header = { beacon: capellaLCHeader.beacon, - execution: {...capellaLCHeader.execution, blobGasUsed: 0, excessBlobGas: 0, depositReceiptsRoot: Root.defaultValue}, + execution: {...capellaLCHeader.execution, blobGasUsed: 0, excessBlobGas: 0, depositReceiptsRoot: new ByteVectorType(32)}, executionBranch: capellaLCHeader.executionBranch, }; diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index d59b4613ba2..ed34da25563 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -249,4 +249,4 @@ export const BLOB_TX_TYPE = 0x03; export const VERSIONED_HASH_VERSION_KZG = 0x01; // EIP-6110 Misc -export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2 ** 64 - 1; +export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = Infinity; From 3dbccd84786d3fbf76d812cbf27570f391795665 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 20 Sep 2023 14:15:45 +0800 Subject: [PATCH 039/155] Modify applyDeposit signature --- .../src/block/processDeposit.ts | 17 +++++++---------- .../src/block/processDepositReceipt.ts | 5 +---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 9307cb98dfc..389bea86278 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -15,6 +15,8 @@ import { import {ZERO_HASH} from "../constants/index.js"; import {computeDomain, computeSigningRoot, increaseBalance} from "../util/index.js"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; +import { DepositData } from "@lodestar/types/lib/phase0/types.js"; +import { DepositReceipt } from "@lodestar/types/lib/eip6110/types.js"; /** * Process a Deposit operation. Potentially adds a new validator to the registry. Mutates the validators and balances @@ -42,10 +44,7 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, applyDeposit( fork, state, - deposit.data.pubkey, - deposit.data.withdrawalCredentials, - deposit.data.amount, - deposit.data.signature + deposit.data ); } @@ -57,12 +56,10 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, export function applyDeposit( fork: ForkSeq, state: CachedBeaconStateAllForks, - pubkey: BLSPubkey, - withdrawalCredentials: Bytes32, - amount: UintNum64, - signature: BLSSignature + deposit: DepositData | DepositReceipt ): void { const {config, validators, epochCtx} = state; + const {pubkey, withdrawalCredentials, amount} = deposit; const cachedIndex = epochCtx.getValidatorIndex(pubkey); if (cachedIndex === undefined || !Number.isSafeInteger(cachedIndex) || cachedIndex >= validators.length) { @@ -78,8 +75,8 @@ export function applyDeposit( try { // Pubkeys must be checked for group + inf. This must be done only once when the validator deposit is processed const publicKey = bls.PublicKey.fromBytes(pubkey, CoordType.affine, true); - const computedSignature = bls.Signature.fromBytes(signature, CoordType.affine, true); - if (!computedSignature.verify(publicKey, signingRoot)) { + const signature = bls.Signature.fromBytes(deposit.signature, CoordType.affine, true); + if (!signature.verify(publicKey, signingRoot)) { return; } } catch (e) { diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositReceipt.ts index 7d9210fc6f2..e425ae0a5cf 100644 --- a/packages/state-transition/src/block/processDepositReceipt.ts +++ b/packages/state-transition/src/block/processDepositReceipt.ts @@ -16,9 +16,6 @@ export function processDepositReceipt( applyDeposit( fork, state, - depositReceipt.pubkey, - depositReceipt.withdrawalCredentials, - depositReceipt.amount, - depositReceipt.signature + depositReceipt ); } From 5bb5dcac3802cb9a964a5684ad254b4e524fe607 Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 20 Sep 2023 15:57:21 +0800 Subject: [PATCH 040/155] Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> --- packages/state-transition/src/cache/epochCache.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index f00542c23f0..a91d240f038 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -770,8 +770,9 @@ export class EpochCache { getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { if (this.isAfterEIP6110) { return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + } else { + return this.globalPubkey2index.get(pubkey); } - return this.globalPubkey2index.get(pubkey); } /** From 3cb55ba5b2a0a136d3b6dd62e401ae802789411a Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 20 Sep 2023 15:57:46 +0800 Subject: [PATCH 041/155] Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> --- packages/state-transition/src/cache/epochCache.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index a91d240f038..c5cb0b3cd0b 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -112,7 +112,6 @@ export class EpochCache { globalIndex2pubkey: Index2PubkeyCache; /** * Unique pubkey registry shared in the same fork. There should only exist one for the fork. - * */ unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; From 7e4f5d7ac48f151714247048465eb1dfcda3e6c9 Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 20 Sep 2023 15:59:39 +0800 Subject: [PATCH 042/155] Update packages/state-transition/src/cache/pubkeyCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> --- packages/state-transition/src/cache/pubkeyCache.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 93ff4ba5e71..ed00ce0fe3a 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -29,9 +29,7 @@ export function toMemoryEfficientHexStr(hex: Uint8Array | string): string { } /** - * * A wrapper for calling immutable.js. To abstract the initialization of UnfinalizedPubkeyIndexMap - * */ export function newUnfinalizedPubkeyIndexMap(): UnfinalizedPubkeyIndexMap { return immutable.Map(); From 22d908106a07980ee4a460e584625eff666841e4 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 20 Sep 2023 15:55:32 +0800 Subject: [PATCH 043/155] Remove old code --- packages/types/src/allForks/sszTypes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index a08371d0a74..a0ddd2dea32 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -192,7 +192,6 @@ export const allForksBlobs = { BlindedBlobSidecar: deneb.BlindedBlobSidecar, }, eip6110: { - SignedBeaconBlockAndBlobSidecars: eip6110.SignedBeaconBlockAndBlobSidecars, BlobSidecar: deneb.BlobSidecar, BlindedBlobSidecar: deneb.BlindedBlobSidecar, }, From 6b3d39b64f06d9f69bc4eef3187fd3422bc1f45a Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 20 Sep 2023 16:16:38 +0800 Subject: [PATCH 044/155] Rename fields in epochCache and immutableData --- packages/beacon-node/src/chain/chain.ts | 8 +-- packages/beacon-node/test/utils/state.ts | 10 +-- .../state-transition/src/cache/epochCache.ts | 64 +++++++++---------- packages/state-transition/test/perf/util.ts | 12 ++-- .../test/unit/util/cachedBeaconState.test.ts | 4 +- packages/state-transition/test/utils/state.ts | 8 +-- 6 files changed, 53 insertions(+), 53 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 94fa6d3a0ea..77f5fb3f510 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -225,15 +225,15 @@ export class BeaconChain implements IBeaconChain { anchorState, { config, - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, createEmptyCarryoverData() ); // Persist single global instance of state caches - this.pubkey2index = cachedState.epochCtx.globalPubkey2index; // TODO: Double check if these two are correct - this.index2pubkey = cachedState.epochCtx.globalIndex2pubkey; + this.pubkey2index = cachedState.epochCtx.finalizedPubkey2index; // TODO: Double check if these two are correct + this.index2pubkey = cachedState.epochCtx.finalizedIndex2pubkey; const stateCache = new StateContextCache({metrics}); const checkpointStateCache = new CheckpointStateCache({metrics}); diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 0445bd8d592..a887ced5931 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -110,8 +110,8 @@ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAl { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a performance test, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, createEmptyCarryoverData() ); @@ -128,8 +128,8 @@ export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoc { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a performance test, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, createEmptyCarryoverData() ); @@ -146,7 +146,7 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a performance test, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), + finali: new PubkeyIndexMap(), index2pubkey: [], }, createEmptyCarryoverData() diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index c5cb0b3cd0b..2dca0740450 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -51,8 +51,8 @@ export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PR export type EpochCacheImmutableData = { config: BeaconConfig; - pubkey2index: PubkeyIndexMap; - index2pubkey: Index2PubkeyCache; + finalizedPubkey2index: PubkeyIndexMap; + finalizedIndex2pubkey: Index2PubkeyCache; }; export type CarryoverData = { @@ -101,7 +101,7 @@ export class EpochCache { * * $VALIDATOR_COUNT x 192 char String -> Number Map */ - globalPubkey2index: PubkeyIndexMap; + finalizedPubkey2index: PubkeyIndexMap; /** * Unique globally shared pubkey registry. There should only exist one for the entire application. * @@ -109,7 +109,7 @@ export class EpochCache { * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ - globalIndex2pubkey: Index2PubkeyCache; + finalizedIndex2pubkey: Index2PubkeyCache; /** * Unique pubkey registry shared in the same fork. There should only exist one for the fork. */ @@ -209,8 +209,8 @@ export class EpochCache { constructor(data: { config: BeaconConfig; - globalPubkey2index: PubkeyIndexMap; - globalIndex2pubkey: Index2PubkeyCache; + finalizedPubkey2index: PubkeyIndexMap; + finalizedIndex2pubkey: Index2PubkeyCache; unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; proposers: number[]; proposersPrevEpoch: number[] | null; @@ -235,8 +235,8 @@ export class EpochCache { isAfterEIP6110: boolean; }) { this.config = data.config; - this.globalPubkey2index = data.globalPubkey2index; - this.globalIndex2pubkey = data.globalIndex2pubkey; + this.finalizedPubkey2index = data.finalizedPubkey2index; + this.finalizedIndex2pubkey = data.finalizedIndex2pubkey; this.unfinalizedPubkey2index = data.unfinalizedPubkey2index; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; @@ -269,14 +269,14 @@ export class EpochCache { */ static createFromState( state: BeaconStateAllForks, - {config, pubkey2index, index2pubkey}: EpochCacheImmutableData, + {config, finalizedPubkey2index, finalizedIndex2pubkey}: EpochCacheImmutableData, {unfinalizedPubkey2index}: CarryoverData, opts?: EpochCacheOpts ): EpochCache { // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches // - computeSyncCommitteeCache() needs a fully populated pubkey2index cache if (!opts?.skipSyncPubkeys) { - syncPubkeys(state, pubkey2index, index2pubkey); + syncPubkeys(state, finalizedPubkey2index, finalizedIndex2pubkey); } const currentEpoch = computeEpochAtSlot(state.slot); @@ -366,8 +366,8 @@ export class EpochCache { // Allow to skip populating sync committee for initializeBeaconStateFromEth1() if (afterAltairFork && !opts?.skipSyncCommitteeCache) { const altairState = state as BeaconStateAltair; - currentSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.currentSyncCommittee, pubkey2index); - nextSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.nextSyncCommittee, pubkey2index); + currentSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.currentSyncCommittee, finalizedPubkey2index); + nextSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.nextSyncCommittee, finalizedPubkey2index); } else { currentSyncCommitteeIndexed = new SyncCommitteeCacheEmpty(); nextSyncCommitteeIndexed = new SyncCommitteeCacheEmpty(); @@ -414,8 +414,8 @@ export class EpochCache { return new EpochCache({ config, - globalPubkey2index: pubkey2index, - globalIndex2pubkey: index2pubkey, + finalizedPubkey2index, + finalizedIndex2pubkey, unfinalizedPubkey2index, proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics @@ -452,8 +452,8 @@ export class EpochCache { return new EpochCache({ config: this.config, // Common append-only structures shared with all states, no need to clone - globalPubkey2index: this.globalPubkey2index, - globalIndex2pubkey: this.globalIndex2pubkey, + finalizedPubkey2index: this.finalizedPubkey2index, + finalizedIndex2pubkey: this.finalizedIndex2pubkey, // Fork-aware cache needs to be cloned. But by the virtue of it being persistent, we don't need to do anything here unfinalizedPubkey2index: this.unfinalizedPubkey2index, // Immutable data @@ -763,14 +763,14 @@ export class EpochCache { } getPubkey(index: ValidatorIndex): PublicKey { - return this.globalIndex2pubkey[index]; + return this.finalizedIndex2pubkey[index]; } getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { if (this.isAfterEIP6110) { - return this.globalPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + return this.finalizedPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } else { - return this.globalPubkey2index.get(pubkey); + return this.finalizedPubkey2index.get(pubkey); } } @@ -783,8 +783,8 @@ export class EpochCache { if (this.isAfterEIP6110) { this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } else { - this.globalPubkey2index.set(pubkey, index); - this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.finalizedPubkey2index.set(pubkey, index); + this.finalizedIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); } } @@ -798,12 +798,12 @@ export class EpochCache { throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } - if (this.globalPubkey2index.get(pubkey)) { + if (this.finalizedPubkey2index.get(pubkey)) { return; // Repeated insert. Should not happen except 6110 activation } - this.globalPubkey2index.set(pubkey, index); - this.globalIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.finalizedPubkey2index.set(pubkey, index); + this.finalizedIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.delete(toMemoryEfficientHexStr(pubkey)); } @@ -910,17 +910,17 @@ type AttesterDuty = { export enum EpochCacheErrorCode { COMMITTEE_INDEX_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_INDEX_OUT_OF_RANGE", - COMMITTEE_EPOCH_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_EPOCH_OUT_OF_RANGE", +COMMITTEE_EPOCH_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_EPOCH_OUT_OF_RANGE", NO_SYNC_COMMITTEE = "EPOCH_CONTEXT_ERROR_NO_SYNC_COMMITTEE", PROPOSER_EPOCH_MISMATCH = "EPOCH_CONTEXT_ERROR_PROPOSER_EPOCH_MISMATCH", } type EpochCacheErrorType = | { - code: EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE; - index: number; - maxIndex: number; - } + code: EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE; + index: number; + maxIndex: number; +} | { code: EpochCacheErrorCode.COMMITTEE_EPOCH_OUT_OF_RANGE; requestedEpoch: Epoch; @@ -934,7 +934,7 @@ type EpochCacheErrorType = code: EpochCacheErrorCode.PROPOSER_EPOCH_MISMATCH; requestedEpoch: Epoch; currentEpoch: Epoch; - }; +}; export class EpochCacheError extends LodestarError {} @@ -945,8 +945,8 @@ export function createEmptyEpochCacheImmutableData( return { config: createBeaconConfig(chainConfig, state.genesisValidatorsRoot), // This is a test state, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }; } diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 7f26ba04669..00aedfd50c2 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -130,8 +130,8 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), - pubkey2index, - index2pubkey, + finalizedPubkey2index: pubkey2index, + finalizedIndex2pubkey: index2pubkey, }, createEmptyCarryoverData() ); @@ -232,8 +232,8 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean state, { config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), - pubkey2index, - index2pubkey, + finalizedPubkey2index: pubkey2index, + finalizedIndex2pubkey: index2pubkey, }, createEmptyCarryoverData() ); @@ -437,8 +437,8 @@ export function generateTestCachedBeaconStateOnlyValidators({ state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), - pubkey2index, - index2pubkey, + finalizedPubkey2index: pubkey2index, + finalizedIndex2pubkey: index2pubkey, }, createEmptyCarryoverData(), {skipSyncPubkeys: true} diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index 03da46235b5..ce1469aaf1b 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -11,8 +11,8 @@ describe("CachedBeaconState", () => { emptyState, { config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, createEmptyCarryoverData() ); diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index 60a9523c50e..5cf34c59a41 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -94,8 +94,8 @@ export function generateCachedState( { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a test state, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, createEmptyCarryoverData() ); @@ -111,8 +111,8 @@ export function createCachedBeaconStateTest( { config: createBeaconConfig(configCustom, state.genesisValidatorsRoot), // This is a test state, there's no need to have a global shared cache of keys - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, createEmptyCarryoverData(), opts From 7610db85ccc1e253ce9839a1940e5b79f0cc9fed Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 20 Sep 2023 16:41:46 +0800 Subject: [PATCH 045/155] Remove CarryoverData --- packages/beacon-node/src/chain/chain.ts | 4 ++-- packages/beacon-node/src/chain/genesis/genesis.ts | 4 ++-- .../beacon-node/test/utils/cachedBeaconState.ts | 4 ++-- packages/beacon-node/test/utils/state.ts | 12 ++++++------ packages/state-transition/src/cache/epochCache.ts | 14 ++------------ packages/state-transition/src/cache/stateCache.ts | 7 ++++--- packages/state-transition/src/index.ts | 3 +-- packages/state-transition/src/util/genesis.ts | 5 +++-- packages/state-transition/test/perf/util.ts | 8 ++++---- .../test/unit/upgradeState.test.ts | 14 +++++++------- .../test/unit/util/cachedBeaconState.test.ts | 4 ++-- packages/state-transition/test/utils/state.ts | 7 ++++--- 12 files changed, 39 insertions(+), 47 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 77f5fb3f510..87a36a0360a 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -11,6 +11,7 @@ import { isCachedBeaconState, Index2PubkeyCache, PubkeyIndexMap, + newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import { @@ -31,7 +32,6 @@ import {ProcessShutdownCallback} from "@lodestar/validator"; import {Logger, isErrorAborted, pruneSetToMax, sleep, toHex} from "@lodestar/utils"; import {ForkSeq, SLOTS_PER_EPOCH, MAX_BLOBS_PER_BLOCK} from "@lodestar/params"; -import {createEmptyCarryoverData} from "@lodestar/state-transition/src/cache/epochCache.js"; import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js"; import {IBeaconDb} from "../db/index.js"; import {Metrics} from "../metrics/index.js"; @@ -228,7 +228,7 @@ export class BeaconChain implements IBeaconChain { finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap(), ); // Persist single global instance of state caches diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 33ea18b3420..35a0f7d2a16 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -13,7 +13,7 @@ import { BeaconStateAllForks, createEmptyEpochCacheImmutableData, getActiveValidatorIndices, - createEmptyCarryoverData, + newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {Logger} from "@lodestar/utils"; import {IEth1Provider} from "../../eth1/index.js"; @@ -90,7 +90,7 @@ export class GenesisBuilder implements IGenesisBuilder { this.state = createCachedBeaconState( stateView, createEmptyEpochCacheImmutableData(config, stateView), - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap(), ); this.config = this.state.config; this.activatedValidatorCount = getActiveValidatorIndices(stateView, GENESIS_EPOCH).length; diff --git a/packages/beacon-node/test/utils/cachedBeaconState.ts b/packages/beacon-node/test/utils/cachedBeaconState.ts index 818ec1a11af..e04daf99948 100644 --- a/packages/beacon-node/test/utils/cachedBeaconState.ts +++ b/packages/beacon-node/test/utils/cachedBeaconState.ts @@ -3,7 +3,7 @@ import { BeaconStateCache, createCachedBeaconState, createEmptyEpochCacheImmutableData, - createEmptyCarryoverData, + newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; @@ -14,6 +14,6 @@ export function createCachedBeaconStateTest( return createCachedBeaconState( state, createEmptyEpochCacheImmutableData(chainConfig, state), - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap(), ); } diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index a887ced5931..80492d13eec 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -7,7 +7,7 @@ import { PubkeyIndexMap, CachedBeaconStateBellatrix, BeaconStateBellatrix, - createEmptyCarryoverData, + newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {allForks, altair, bellatrix, eip6110, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; @@ -113,7 +113,7 @@ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAl finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap() ); } @@ -131,7 +131,7 @@ export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoc finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap() ); } @@ -146,9 +146,9 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a performance test, there's no need to have a global shared cache of keys - finali: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap() ); } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 2dca0740450..2b22edf04b3 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -55,10 +55,6 @@ export type EpochCacheImmutableData = { finalizedIndex2pubkey: Index2PubkeyCache; }; -export type CarryoverData = { - unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; -}; - export type EpochCacheOpts = { skipSyncCommitteeCache?: boolean; skipSyncPubkeys?: boolean; @@ -270,7 +266,7 @@ export class EpochCache { static createFromState( state: BeaconStateAllForks, {config, finalizedPubkey2index, finalizedIndex2pubkey}: EpochCacheImmutableData, - {unfinalizedPubkey2index}: CarryoverData, + unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap, opts?: EpochCacheOpts ): EpochCache { // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches @@ -948,10 +944,4 @@ export function createEmptyEpochCacheImmutableData( finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }; -} - -export function createEmptyCarryoverData(): CarryoverData { - return { - unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), - }; -} +} \ No newline at end of file diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 5abc4beddfe..cad18746140 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -1,5 +1,5 @@ import {BeaconConfig} from "@lodestar/config"; -import {CarryoverData, EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js"; +import {EpochCache, EpochCacheImmutableData, EpochCacheOpts} from "./epochCache.js"; import { BeaconStateAllForks, BeaconStateExecutions, @@ -10,6 +10,7 @@ import { BeaconStateDeneb, BeaconStateEIP6110, } from "./types.js"; +import { UnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; export type BeaconStateCache = { config: BeaconConfig; @@ -138,12 +139,12 @@ export type CachedBeaconStateExecutions = CachedBeaconState( state: T, immutableData: EpochCacheImmutableData, - carryoverData: CarryoverData, + unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap, opts?: EpochCacheOpts ): T & BeaconStateCache { return getCachedBeaconState(state, { config: immutableData.config, - epochCtx: EpochCache.createFromState(state, immutableData, carryoverData, opts), + epochCtx: EpochCache.createFromState(state, immutableData, unfinalizedPubkey2index, opts), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 7c0cf4cf7bf..157e5fd473f 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -34,14 +34,13 @@ export { EpochCache, EpochCacheImmutableData, createEmptyEpochCacheImmutableData, - createEmptyCarryoverData, EpochCacheError, EpochCacheErrorCode, } from "./cache/epochCache.js"; export {EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures -export {PubkeyIndexMap, Index2PubkeyCache, UnfinalizedPubkeyIndexMap} from "./cache/pubkeyCache.js"; +export {PubkeyIndexMap, Index2PubkeyCache, UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap} from "./cache/pubkeyCache.js"; export { EffectiveBalanceIncrements, diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 7b8178802bf..4a34410ebc1 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -12,13 +12,14 @@ import {Bytes32, phase0, Root, ssz, TimeSeconds} from "@lodestar/types"; import {CachedBeaconStateAllForks, BeaconStateAllForks} from "../types.js"; import {createCachedBeaconState} from "../cache/stateCache.js"; -import {EpochCacheImmutableData, createEmptyCarryoverData} from "../cache/epochCache.js"; +import {EpochCacheImmutableData} from "../cache/epochCache.js"; import {processDeposit} from "../block/processDeposit.js"; import {computeEpochAtSlot} from "./epoch.js"; import {getActiveValidatorIndices} from "./validator.js"; import {getTemporaryBlockHeader} from "./blockRoot.js"; import {newFilledArray} from "./array.js"; import {getNextSyncCommittee} from "./syncCommittee.js"; +import { newUnfinalizedPubkeyIndexMap } from "../cache/pubkeyCache.js"; type DepositDataRootListType = ListCompositeType; type DepositDataRootViewDU = CompositeViewDU; @@ -233,7 +234,7 @@ export function initializeBeaconStateFromEth1( // - 3. interop state: Only supports starting from genesis at phase0 fork // So it's okay to skip syncing the sync committee cache here and expect it to be // populated latter when the altair fork happens for cases 2, 3. - const state = createCachedBeaconState(stateView, immutableData, createEmptyCarryoverData(), { + const state = createCachedBeaconState(stateView, immutableData, newUnfinalizedPubkeyIndexMap(), { skipSyncCommitteeCache: true, }); diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 00aedfd50c2..0a738a86f92 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -20,7 +20,7 @@ import { newFilledArray, createCachedBeaconState, computeCommitteeCount, - createEmptyCarryoverData, + newUnfinalizedPubkeyIndexMap, } from "../../src/index.js"; import { CachedBeaconStateAllForks, @@ -133,7 +133,7 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean finalizedPubkey2index: pubkey2index, finalizedIndex2pubkey: index2pubkey, }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap(), ); const currentEpoch = computeEpochAtSlot(state.slot - 1); @@ -235,7 +235,7 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean finalizedPubkey2index: pubkey2index, finalizedIndex2pubkey: index2pubkey, }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap(), ); } if (!altairCachedState23638) { @@ -440,7 +440,7 @@ export function generateTestCachedBeaconStateOnlyValidators({ finalizedPubkey2index: pubkey2index, finalizedIndex2pubkey: index2pubkey, }, - createEmptyCarryoverData(), + newUnfinalizedPubkeyIndexMap(), {skipSyncPubkeys: true} ); } diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 3cdcdd84603..4a2100371fd 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; -import {createCachedBeaconState, PubkeyIndexMap, createEmptyCarryoverData} from "@lodestar/state-transition"; +import {createCachedBeaconState, newUnfinalizedPubkeyIndexMap, PubkeyIndexMap} from "@lodestar/state-transition"; import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {config as chainConfig} from "@lodestar/config/default"; @@ -16,10 +16,10 @@ describe("upgradeState", () => { capellaState, { config: createBeaconConfig(config, capellaState.genesisValidatorsRoot), - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, - createEmptyCarryoverData(), + newUnfinalizedPubkeyIndexMap(), {skipSyncCommitteeCache: true} ); const newState = upgradeStateToDeneb(stateView); @@ -32,10 +32,10 @@ describe("upgradeState", () => { denebState, { config: createBeaconConfig(config, denebState.genesisValidatorsRoot), - pubkey2index: new PubkeyIndexMap(), - index2pubkey: [], + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], }, - createEmptyCarryoverData(), + newUnfinalizedPubkeyIndexMap(), {skipSyncCommitteeCache: true} ); const newState = upgradeStateToEIP6110(stateView); diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index ce1469aaf1b..54e61dc4532 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -1,7 +1,7 @@ import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {createCachedBeaconState, PubkeyIndexMap, createEmptyCarryoverData} from "../../../src/index.js"; +import {createCachedBeaconState, PubkeyIndexMap, newUnfinalizedPubkeyIndexMap} from "../../../src/index.js"; describe("CachedBeaconState", () => { it("Create empty CachedBeaconState", () => { @@ -14,7 +14,7 @@ describe("CachedBeaconState", () => { finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap() ); }); }); diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index 5cf34c59a41..7bc0366f2d5 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -19,9 +19,10 @@ import { BeaconStateAllForks, createCachedBeaconState, PubkeyIndexMap, + newUnfinalizedPubkeyIndexMap, } from "../../src/index.js"; import {BeaconStateCache} from "../../src/cache/stateCache.js"; -import {EpochCacheOpts, createEmptyCarryoverData} from "../../src/cache/epochCache.js"; +import {EpochCacheOpts} from "../../src/cache/epochCache.js"; /** * Copy of BeaconState, but all fields are marked optional to allow for swapping out variables as needed. @@ -97,7 +98,7 @@ export function generateCachedState( finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - createEmptyCarryoverData() + newUnfinalizedPubkeyIndexMap(), ); } @@ -114,7 +115,7 @@ export function createCachedBeaconStateTest( finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - createEmptyCarryoverData(), + newUnfinalizedPubkeyIndexMap(), opts ); } From 18995811b7cef4b67905f48c6be130364522902c Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 20 Sep 2023 16:50:21 +0800 Subject: [PATCH 046/155] Move isAfter6110 from var to method --- .../state-transition/src/cache/epochCache.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 2b22edf04b3..8099b8bccdf 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -201,7 +201,6 @@ export class EpochCache { // TODO: Helper stats epoch: Epoch; syncPeriod: SyncPeriod; - isAfterEIP6110: boolean; constructor(data: { config: BeaconConfig; @@ -228,7 +227,6 @@ export class EpochCache { nextSyncCommitteeIndexed: SyncCommitteeCache; epoch: Epoch; syncPeriod: SyncPeriod; - isAfterEIP6110: boolean; }) { this.config = data.config; this.finalizedPubkey2index = data.finalizedPubkey2index; @@ -254,7 +252,6 @@ export class EpochCache { this.nextSyncCommitteeIndexed = data.nextSyncCommitteeIndexed; this.epoch = data.epoch; this.syncPeriod = data.syncPeriod; - this.isAfterEIP6110 = data.isAfterEIP6110; } /** @@ -434,7 +431,6 @@ export class EpochCache { nextSyncCommitteeIndexed, epoch: currentEpoch, syncPeriod: computeSyncPeriodAtEpoch(currentEpoch), - isAfterEIP6110: currentEpoch >= (config.EIP6110_FORK_EPOCH ?? Infinity), }); } @@ -476,7 +472,6 @@ export class EpochCache { nextSyncCommitteeIndexed: this.nextSyncCommitteeIndexed, epoch: this.epoch, syncPeriod: this.syncPeriod, - isAfterEIP6110: this.isAfterEIP6110, }); } @@ -556,10 +551,9 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); - this.isAfterEIP6110 = this.epoch >= (this.config.EIP6110_FORK_EPOCH ?? Infinity); // To populate finalized cache and prune unfinalized cache with validators that just entered the activation queue - if (this.isAfterEIP6110) { + if (this.isAfterEIP6110()) { const expectedActivationEligibilityEpoch = prevEpoch + 1; const validators = state.validators; for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { @@ -763,7 +757,7 @@ export class EpochCache { } getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { - if (this.isAfterEIP6110) { + if (this.isAfterEIP6110()) { return this.finalizedPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } else { return this.finalizedPubkey2index.get(pubkey); @@ -776,7 +770,7 @@ export class EpochCache { * */ addPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { - if (this.isAfterEIP6110) { + if (this.isAfterEIP6110()) { this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } else { this.finalizedPubkey2index.set(pubkey, index); @@ -790,7 +784,7 @@ export class EpochCache { * */ addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { - if (!this.isAfterEIP6110) { + if (!this.isAfterEIP6110()) { throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } @@ -887,7 +881,11 @@ export class EpochCache { this.effectiveBalanceIncrements[index] = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); } -} + + isAfterEIP6110(): boolean { + return this.epoch >= (this.config.EIP6110_FORK_EPOCH ?? Infinity); + } + } function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { // TODO: Research what's the best number to minimize both memory cost and copy costs From fcfaf5aea8fd10655a63a545d1472486ff9e7175 Mon Sep 17 00:00:00 2001 From: naviechan Date: Sun, 24 Sep 2023 21:04:13 +0800 Subject: [PATCH 047/155] Fix cyclic import --- packages/beacon-node/test/spec/presets/index.test.ts | 1 - packages/light-client/src/spec/utils.ts | 5 ++--- packages/state-transition/src/index.ts | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/index.test.ts b/packages/beacon-node/test/spec/presets/index.test.ts index c45f859ec1e..0ff8eefcd97 100644 --- a/packages/beacon-node/test/spec/presets/index.test.ts +++ b/packages/beacon-node/test/spec/presets/index.test.ts @@ -30,7 +30,6 @@ import {transition} from "./transition.js"; // ], // ``` const skipOpts: SkipOpts = { - skippedForks: ["eip6110"], // TODO: capella // BeaconBlockBody proof in lightclient is the new addition in v1.3.0-rc.2-hotfix // Skip them for now to enable subsequently diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 7824046bc26..22fb1fb9b6c 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -1,4 +1,4 @@ -import {BitArray, byteArrayEquals} from "@chainsafe/ssz"; +import {BitArray, ByteVectorType, byteArrayEquals} from "@chainsafe/ssz"; import { FINALIZED_ROOT_DEPTH, @@ -12,7 +12,6 @@ import {altair, phase0, ssz, allForks, capella, deneb, Slot, eip6110} from "@lod import {ChainForkConfig} from "@lodestar/config"; import {computeEpochAtSlot} from "@lodestar/state-transition"; -import {Root} from "@lodestar/types/lib/sszTypes.js"; import {isValidMerkleBranch, computeSyncPeriodAtSlot} from "../utils/index.js"; import {LightClientStore} from "./store.js"; @@ -150,7 +149,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: allFor if (epoch < config.EIP6110_FORK_EPOCH) { if ( (header as eip6110.LightClientHeader).execution.depositReceiptsRoot && - (header as eip6110.LightClientHeader).execution.depositReceiptsRoot != Root.defaultValue() + (header as eip6110.LightClientHeader).execution.depositReceiptsRoot != new ByteVectorType(32).defaultValue() ) { return false; } diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 157e5fd473f..12c742c6956 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -10,6 +10,7 @@ export { CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, + CachedBeaconStateEIP6110, CachedBeaconStateAllForks, CachedBeaconStateExecutions, // Non-cached states @@ -18,6 +19,7 @@ export { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateEIP6110, BeaconStateAllForks, BeaconStateExecutions, } from "./types.js"; From b86780785c0dd9201d7f242293c8595819846f05 Mon Sep 17 00:00:00 2001 From: naviechan Date: Sun, 24 Sep 2023 21:19:10 +0800 Subject: [PATCH 048/155] Fix operations spec runner --- packages/beacon-node/test/spec/presets/operations.ts | 9 ++++++++- packages/state-transition/src/block/processOperations.ts | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/test/spec/presets/operations.ts b/packages/beacon-node/test/spec/presets/operations.ts index 0dc9739e31b..20e7ee3927a 100644 --- a/packages/beacon-node/test/spec/presets/operations.ts +++ b/packages/beacon-node/test/spec/presets/operations.ts @@ -3,12 +3,13 @@ import { CachedBeaconStateAllForks, CachedBeaconStateBellatrix, CachedBeaconStateCapella, + CachedBeaconStateEIP6110, DataAvailableStatus, ExecutionPayloadStatus, getBlockRootAtSlot, } from "@lodestar/state-transition"; import * as blockFns from "@lodestar/state-transition/block"; -import {ssz, phase0, altair, bellatrix, capella} from "@lodestar/types"; +import {ssz, phase0, altair, bellatrix, capella, eip6110} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; import {ForkName} from "@lodestar/params"; @@ -54,6 +55,11 @@ const operationFns: Record> = blockFns.processDeposit(fork, state, testCase.deposit); }, + deposit_receipt: (state, testCase: {deposit_receipt: eip6110.DepositReceipt}) => { + const fork = state.config.getForkSeq(state.slot); + blockFns.processDepositReceipt(fork, state as CachedBeaconStateEIP6110, testCase.deposit_receipt); + }, + proposer_slashing: (state, testCase: {proposer_slashing: phase0.ProposerSlashing}) => { const fork = state.config.getForkSeq(state.slot); blockFns.processProposerSlashing(fork, state, testCase.proposer_slashing); @@ -121,6 +127,7 @@ export const operations: TestRunnerFn = block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, + deposit_receipt: ssz.eip6110.DepositReceipt, proposer_slashing: ssz.phase0.ProposerSlashing, voluntary_exit: ssz.phase0.SignedVoluntaryExit, // Altair diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index dbffad312b7..b2217b433a7 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -19,6 +19,7 @@ export { processDeposit, processVoluntaryExit, processBlsToExecutionChange, + processDepositReceipt, }; export function processOperations( From 7587f056ecf52f8956af53ad2d5f945a5cf3392b Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 25 Sep 2023 14:53:38 +0800 Subject: [PATCH 049/155] Fix for spec test --- packages/beacon-node/test/spec/presets/ssz_static.ts | 1 + .../state-transition/src/signatureSets/attesterSlashings.ts | 3 +-- packages/types/src/eip6110/sszTypes.ts | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/ssz_static.ts b/packages/beacon-node/test/spec/presets/ssz_static.ts index 014e7d6293e..b7787f3a8c0 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.ts @@ -40,6 +40,7 @@ export const sszStatic = // will help us get the right type for lightclient objects ((ssz.allForksLightClient[fork as ForkLightClient] || {}) as Types)[typeName] || (ssz[fork] as Types)[typeName] || + (ssz.deneb as Types)[typeName] || (ssz.capella as Types)[typeName] || (ssz.bellatrix as Types)[typeName] || (ssz.altair as Types)[typeName] || diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 071b084aef0..0ec704e987a 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -27,13 +27,12 @@ export function getIndexedAttestationBigintSignatureSet( state: CachedBeaconStateAllForks, indexedAttestation: phase0.IndexedAttestationBigint ): ISignatureSet { - const index2pubkey = state.epochCtx.getPubkey; const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); const domain = state.config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); return { type: SignatureSetType.aggregate, - pubkeys: indexedAttestation.attestingIndices.map((i) => index2pubkey(i)), + pubkeys: indexedAttestation.attestingIndices.map((i) => state.epochCtx.getPubkey(i)), signingRoot: computeSigningRoot(ssz.phase0.AttestationDataBigint, indexedAttestation.data, domain), signature: indexedAttestation.signature, }; diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index c58f4883926..120f437bc39 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -23,7 +23,6 @@ export const DepositReceipt = new ContainerType( amount: UintNum64, signature: BLSSignature, index: DepositIndex, - validatorIndex: ValidatorIndex, }, {typeName: "DepositReceipt", jsonCase: "eth2"} ); From f1f50190054e9a4b879835ddc16dc48d64748aa6 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 25 Sep 2023 18:42:22 +0800 Subject: [PATCH 050/155] Fix spec test --- packages/params/src/presets/minimal.ts | 2 +- packages/state-transition/src/cache/epochCache.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 5ca74b0554d..0b039cfae6e 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -124,5 +124,5 @@ export const minimalPreset: BeaconPreset = { MAX_BLOBS_PER_BLOCK: 6, // EIP6110 - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, }; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 8099b8bccdf..f6fbddc8a46 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -758,7 +758,7 @@ export class EpochCache { getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { if (this.isAfterEIP6110()) { - return this.finalizedPubkey2index.get(pubkey) || this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + return this.finalizedPubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } else { return this.finalizedPubkey2index.get(pubkey); } From 57b526d57c0eb88a9408b89e757ae8b5bbe0e5d7 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 25 Sep 2023 18:51:22 +0800 Subject: [PATCH 051/155] state.depositReceiptsStartIndex to BigInt --- packages/params/src/index.ts | 2 +- .../src/block/processDepositReceipt.ts | 2 +- packages/state-transition/src/util/deposit.ts | 24 +++++++++++-------- packages/types/src/eip6110/sszTypes.ts | 4 ++-- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index ed34da25563..cf2768294e2 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -249,4 +249,4 @@ export const BLOB_TX_TYPE = 0x03; export const VERSIONED_HASH_VERSION_KZG = 0x01; // EIP-6110 Misc -export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = Infinity; +export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2n ** 64n - 1n; diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositReceipt.ts index e425ae0a5cf..967ecaf90b0 100644 --- a/packages/state-transition/src/block/processDepositReceipt.ts +++ b/packages/state-transition/src/block/processDepositReceipt.ts @@ -10,7 +10,7 @@ export function processDepositReceipt( depositReceipt: eip6110.DepositReceipt ): void { if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { - state.depositReceiptsStartIndex = depositReceipt.index; + state.depositReceiptsStartIndex = BigInt(depositReceipt.index); } applyDeposit( diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 747b1cd9dfc..5ab549f5a84 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -1,16 +1,20 @@ -import {MAX_DEPOSITS} from "@lodestar/params"; +import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; import {UintNum64} from "@lodestar/types"; -import {BeaconStateAllForks} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateEIP6110} from "../types.js"; -export function getEth1DepositCount(state: BeaconStateAllForks): UintNum64 { - const eth1DataIndexLimit = - "depositReceiptsStartIndex" in state - ? Math.min(state.eth1Data.depositCount, state.depositReceiptsStartIndex) - : Math.min(state.eth1Data.depositCount, 0); +export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 { - if (state.eth1DepositIndex < eth1DataIndexLimit) { - return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); + if (state.config.getForkSeq(state.slot) >= ForkSeq.eip6110) { + const eip6110State = state as CachedBeaconStateEIP6110; + const eth1DataIndexLimit = state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex ? state.eth1Data.depositCount : eip6110State.depositReceiptsStartIndex; + + if (state.eth1DepositIndex < eth1DataIndexLimit) { + return Math.min(MAX_DEPOSITS, Number(eth1DataIndexLimit) - state.eth1DepositIndex); // eth1DataIndexLimit can be safely casted as number + } else { + return 0; + } + } else { + return Math.min(MAX_DEPOSITS, state.eth1Data.depositCount - state.eth1DepositIndex); } - return 0; } diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index 120f437bc39..4c6eb8481f0 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -13,7 +13,7 @@ import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, ValidatorIndex, DepositIndex} = +const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, ValidatorIndex, DepositIndex, UintBn64} = primitiveSsz; export const DepositReceipt = new ContainerType( @@ -160,7 +160,7 @@ export const BeaconState = new ContainerType( nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, // Deep history valid from Capella onwards historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, - depositReceiptsStartIndex: UintNum64, // New in EIP6110 + depositReceiptsStartIndex: UintBn64, // New in EIP6110 }, {typeName: "BeaconState", jsonCase: "eth2"} ); From 64943096066612159b549c23b6847fa1737b8575 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 25 Sep 2023 18:51:50 +0800 Subject: [PATCH 052/155] getDeposit requires cached state --- packages/beacon-node/src/eth1/eth1DepositDataTracker.ts | 6 +++--- packages/beacon-node/src/eth1/utils/deposits.ts | 4 ++-- packages/beacon-node/test/unit/eth1/utils/deposits.test.ts | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index a7fc91fafb0..d9940d334fc 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -1,6 +1,6 @@ import {phase0, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {BeaconStateAllForks, becomesNewEth1Data} from "@lodestar/state-transition"; +import {BeaconStateAllForks, CachedBeaconStateAllForks, becomesNewEth1Data} from "@lodestar/state-transition"; import {ErrorAborted, TimeoutError, fromHex, Logger, isErrorAborted, sleep} from "@lodestar/utils"; import {IBeaconDb} from "../db/index.js"; @@ -112,7 +112,7 @@ export class Eth1DepositDataTracker { /** * Return eth1Data and deposits ready for block production for a given state */ - async getEth1DataAndDeposits(state: BeaconStateAllForks): Promise { + async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state)); const deposits = await this.getDeposits(state, eth1Data); return {eth1Data, deposits}; @@ -141,7 +141,7 @@ export class Eth1DepositDataTracker { * Returns deposits to be included for a given state and eth1Data vote. * Requires internal caches to be updated regularly to return good results */ - private async getDeposits(state: BeaconStateAllForks, eth1DataVote: phase0.Eth1Data): Promise { + private async getDeposits(state: CachedBeaconStateAllForks, eth1DataVote: phase0.Eth1Data): Promise { // No new deposits have to be included, continue if (eth1DataVote.depositCount === state.eth1DepositIndex) { return []; diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index fb00db4b50a..cdc36580e13 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -1,6 +1,6 @@ import {toGindex, Tree} from "@chainsafe/persistent-merkle-tree"; import {toHexString} from "@chainsafe/ssz"; -import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {FilterOptions} from "@lodestar/db"; import {getEth1DepositCount} from "@lodestar/state-transition"; @@ -11,7 +11,7 @@ export type DepositGetter = (indexRange: FilterOptions, eth1Data: pha export async function getDeposits( // eth1_deposit_index represents the next deposit index to be added - state: BeaconStateAllForks, + state: CachedBeaconStateAllForks, eth1Data: phase0.Eth1Data, depositsGetter: DepositGetter ): Promise { diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index f4dad8dcf26..aecee59eef2 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -9,6 +9,8 @@ import {generateState} from "../../../utils/state.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src/eth1/utils/deposits.js"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; +import { createCachedBeaconStateTest } from "../../../utils/cachedBeaconState.js"; +import { createChainForkConfig } from "@lodestar/config"; describe("eth1 / util / deposits", function () { describe("getDeposits", () => { @@ -106,12 +108,13 @@ describe("eth1 / util / deposits", function () { const state = post6110 ? generateState({slot: post6110Slot, eth1DepositIndex}) : generateState({eth1DepositIndex}); + const cachedState = createCachedBeaconStateTest(state, createChainForkConfig({})); const eth1Data = generateEth1Data(depositCount); const deposits = depositIndexes.map((index) => generateDepositEvent(index)); const depositsGetter: DepositGetter = async (indexRange) => filterBy(deposits, indexRange, (deposit) => deposit.index); - const resultPromise = getDeposits(state, eth1Data, depositsGetter); + const resultPromise = getDeposits(cachedState, eth1Data, depositsGetter); if (expectedReturnedIndexes) { const result = await resultPromise; From a8638e285c768e7c7aa547f9948a0ad239a6f31c Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 25 Sep 2023 19:31:45 +0800 Subject: [PATCH 053/155] default depositReceiptsStartIndex value in genesis --- packages/state-transition/src/util/genesis.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 4a34410ebc1..83867ac93c9 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -7,6 +7,7 @@ import { GENESIS_EPOCH, GENESIS_SLOT, MAX_EFFECTIVE_BALANCE, + UNSET_DEPOSIT_RECEIPTS_START_INDEX, } from "@lodestar/params"; import {Bytes32, phase0, Root, ssz, TimeSeconds} from "@lodestar/types"; @@ -295,6 +296,7 @@ export function initializeBeaconStateFromEth1( stateEIP6110.latestExecutionPayloadHeader = (executionPayloadHeader as CompositeViewDU) ?? ssz.eip6110.ExecutionPayloadHeader.defaultViewDU(); + stateEIP6110.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; } state.commit(); From 8aafcb9c8cb0e5bdf360a9601e491e39ae2a5044 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 25 Sep 2023 19:42:34 +0800 Subject: [PATCH 054/155] Fix pubkeyCache bug --- packages/state-transition/src/cache/epochCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index f6fbddc8a46..a03b5987f74 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -771,7 +771,7 @@ export class EpochCache { */ addPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { if (this.isAfterEIP6110()) { - this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); + this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } else { this.finalizedPubkey2index.set(pubkey, index); this.finalizedIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); From 1730ebe8edfa82cd92ae3ed6c33c9ebcdd65c7c6 Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 26 Sep 2023 16:06:43 +0800 Subject: [PATCH 055/155] newUnfinalizedPubkeyIndexMap in createCachedBeaconState --- packages/beacon-node/src/chain/chain.ts | 3 +-- packages/beacon-node/src/chain/genesis/genesis.ts | 3 +-- packages/beacon-node/test/utils/cachedBeaconState.ts | 3 +-- packages/beacon-node/test/utils/state.ts | 9 +++------ packages/state-transition/src/cache/stateCache.ts | 5 ++--- packages/state-transition/src/util/genesis.ts | 2 +- packages/state-transition/test/perf/util.ts | 7 ++----- packages/state-transition/test/unit/upgradeState.test.ts | 2 -- .../test/unit/util/cachedBeaconState.test.ts | 3 +-- packages/state-transition/test/utils/state.ts | 4 +--- 10 files changed, 13 insertions(+), 28 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 87a36a0360a..80a7eed5d8f 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -227,8 +227,7 @@ export class BeaconChain implements IBeaconChain { config, finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], - }, - newUnfinalizedPubkeyIndexMap(), + } ); // Persist single global instance of state caches diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 35a0f7d2a16..2bd0e32ff78 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -89,8 +89,7 @@ export class GenesisBuilder implements IGenesisBuilder { // TODO - PENDING: Ensure EpochCacheImmutableData is created only once this.state = createCachedBeaconState( stateView, - createEmptyEpochCacheImmutableData(config, stateView), - newUnfinalizedPubkeyIndexMap(), + createEmptyEpochCacheImmutableData(config, stateView) ); this.config = this.state.config; this.activatedValidatorCount = getActiveValidatorIndices(stateView, GENESIS_EPOCH).length; diff --git a/packages/beacon-node/test/utils/cachedBeaconState.ts b/packages/beacon-node/test/utils/cachedBeaconState.ts index e04daf99948..00b2c55aad3 100644 --- a/packages/beacon-node/test/utils/cachedBeaconState.ts +++ b/packages/beacon-node/test/utils/cachedBeaconState.ts @@ -13,7 +13,6 @@ export function createCachedBeaconStateTest( ): T & BeaconStateCache { return createCachedBeaconState( state, - createEmptyEpochCacheImmutableData(chainConfig, state), - newUnfinalizedPubkeyIndexMap(), + createEmptyEpochCacheImmutableData(chainConfig, state) ); } diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 80492d13eec..f8e47d33ce4 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -112,8 +112,7 @@ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAl // This is a performance test, there's no need to have a global shared cache of keys finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], - }, - newUnfinalizedPubkeyIndexMap() + } ); } @@ -130,8 +129,7 @@ export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoc // This is a performance test, there's no need to have a global shared cache of keys finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], - }, - newUnfinalizedPubkeyIndexMap() + } ); } @@ -148,7 +146,6 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac // This is a performance test, there's no need to have a global shared cache of keys finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], - }, - newUnfinalizedPubkeyIndexMap() + } ); } diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index cad18746140..7fcd1b189ac 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -10,7 +10,7 @@ import { BeaconStateDeneb, BeaconStateEIP6110, } from "./types.js"; -import { UnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; +import { UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; export type BeaconStateCache = { config: BeaconConfig; @@ -139,12 +139,11 @@ export type CachedBeaconStateExecutions = CachedBeaconState( state: T, immutableData: EpochCacheImmutableData, - unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap, opts?: EpochCacheOpts ): T & BeaconStateCache { return getCachedBeaconState(state, { config: immutableData.config, - epochCtx: EpochCache.createFromState(state, immutableData, unfinalizedPubkey2index, opts), + epochCtx: EpochCache.createFromState(state, immutableData, newUnfinalizedPubkeyIndexMap(), opts), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 83867ac93c9..0bf6bb1470a 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -235,7 +235,7 @@ export function initializeBeaconStateFromEth1( // - 3. interop state: Only supports starting from genesis at phase0 fork // So it's okay to skip syncing the sync committee cache here and expect it to be // populated latter when the altair fork happens for cases 2, 3. - const state = createCachedBeaconState(stateView, immutableData, newUnfinalizedPubkeyIndexMap(), { + const state = createCachedBeaconState(stateView, immutableData, { skipSyncCommitteeCache: true, }); diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 0a738a86f92..2e9caba2f91 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -132,8 +132,7 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean config: createBeaconConfig(config, state.genesisValidatorsRoot), finalizedPubkey2index: pubkey2index, finalizedIndex2pubkey: index2pubkey, - }, - newUnfinalizedPubkeyIndexMap(), + } ); const currentEpoch = computeEpochAtSlot(state.slot - 1); @@ -234,8 +233,7 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), finalizedPubkey2index: pubkey2index, finalizedIndex2pubkey: index2pubkey, - }, - newUnfinalizedPubkeyIndexMap(), + } ); } if (!altairCachedState23638) { @@ -440,7 +438,6 @@ export function generateTestCachedBeaconStateOnlyValidators({ finalizedPubkey2index: pubkey2index, finalizedIndex2pubkey: index2pubkey, }, - newUnfinalizedPubkeyIndexMap(), {skipSyncPubkeys: true} ); } diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 4a2100371fd..15a1e1306bf 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -19,7 +19,6 @@ describe("upgradeState", () => { finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - newUnfinalizedPubkeyIndexMap(), {skipSyncCommitteeCache: true} ); const newState = upgradeStateToDeneb(stateView); @@ -35,7 +34,6 @@ describe("upgradeState", () => { finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - newUnfinalizedPubkeyIndexMap(), {skipSyncCommitteeCache: true} ); const newState = upgradeStateToEIP6110(stateView); diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index 54e61dc4532..f466d71af8f 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -13,8 +13,7 @@ describe("CachedBeaconState", () => { config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], - }, - newUnfinalizedPubkeyIndexMap() + } ); }); }); diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index 7bc0366f2d5..ffba541f162 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -97,8 +97,7 @@ export function generateCachedState( // This is a test state, there's no need to have a global shared cache of keys finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], - }, - newUnfinalizedPubkeyIndexMap(), + } ); } @@ -115,7 +114,6 @@ export function createCachedBeaconStateTest( finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }, - newUnfinalizedPubkeyIndexMap(), opts ); } From 6af01cbd2331656ba99f30d623614c96bb6b8cd6 Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 26 Sep 2023 16:26:52 +0800 Subject: [PATCH 056/155] Lint --- packages/beacon-node/src/chain/chain.ts | 14 ++---- .../beacon-node/src/chain/genesis/genesis.ts | 6 +-- .../src/eth1/eth1DepositDataTracker.ts | 5 +- .../test/unit/eth1/utils/deposits.test.ts | 4 +- .../test/utils/cachedBeaconState.ts | 6 +-- packages/beacon-node/test/utils/state.ts | 46 ++++++++----------- .../test/utils/validationData/attestation.ts | 4 +- packages/light-client/src/spec/utils.ts | 7 +-- .../unit/isValidLightClientHeader.test.ts | 7 ++- .../src/block/processDeposit.ts | 12 ++--- .../src/block/processDepositReceipt.ts | 6 +-- .../state-transition/src/cache/epochCache.ts | 25 +++++----- .../state-transition/src/cache/stateCache.ts | 2 +- packages/state-transition/src/index.ts | 7 ++- packages/state-transition/src/util/deposit.ts | 7 +-- packages/state-transition/src/util/genesis.ts | 1 - packages/state-transition/test/perf/util.ts | 27 ++++------- .../test/unit/upgradeState.test.ts | 2 +- .../test/unit/util/cachedBeaconState.test.ts | 15 +++--- packages/state-transition/test/utils/state.ts | 16 +++---- packages/types/src/eip6110/sszTypes.ts | 43 +++++++++-------- 21 files changed, 114 insertions(+), 148 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 80a7eed5d8f..7dd1a0f424c 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -11,7 +11,6 @@ import { isCachedBeaconState, Index2PubkeyCache, PubkeyIndexMap, - newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import { @@ -221,14 +220,11 @@ export class BeaconChain implements IBeaconChain { const cachedState = isCachedBeaconState(anchorState) && opts.skipCreateStateCacheIfAvailable ? anchorState - : createCachedBeaconState( - anchorState, - { - config, - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], - } - ); + : createCachedBeaconState(anchorState, { + config, + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], + }); // Persist single global instance of state caches this.pubkey2index = cachedState.epochCtx.finalizedPubkey2index; // TODO: Double check if these two are correct diff --git a/packages/beacon-node/src/chain/genesis/genesis.ts b/packages/beacon-node/src/chain/genesis/genesis.ts index 2bd0e32ff78..979476c6953 100644 --- a/packages/beacon-node/src/chain/genesis/genesis.ts +++ b/packages/beacon-node/src/chain/genesis/genesis.ts @@ -13,7 +13,6 @@ import { BeaconStateAllForks, createEmptyEpochCacheImmutableData, getActiveValidatorIndices, - newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {Logger} from "@lodestar/utils"; import {IEth1Provider} from "../../eth1/index.js"; @@ -87,10 +86,7 @@ export class GenesisBuilder implements IGenesisBuilder { } // TODO - PENDING: Ensure EpochCacheImmutableData is created only once - this.state = createCachedBeaconState( - stateView, - createEmptyEpochCacheImmutableData(config, stateView) - ); + this.state = createCachedBeaconState(stateView, createEmptyEpochCacheImmutableData(config, stateView)); this.config = this.state.config; this.activatedValidatorCount = getActiveValidatorIndices(stateView, GENESIS_EPOCH).length; } diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index d9940d334fc..5fcd7ebb592 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -141,7 +141,10 @@ export class Eth1DepositDataTracker { * Returns deposits to be included for a given state and eth1Data vote. * Requires internal caches to be updated regularly to return good results */ - private async getDeposits(state: CachedBeaconStateAllForks, eth1DataVote: phase0.Eth1Data): Promise { + private async getDeposits( + state: CachedBeaconStateAllForks, + eth1DataVote: phase0.Eth1Data + ): Promise { // No new deposits have to be included, continue if (eth1DataVote.depositCount === state.eth1DepositIndex) { return []; diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index aecee59eef2..87732264191 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -3,14 +3,14 @@ import {phase0, ssz} from "@lodestar/types"; import {MAX_DEPOSITS, SLOTS_PER_EPOCH} from "@lodestar/params"; import {verifyMerkleBranch} from "@lodestar/utils"; import {minimalChainConfig} from "@lodestar/config/lib/presets.js"; +import {createChainForkConfig} from "@lodestar/config"; import {filterBy} from "../../../utils/db.js"; import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; import {generateState} from "../../../utils/state.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src/eth1/utils/deposits.js"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; -import { createCachedBeaconStateTest } from "../../../utils/cachedBeaconState.js"; -import { createChainForkConfig } from "@lodestar/config"; +import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; describe("eth1 / util / deposits", function () { describe("getDeposits", () => { diff --git a/packages/beacon-node/test/utils/cachedBeaconState.ts b/packages/beacon-node/test/utils/cachedBeaconState.ts index 00b2c55aad3..3efb16b6250 100644 --- a/packages/beacon-node/test/utils/cachedBeaconState.ts +++ b/packages/beacon-node/test/utils/cachedBeaconState.ts @@ -3,7 +3,6 @@ import { BeaconStateCache, createCachedBeaconState, createEmptyEpochCacheImmutableData, - newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {ChainForkConfig} from "@lodestar/config"; @@ -11,8 +10,5 @@ export function createCachedBeaconStateTest( state: T, chainConfig: ChainForkConfig ): T & BeaconStateCache { - return createCachedBeaconState( - state, - createEmptyEpochCacheImmutableData(chainConfig, state) - ); + return createCachedBeaconState(state, createEmptyEpochCacheImmutableData(chainConfig, state)); } diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index f8e47d33ce4..e196a5fba7b 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -7,7 +7,6 @@ import { PubkeyIndexMap, CachedBeaconStateBellatrix, BeaconStateBellatrix, - newUnfinalizedPubkeyIndexMap, } from "@lodestar/state-transition"; import {allForks, altair, bellatrix, eip6110, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; @@ -105,15 +104,12 @@ export function generateState( export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAllForks { const config = getConfig(ForkName.phase0); const state = generateState(opts, config); - return createCachedBeaconState( - state, - { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a performance test, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], - } - ); + return createCachedBeaconState(state, { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a performance test, there's no need to have a global shared cache of keys + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], + }); } /** @@ -122,15 +118,12 @@ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAl export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoch = 0): CachedBeaconStateAllForks { const config = getConfig(ForkName.altair, altairForkEpoch); const state = generateState(opts, config); - return createCachedBeaconState( - state, - { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a performance test, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], - } - ); + return createCachedBeaconState(state, { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a performance test, there's no need to have a global shared cache of keys + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], + }); } /** @@ -139,13 +132,10 @@ export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoc export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeaconStateBellatrix { const config = getConfig(ForkName.bellatrix); const state = generateState(opts, config); - return createCachedBeaconState( - state as BeaconStateBellatrix, - { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a performance test, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], - } - ); + return createCachedBeaconState(state as BeaconStateBellatrix, { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a performance test, there's no need to have a global shared cache of keys + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], + }); } diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index 6f768227e5c..1ba5e99337b 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -9,7 +9,7 @@ import { generateTestCachedBeaconStateOnlyValidators, getSecretKeyFromIndexCached, // eslint-disable-next-line import/no-relative-packages -} from "../../../../state-transition/test/perf/util.js"; +} from "@lodestar/state-transition"; import {IBeaconChain} from "../../../src/chain/index.js"; import {IStateRegenerator} from "../../../src/chain/regen/index.js"; import {ZERO_HASH, ZERO_HASH_HEX} from "../../../src/constants/index.js"; @@ -131,7 +131,7 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { ? new BlsSingleThreadVerifier({metrics: null}) : new BlsMultiThreadWorkerPool({}, {logger: testLogger(), metrics: null}), waitForBlock: () => Promise.resolve(false), - index2pubkey: state.epochCtx.index2pubkey, + index2pubkey: state.epochCtx.finalizedIndex2pubkey, opts: defaultChainOptions, } as Partial as IBeaconChain; diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 22fb1fb9b6c..3bd208ac2dc 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -1,4 +1,4 @@ -import {BitArray, ByteVectorType, byteArrayEquals} from "@chainsafe/ssz"; +import {BitArray, byteArrayEquals} from "@chainsafe/ssz"; import { FINALIZED_ROOT_DEPTH, @@ -147,10 +147,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: allFor } if (epoch < config.EIP6110_FORK_EPOCH) { - if ( - (header as eip6110.LightClientHeader).execution.depositReceiptsRoot && - (header as eip6110.LightClientHeader).execution.depositReceiptsRoot != new ByteVectorType(32).defaultValue() - ) { + if ((header as eip6110.LightClientHeader).execution.depositReceiptsRoot !== undefined) { return false; } } diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index 67fe9bcba3f..fa30bf58d78 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -89,7 +89,12 @@ describe("isValidLightClientHeader", function () { const capellaUpgradedEIP6110Header = { beacon: capellaLCHeader.beacon, - execution: {...capellaLCHeader.execution, blobGasUsed: 0, excessBlobGas: 0, depositReceiptsRoot: new ByteVectorType(32)}, + execution: { + ...capellaLCHeader.execution, + blobGasUsed: 0, + excessBlobGas: 0, + depositReceiptsRoot: new ByteVectorType(32), + }, executionBranch: capellaLCHeader.executionBranch, }; diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 389bea86278..fa74c638d47 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -1,6 +1,6 @@ import bls from "@chainsafe/bls"; import {CoordType} from "@chainsafe/bls/types"; -import {BLSPubkey, BLSSignature, Bytes32, UintNum64, phase0, ssz} from "@lodestar/types"; +import {BLSPubkey, Bytes32, UintNum64, phase0, ssz} from "@lodestar/types"; import {verifyMerkleBranch} from "@lodestar/utils"; import { @@ -12,11 +12,11 @@ import { MAX_EFFECTIVE_BALANCE, } from "@lodestar/params"; +import {DepositData} from "@lodestar/types/lib/phase0/types.js"; +import {DepositReceipt} from "@lodestar/types/lib/eip6110/types.js"; import {ZERO_HASH} from "../constants/index.js"; import {computeDomain, computeSigningRoot, increaseBalance} from "../util/index.js"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; -import { DepositData } from "@lodestar/types/lib/phase0/types.js"; -import { DepositReceipt } from "@lodestar/types/lib/eip6110/types.js"; /** * Process a Deposit operation. Potentially adds a new validator to the registry. Mutates the validators and balances @@ -41,11 +41,7 @@ export function processDeposit(fork: ForkSeq, state: CachedBeaconStateAllForks, // deposits must be processed in order state.eth1DepositIndex += 1; - applyDeposit( - fork, - state, - deposit.data - ); + applyDeposit(fork, state, deposit.data); } /** diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositReceipt.ts index 967ecaf90b0..c9e13b7de8e 100644 --- a/packages/state-transition/src/block/processDepositReceipt.ts +++ b/packages/state-transition/src/block/processDepositReceipt.ts @@ -13,9 +13,5 @@ export function processDepositReceipt( state.depositReceiptsStartIndex = BigInt(depositReceipt.index); } - applyDeposit( - fork, - state, - depositReceipt - ); + applyDeposit(fork, state, depositReceipt); } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index a03b5987f74..8a4b7bab2b6 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -35,7 +35,6 @@ import { UnfinalizedPubkeyIndexMap, syncPubkeys, toMemoryEfficientHexStr, - newUnfinalizedPubkeyIndexMap, PubkeyHex, } from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; @@ -758,7 +757,9 @@ export class EpochCache { getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { if (this.isAfterEIP6110()) { - return this.finalizedPubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); + return ( + this.finalizedPubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)) + ); } else { return this.finalizedPubkey2index.get(pubkey); } @@ -774,7 +775,7 @@ export class EpochCache { this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } else { this.finalizedPubkey2index.set(pubkey, index); - this.finalizedIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.finalizedIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); } } @@ -788,7 +789,7 @@ export class EpochCache { throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } - if (this.finalizedPubkey2index.get(pubkey)) { + if (this.finalizedPubkey2index.get(pubkey) !== undefined) { return; // Repeated insert. Should not happen except 6110 activation } @@ -885,7 +886,7 @@ export class EpochCache { isAfterEIP6110(): boolean { return this.epoch >= (this.config.EIP6110_FORK_EPOCH ?? Infinity); } - } +} function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { // TODO: Research what's the best number to minimize both memory cost and copy costs @@ -904,17 +905,17 @@ type AttesterDuty = { export enum EpochCacheErrorCode { COMMITTEE_INDEX_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_INDEX_OUT_OF_RANGE", -COMMITTEE_EPOCH_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_EPOCH_OUT_OF_RANGE", + COMMITTEE_EPOCH_OUT_OF_RANGE = "EPOCH_CONTEXT_ERROR_COMMITTEE_EPOCH_OUT_OF_RANGE", NO_SYNC_COMMITTEE = "EPOCH_CONTEXT_ERROR_NO_SYNC_COMMITTEE", PROPOSER_EPOCH_MISMATCH = "EPOCH_CONTEXT_ERROR_PROPOSER_EPOCH_MISMATCH", } type EpochCacheErrorType = | { - code: EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE; - index: number; - maxIndex: number; -} + code: EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE; + index: number; + maxIndex: number; + } | { code: EpochCacheErrorCode.COMMITTEE_EPOCH_OUT_OF_RANGE; requestedEpoch: Epoch; @@ -928,7 +929,7 @@ type EpochCacheErrorType = code: EpochCacheErrorCode.PROPOSER_EPOCH_MISMATCH; requestedEpoch: Epoch; currentEpoch: Epoch; -}; + }; export class EpochCacheError extends LodestarError {} @@ -942,4 +943,4 @@ export function createEmptyEpochCacheImmutableData( finalizedPubkey2index: new PubkeyIndexMap(), finalizedIndex2pubkey: [], }; -} \ No newline at end of file +} diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 7fcd1b189ac..3aee1291b45 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -10,7 +10,7 @@ import { BeaconStateDeneb, BeaconStateEIP6110, } from "./types.js"; -import { UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; +import {newUnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; export type BeaconStateCache = { config: BeaconConfig; diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 12c742c6956..ea468f1a9b2 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -42,7 +42,12 @@ export { export {EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures -export {PubkeyIndexMap, Index2PubkeyCache, UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap} from "./cache/pubkeyCache.js"; +export { + PubkeyIndexMap, + Index2PubkeyCache, + UnfinalizedPubkeyIndexMap, + newUnfinalizedPubkeyIndexMap, +} from "./cache/pubkeyCache.js"; export { EffectiveBalanceIncrements, diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 5ab549f5a84..c7e636517f7 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -3,10 +3,12 @@ import {UintNum64} from "@lodestar/types"; import {CachedBeaconStateAllForks, CachedBeaconStateEIP6110} from "../types.js"; export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 { - if (state.config.getForkSeq(state.slot) >= ForkSeq.eip6110) { const eip6110State = state as CachedBeaconStateEIP6110; - const eth1DataIndexLimit = state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex ? state.eth1Data.depositCount : eip6110State.depositReceiptsStartIndex; + const eth1DataIndexLimit = + state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex + ? state.eth1Data.depositCount + : eip6110State.depositReceiptsStartIndex; if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, Number(eth1DataIndexLimit) - state.eth1DepositIndex); // eth1DataIndexLimit can be safely casted as number @@ -16,5 +18,4 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 } else { return Math.min(MAX_DEPOSITS, state.eth1Data.depositCount - state.eth1DepositIndex); } - } diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 0bf6bb1470a..2d51171ae9b 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -20,7 +20,6 @@ import {getActiveValidatorIndices} from "./validator.js"; import {getTemporaryBlockHeader} from "./blockRoot.js"; import {newFilledArray} from "./array.js"; import {getNextSyncCommittee} from "./syncCommittee.js"; -import { newUnfinalizedPubkeyIndexMap } from "../cache/pubkeyCache.js"; type DepositDataRootListType = ListCompositeType; type DepositDataRootViewDU = CompositeViewDU; diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 2e9caba2f91..1ce8528ecd1 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -20,7 +20,6 @@ import { newFilledArray, createCachedBeaconState, computeCommitteeCount, - newUnfinalizedPubkeyIndexMap, } from "../../src/index.js"; import { CachedBeaconStateAllForks, @@ -126,14 +125,11 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean if (!phase0CachedState23637) { const state = phase0State.clone(); state.slot -= 1; - phase0CachedState23637 = createCachedBeaconState( - state, - { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - finalizedPubkey2index: pubkey2index, - finalizedIndex2pubkey: index2pubkey, - } - ); + phase0CachedState23637 = createCachedBeaconState(state, { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + finalizedPubkey2index: pubkey2index, + finalizedIndex2pubkey: index2pubkey, + }); const currentEpoch = computeEpochAtSlot(state.slot - 1); const previousEpoch = currentEpoch - 1; @@ -227,14 +223,11 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean if (!altairCachedState23637) { const state = origState.clone(); state.slot -= 1; - altairCachedState23637 = createCachedBeaconState( - state, - { - config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), - finalizedPubkey2index: pubkey2index, - finalizedIndex2pubkey: index2pubkey, - } - ); + altairCachedState23637 = createCachedBeaconState(state, { + config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), + finalizedPubkey2index: pubkey2index, + finalizedIndex2pubkey: index2pubkey, + }); } if (!altairCachedState23638) { altairCachedState23638 = processSlots( diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 15a1e1306bf..415fd0cd124 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -1,7 +1,7 @@ import {expect} from "chai"; import {ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; -import {createCachedBeaconState, newUnfinalizedPubkeyIndexMap, PubkeyIndexMap} from "@lodestar/state-transition"; +import {createCachedBeaconState, PubkeyIndexMap} from "@lodestar/state-transition"; import {createBeaconConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; import {config as chainConfig} from "@lodestar/config/default"; diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index f466d71af8f..5acd024ed2c 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -1,19 +1,16 @@ import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; -import {createCachedBeaconState, PubkeyIndexMap, newUnfinalizedPubkeyIndexMap} from "../../../src/index.js"; +import {createCachedBeaconState, PubkeyIndexMap} from "../../../src/index.js"; describe("CachedBeaconState", () => { it("Create empty CachedBeaconState", () => { const emptyState = ssz.phase0.BeaconState.defaultViewDU(); - createCachedBeaconState( - emptyState, - { - config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], - } - ); + createCachedBeaconState(emptyState, { + config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], + }); }); }); diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index ffba541f162..6ebae08ce64 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -19,7 +19,6 @@ import { BeaconStateAllForks, createCachedBeaconState, PubkeyIndexMap, - newUnfinalizedPubkeyIndexMap, } from "../../src/index.js"; import {BeaconStateCache} from "../../src/cache/stateCache.js"; import {EpochCacheOpts} from "../../src/cache/epochCache.js"; @@ -90,15 +89,12 @@ export function generateCachedState( opts: TestBeaconState = {} ): CachedBeaconStateAllForks { const state = generateState(opts); - return createCachedBeaconState( - state, - { - config: createBeaconConfig(config, state.genesisValidatorsRoot), - // This is a test state, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], - } - ); + return createCachedBeaconState(state, { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + // This is a test state, there's no need to have a global shared cache of keys + finalizedPubkey2index: new PubkeyIndexMap(), + finalizedIndex2pubkey: [], + }); } export function createCachedBeaconStateTest( diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index 4c6eb8481f0..6136fe6cb86 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -13,10 +13,9 @@ import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, ValidatorIndex, DepositIndex, UintBn64} = - primitiveSsz; +const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, DepositIndex, UintBn64} = primitiveSsz; -export const DepositReceipt = new ContainerType( +export const DepositReceipt = new ContainerType( { pubkey: BLSPubkey, withdrawalCredentials: Bytes32, @@ -29,7 +28,7 @@ export const DepositReceipt = new ContainerType( export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); -export const ExecutionPayload = new ContainerType( +export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, depositReceipts: DepositReceipts, // New in EIP6110 @@ -37,7 +36,7 @@ export const ExecutionPayload = new ContainerType( {typeName: "ExecutionPayload", jsonCase: "eth2"} ); -export const ExecutionPayloadHeader = new ContainerType( +export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, depositReceiptsRoot: Root, // New in EIP6110 @@ -46,7 +45,7 @@ export const ExecutionPayloadHeader = new ContainerType( ); // We have to preserve Fields ordering while changing the type of ExecutionPayload -export const BeaconBlockBody = new ContainerType( +export const BeaconBlockBody = new ContainerType( { ...altairSsz.BeaconBlockBody.fields, executionPayload: ExecutionPayload, // Modified in EIP6110 @@ -56,7 +55,7 @@ export const BeaconBlockBody = new ContainerType( {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const BeaconBlock = new ContainerType( +export const BeaconBlock = new ContainerType( { ...denebSsz.BeaconBlock.fields, body: BeaconBlockBody, // Modified in EIP6110 @@ -64,7 +63,7 @@ export const BeaconBlock = new ContainerType( {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const SignedBeaconBlock = new ContainerType( +export const SignedBeaconBlock = new ContainerType( { message: BeaconBlock, // Modified in EIP6110 signature: BLSSignature, @@ -72,7 +71,7 @@ export const SignedBeaconBlock = new ContainerType( {typeName: "SignedBeaconBlock", jsonCase: "eth2"} ); -export const BlindedBeaconBlockBody = new ContainerType( +export const BlindedBeaconBlockBody = new ContainerType( { ...altairSsz.BeaconBlockBody.fields, executionPayloadHeader: ExecutionPayloadHeader, // Modified in EIP6110 @@ -82,7 +81,7 @@ export const BlindedBeaconBlockBody = new ContainerType( {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const BlindedBeaconBlock = new ContainerType( +export const BlindedBeaconBlock = new ContainerType( { ...denebSsz.BlindedBeaconBlock.fields, body: BlindedBeaconBlockBody, // Modified in EIP6110 @@ -90,7 +89,7 @@ export const BlindedBeaconBlock = new ContainerType( {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const SignedBlindedBeaconBlock = new ContainerType( +export const SignedBlindedBeaconBlock = new ContainerType( { message: BlindedBeaconBlock, // Modified in EIP6110 signature: BLSSignature, @@ -98,7 +97,7 @@ export const SignedBlindedBeaconBlock = new ContainerType( {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} ); -export const BuilderBid = new ContainerType( +export const BuilderBid = new ContainerType( { header: ExecutionPayloadHeader, // Modified in EIP6110 value: UintBn256, @@ -108,7 +107,7 @@ export const BuilderBid = new ContainerType( {typeName: "BuilderBid", jsonCase: "eth2"} ); -export const SignedBuilderBid = new ContainerType( +export const SignedBuilderBid = new ContainerType( { message: BuilderBid, signature: BLSSignature, @@ -118,7 +117,7 @@ export const SignedBuilderBid = new ContainerType( // We don't spread deneb.BeaconState fields since we need to replace // latestExecutionPayloadHeader and we cannot keep order doing that -export const BeaconState = new ContainerType( +export const BeaconState = new ContainerType( { genesisTime: UintNum64, genesisValidatorsRoot: Root, @@ -165,7 +164,7 @@ export const BeaconState = new ContainerType( {typeName: "BeaconState", jsonCase: "eth2"} ); -export const LightClientHeader = new ContainerType( +export const LightClientHeader = new ContainerType( { beacon: phase0Ssz.BeaconBlockHeader, execution: ExecutionPayloadHeader, // Modified in EIP6110 @@ -174,7 +173,7 @@ export const LightClientHeader = new ContainerType( {typeName: "LightClientHeader", jsonCase: "eth2"} ); -export const LightClientBootstrap = new ContainerType( +export const LightClientBootstrap = new ContainerType( { header: LightClientHeader, currentSyncCommittee: altairSsz.SyncCommittee, @@ -183,7 +182,7 @@ export const LightClientBootstrap = new ContainerType( {typeName: "LightClientBootstrap", jsonCase: "eth2"} ); -export const LightClientUpdate = new ContainerType( +export const LightClientUpdate = new ContainerType( { attestedHeader: LightClientHeader, nextSyncCommittee: altairSsz.SyncCommittee, @@ -196,7 +195,7 @@ export const LightClientUpdate = new ContainerType( {typeName: "LightClientUpdate", jsonCase: "eth2"} ); -export const LightClientFinalityUpdate = new ContainerType( +export const LightClientFinalityUpdate = new ContainerType( { attestedHeader: LightClientHeader, finalizedHeader: LightClientHeader, @@ -207,7 +206,7 @@ export const LightClientFinalityUpdate = new ContainerType( {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} ); -export const LightClientOptimisticUpdate = new ContainerType( +export const LightClientOptimisticUpdate = new ContainerType( { attestedHeader: LightClientHeader, syncAggregate: altairSsz.SyncAggregate, @@ -216,7 +215,7 @@ export const LightClientOptimisticUpdate = new ContainerType( {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} ); -export const LightClientStore = new ContainerType( +export const LightClientStore = new ContainerType( { snapshot: LightClientBootstrap, validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), @@ -225,7 +224,7 @@ export const LightClientStore = new ContainerType( ); // PayloadAttributes primarily for SSE event -export const PayloadAttributes = new ContainerType( +export const PayloadAttributes = new ContainerType( { ...capellaSsz.PayloadAttributes.fields, parentBeaconBlockRoot: Root, @@ -233,7 +232,7 @@ export const PayloadAttributes = new ContainerType( {typeName: "PayloadAttributes", jsonCase: "eth2"} ); -export const SSEPayloadAttributes = new ContainerType( +export const SSEPayloadAttributes = new ContainerType( { ...bellatrixSsz.SSEPayloadAttributesCommon.fields, payloadAttributes: PayloadAttributes, From c2393c8bcc958e419717c744deed76b2a35db377 Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 26 Sep 2023 16:51:36 +0800 Subject: [PATCH 057/155] Pass epochCache instead of pubkey2IndexFn in apis --- .../src/api/impl/beacon/state/index.ts | 10 +++++----- .../src/api/impl/beacon/state/utils.ts | 9 +++++---- .../unit/api/impl/beacon/state/utils.test.ts | 16 ++++++++-------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 525435ae46b..e38d0cda114 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -59,12 +59,12 @@ export function getBeaconStateApi({ const {state, executionOptimistic} = await resolveStateId(chain, stateId); const currentEpoch = getCurrentEpoch(state); const {validators, balances} = state; // Get the validators sub tree once for all the loop - const pubkey2indexFn = chain.getHeadState().epochCtx.getValidatorIndex; + const epochCache = chain.getHeadState().epochCtx; const validatorResponses: routes.beacon.ValidatorResponse[] = []; if (filters?.id) { for (const id of filters.id) { - const resp = getStateValidatorIndex(id, state, pubkey2indexFn); + const resp = getStateValidatorIndex(id, state, epochCache); if (resp.valid) { const validatorIndex = resp.validatorIndex; const validator = validators.getReadonly(validatorIndex); @@ -85,7 +85,7 @@ export function getBeaconStateApi({ data: validatorResponses, }; } else if (filters?.status) { - const validatorsByStatus = filterStateValidatorsByStatus(filters.status, state, pubkey2indexFn, currentEpoch); + const validatorsByStatus = filterStateValidatorsByStatus(filters.status, state, epochCache, currentEpoch); return { executionOptimistic, data: validatorsByStatus, @@ -108,9 +108,9 @@ export function getBeaconStateApi({ async getStateValidator(stateId, validatorId) { const {state, executionOptimistic} = await resolveStateId(chain, stateId); - const pubkey2indexFn = chain.getHeadState().epochCtx.getValidatorIndex; + const epochCache = chain.getHeadState().epochCtx; - const resp = getStateValidatorIndex(validatorId, state, pubkey2indexFn); + const resp = getStateValidatorIndex(validatorId, state, epochCache); if (!resp.valid) { throw new ApiError(resp.code, resp.reason); } diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index c67fde5564e..2590b4b9d12 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -7,6 +7,7 @@ import {Epoch, ValidatorIndex} from "@lodestar/types"; import {IBeaconChain, StateGetOpts} from "../../../../chain/index.js"; import {ApiError, ValidationError} from "../../errors.js"; import {isOptimisticBlock} from "../../../../util/forkChoice.js"; +import { EpochCache } from "@lodestar/state-transition/src/types.js"; export async function resolveStateId( chain: IBeaconChain, @@ -111,7 +112,7 @@ export function toValidatorResponse( export function filterStateValidatorsByStatus( statuses: string[], state: BeaconStateAllForks, - pubkey2index: (arg: BLSPubkey) => number | undefined, + epochCache: EpochCache, currentEpoch: Epoch ): routes.beacon.ValidatorResponse[] { const responses: routes.beacon.ValidatorResponse[] = []; @@ -121,7 +122,7 @@ export function filterStateValidatorsByStatus( for (const validator of validatorsArr) { const validatorStatus = getValidatorStatus(validator, currentEpoch); - const resp = getStateValidatorIndex(validator.pubkey, state, pubkey2index); + const resp = getStateValidatorIndex(validator.pubkey, state, epochCache); if (resp.valid && statusSet.has(validatorStatus)) { responses.push( toValidatorResponse(resp.validatorIndex, validator, state.balances.get(resp.validatorIndex), currentEpoch) @@ -136,7 +137,7 @@ type StateValidatorIndexResponse = {valid: true; validatorIndex: number} | {vali export function getStateValidatorIndex( id: routes.beacon.ValidatorId | BLSPubkey, state: BeaconStateAllForks, - pubkey2indexFn: (arg: BLSPubkey) => number | undefined + epochCache: EpochCache, ): StateValidatorIndexResponse { let validatorIndex: ValidatorIndex | undefined; if (typeof id === "string") { @@ -161,7 +162,7 @@ export function getStateValidatorIndex( } // typeof id === Uint8Array - validatorIndex = pubkey2indexFn(id as BLSPubkey); + validatorIndex = epochCache.getValidatorIndex(id as BLSPubkey); if (validatorIndex === undefined) { return {valid: false, code: 404, reason: "Validator pubkey not found in state"}; } diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index 974c807df00..14fb2425228 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -107,39 +107,39 @@ describe("beacon state api utils", function () { describe("getStateValidatorIndex", async function () { const state = generateCachedAltairState(); - const pubkey2indexFn = state.epochCtx.getValidatorIndex; + const epochCache = state.epochCtx; it("should return valid: false on invalid input", () => { - expect(getStateValidatorIndex("foo", state, pubkey2indexFn).valid, "invalid validator id number").to.equal(false); - expect(getStateValidatorIndex("0xfoo", state, pubkey2indexFn).valid, "invalid hex").to.equal(false); + expect(getStateValidatorIndex("foo", state, epochCache).valid, "invalid validator id number").to.equal(false); + expect(getStateValidatorIndex("0xfoo", state, epochCache).valid, "invalid hex").to.equal(false); }); it("should return valid: false on validator indices / pubkeys not in the state", () => { expect( - getStateValidatorIndex(String(state.validators.length), state, pubkey2indexFn).valid, + getStateValidatorIndex(String(state.validators.length), state, epochCache).valid, "validator id not in state" ).to.equal(false); - expect(getStateValidatorIndex("0xabcd", state, pubkey2indexFn).valid, "validator pubkey not in state").to.equal( + expect(getStateValidatorIndex("0xabcd", state, epochCache).valid, "validator pubkey not in state").to.equal( false ); }); it("should return valid: true on validator indices / pubkeys in the state", () => { const index = state.validators.length - 1; - const resp1 = getStateValidatorIndex(String(index), state, pubkey2indexFn); + const resp1 = getStateValidatorIndex(String(index), state, epochCache); if (resp1.valid) { expect(resp1.validatorIndex).to.equal(index); } else { expect.fail("validator index should be found - validator index input"); } const pubkey = state.validators.get(index).pubkey; - const resp2 = getStateValidatorIndex(pubkey, state, pubkey2indexFn); + const resp2 = getStateValidatorIndex(pubkey, state, epochCache); if (resp2.valid) { expect(resp2.validatorIndex).to.equal(index); } else { expect.fail("validator index should be found - Uint8Array input"); } - const resp3 = getStateValidatorIndex(toHexString(pubkey), state, pubkey2indexFn); + const resp3 = getStateValidatorIndex(toHexString(pubkey), state, epochCache); if (resp3.valid) { expect(resp3.validatorIndex).to.equal(index); } else { From 680816bcea5b592d7adb15153ebeb9b3ef8309fe Mon Sep 17 00:00:00 2001 From: navie Date: Wed, 27 Sep 2023 11:37:35 +0800 Subject: [PATCH 058/155] Address comments --- packages/beacon-node/src/chain/chain.ts | 2 +- .../unit/chain/lightclient/upgradeLightClientHeader.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 7dd1a0f424c..0a8450ab839 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -227,7 +227,7 @@ export class BeaconChain implements IBeaconChain { }); // Persist single global instance of state caches - this.pubkey2index = cachedState.epochCtx.finalizedPubkey2index; // TODO: Double check if these two are correct + this.pubkey2index = cachedState.epochCtx.finalizedPubkey2index; this.index2pubkey = cachedState.epochCtx.finalizedIndex2pubkey; const stateCache = new StateContextCache({metrics}); diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index 7a9223877a3..f6af6d0433c 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -15,7 +15,7 @@ describe("UpgradeLightClientHeader", function () { BELLATRIX_FORK_EPOCH: 2, CAPELLA_FORK_EPOCH: 3, DENEB_FORK_EPOCH: 4, - EIP6110_FORK_EPOCH: 4, + EIP6110_FORK_EPOCH: 5, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); From f0ef6299862a07aa37b82c1ce86874ddaefab009 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 27 Sep 2023 23:08:44 +0800 Subject: [PATCH 059/155] Add unit test on pubkey cache cloning --- .../test/unit/cachedBeaconState.test.ts | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 0367fd636e7..b02da161f42 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -1,6 +1,8 @@ import {expect} from "chai"; +import {fromHexString} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; +import {createChainForkConfig} from "@lodestar/config"; import {createCachedBeaconStateTest} from "../utils/state.js"; describe("CachedBeaconState", () => { @@ -24,6 +26,89 @@ describe("CachedBeaconState", () => { expect(state2.epochCtx.epoch).to.equal(0, "state2.epochCtx.epoch was mutated"); }); + it("Clone and mutate cache pre-6110", () => { + const stateView = ssz.altair.BeaconState.defaultViewDU(); + const state1 = createCachedBeaconStateTest(stateView); + + const pubkey1 = fromHexString( + "0x84105a985058fc8740a48bf1ede9d223ef09e8c6b1735ba0a55cf4a9ff2ff92376b778798365e488dab07a652eb04576" + ); + const index1 = 123; + const pubkey2 = fromHexString( + "0xa41726266b1d83ef609d759ba7796d54cfe549154e01e4730a3378309bc81a7638140d7e184b33593c072595f23f032d" + ); + const index2 = 456; + + state1.epochCtx.addPubkey(pubkey1, index1); + + const state2 = state1.clone(); + state2.epochCtx.addPubkey(pubkey2, index2); + + expect(state1.epochCtx.getValidatorIndex(pubkey1)).to.equal( + index1, + "addPubkey() is not reflected in getValidatorIndex()" + ); + expect(state2.epochCtx.getValidatorIndex(pubkey1)).to.equal( + index1, + "cloned state does not maintain cache from original state" + ); + expect(state1.epochCtx.getValidatorIndex(pubkey2)).to.equal( + index2, + "original state cache was not updated when inserting pubkeys into cloned state cache" + ); + expect(state2.epochCtx.getValidatorIndex(pubkey2)).to.equal( + index2, + "addPubkey() is not reflected in getValidatorIndex()" + ); + }); + + /* eslint-disable @typescript-eslint/naming-convention */ + it("Clone and mutate cache post-6110", () => { + const stateView = ssz.eip6110.BeaconState.defaultViewDU(); + const state1 = createCachedBeaconStateTest( + stateView, + createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + EIP6110_FORK_EPOCH: 0, + }), + {skipSyncCommitteeCache: true, skipSyncPubkeys: true} + ); + + const pubkey1 = fromHexString( + "0x84105a985058fc8740a48bf1ede9d223ef09e8c6b1735ba0a55cf4a9ff2ff92376b778798365e488dab07a652eb04576" + ); + const index1 = 123; + const pubkey2 = fromHexString( + "0xa41726266b1d83ef609d759ba7796d54cfe549154e01e4730a3378309bc81a7638140d7e184b33593c072595f23f032d" + ); + const index2 = 456; + + state1.epochCtx.addPubkey(pubkey1, index1); + + const state2 = state1.clone(); + state2.epochCtx.addPubkey(pubkey2, index2); + + expect(state1.epochCtx.getValidatorIndex(pubkey1)).to.equal( + index1, + "addPubkey() is not reflected in getValidatorIndex()" + ); + expect(state2.epochCtx.getValidatorIndex(pubkey1)).to.equal( + index1, + "cloned state does not maintain cache from original state" + ); + expect(state1.epochCtx.getValidatorIndex(pubkey2)).to.equal( + undefined, + "original state cache was updated when inserting pubkeys into cloned state cache" + ); + expect(state2.epochCtx.getValidatorIndex(pubkey2)).to.equal( + index2, + "addPubkey() is not reflected in getValidatorIndex()" + ); + }); + it("Auto-commit on hashTreeRoot", () => { // Use Checkpoint instead of BeaconState to speed up the test const cp1 = ssz.phase0.Checkpoint.defaultViewDU(); From b0b5dfd09d626a95759ca5ec173b7ee9537512aa Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 28 Sep 2023 14:57:31 +0800 Subject: [PATCH 060/155] Add unfinalizedPubkeyCacheSize to metrics --- packages/beacon-node/src/metrics/metrics/beacon.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/beacon-node/src/metrics/metrics/beacon.ts b/packages/beacon-node/src/metrics/metrics/beacon.ts index 25f842e635a..48f5e60c905 100644 --- a/packages/beacon-node/src/metrics/metrics/beacon.ts +++ b/packages/beacon-node/src/metrics/metrics/beacon.ts @@ -109,6 +109,13 @@ export function createBeaconMetrics(register: RegistryMetricCreator) { }), }, + headState: { + unfinalizedPubkeyCacheSize: register.gauge({ + name: "head_state_unfinalized_pubkey_cache_size", + help: "Current size of the unfinalizedPubkey2Index cache in the head state", + }), + }, + parentBlockDistance: register.histogram({ name: "beacon_imported_block_parent_distance", help: "Histogram of distance to parent block of valid imported blocks", From f44098c82b8fc7783c9f46f1c75573bc0ea03588 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 28 Sep 2023 14:57:43 +0800 Subject: [PATCH 061/155] Add unfinalizedPubkeyCacheSize to metrics --- packages/beacon-node/src/chain/chain.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 0a8450ab839..5883c0507a8 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -761,6 +761,9 @@ export class BeaconChain implements IBeaconChain { metrics.forkChoice.balancesLength.set(forkChoiceMetrics.balancesLength); metrics.forkChoice.nodes.set(forkChoiceMetrics.nodes); metrics.forkChoice.indices.set(forkChoiceMetrics.indices); + + const headState = this.getHeadState(); + metrics.headState.unfinalizedPubkeyCacheSize.set(headState.epochCtx.unfinalizedPubkey2index.size); } private onClockSlot(slot: Slot): void { From 64facbfa8193173466ff8d6e4de5c6110cf9c081 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 28 Sep 2023 15:21:53 +0800 Subject: [PATCH 062/155] Clean up code --- .../state-transition/src/block/processExecutionPayload.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 56fa39d78d9..d1d8bb1f716 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -84,7 +84,7 @@ export function executionPayloadToPayloadHeader( ): allForks.ExecutionPayloadHeader { const transactionsRoot = ssz.bellatrix.Transactions.hashTreeRoot(payload.transactions); - const bellatrixPayloadFields: allForks.ExecutionPayloadHeader = { + const payloadFields: allForks.ExecutionPayloadHeader = { // Starts off with bellatrix payload fields as the base parentHash: payload.parentHash, feeRecipient: payload.feeRecipient, stateRoot: payload.stateRoot, @@ -101,8 +101,6 @@ export function executionPayloadToPayloadHeader( transactionsRoot, }; - const payloadFields = bellatrixPayloadFields; - if (fork >= ForkSeq.capella) { (payloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot( (payload as capella.ExecutionPayload).withdrawals From f7d0f0529d4cb2f018b029ce578ab96fb7eb25ee Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 29 Sep 2023 14:49:48 +0800 Subject: [PATCH 063/155] Add besu to el-interop --- .../scripts/el-interop/besu/common-setup.sh | 19 ++++++++++++++++ .../scripts/el-interop/besu/post-merge.sh | 8 +++++++ .../el-interop/besudocker/common-setup.sh | 22 +++++++++++++++++++ .../el-interop/besudocker/post-merge.sh | 8 +++++++ 4 files changed, 57 insertions(+) create mode 100755 packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh create mode 100755 packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh create mode 100644 packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh create mode 100644 packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh diff --git a/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh b/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh new file mode 100755 index 00000000000..1444f6d3a47 --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besu/common-setup.sh @@ -0,0 +1,19 @@ +#!/bin/bash -x + +echo $TTD +echo $DATA_DIR +echo $EL_BINARY_DIR +echo $JWT_SECRET_HEX +echo $TEMPLATE_FILE + +echo $scriptDir +echo $currentDir + + +env TTD=$TTD envsubst < $scriptDir/$TEMPLATE_FILE > $DATA_DIR/genesis.json +echo "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" > $DATA_DIR/sk.json +echo "12345678" > $DATA_DIR/password.txt +pubKey="0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" + +# echo a hex encoded 256 bit secret into a file +echo $JWT_SECRET_HEX> $DATA_DIR/jwtsecret \ No newline at end of file diff --git a/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh new file mode 100755 index 00000000000..ccfa609ec5d --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh @@ -0,0 +1,8 @@ +#!/bin/bash -x + +scriptDir=$(dirname $0) +currentDir=$(pwd) + +. $scriptDir/common-setup.sh + +$EL_BINARY_DIR/besu --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json \ No newline at end of file diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh b/packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh new file mode 100644 index 00000000000..b3d93190ef2 --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/common-setup.sh @@ -0,0 +1,22 @@ +#!/bin/bash -x + +echo $TTD +echo $DATA_DIR +echo $EL_BINARY_DIR +echo $JWT_SECRET_HEX +echo $TEMPLATE_FILE + +echo $scriptDir +echo $currentDir + + +env TTD=$TTD envsubst < $scriptDir/$TEMPLATE_FILE > $DATA_DIR/genesis.json +echo "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" > $DATA_DIR/sk.json +echo "12345678" > $DATA_DIR/password.txt +pubKey="0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" + +# echo a hex encoded 256 bit secret into a file +echo $JWT_SECRET_HEX> $DATA_DIR/jwtsecret +# clear any previous docker dangling docker run +docker rm -f custom-execution +rm -rf $DATA_DIR/besu diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh new file mode 100644 index 00000000000..7d2022524ef --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh @@ -0,0 +1,8 @@ +#!/bin/bash -x + +scriptDir=$(dirname $0) +currentDir=$(pwd) + +. $scriptDir/common-setup.sh + +docker run --rm -u $(id -u ${USER}):$(id -g ${USER}) --name custom-execution --network host -v $currentDir/$DATA_DIR:/data $EL_BINARY_DIR --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json \ No newline at end of file From 1e00e757767ac443b72cf2b511b2a154f2975f0a Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 29 Sep 2023 14:50:00 +0800 Subject: [PATCH 064/155] Add 6110 genesis file --- .../test/scripts/el-interop/besu/6110.tmpl | 77 +++++++++++++++++++ .../scripts/el-interop/besudocker/6110.tmpl | 77 +++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl create mode 100644 packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl diff --git a/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl b/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl new file mode 100644 index 00000000000..4a646efb5ac --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl @@ -0,0 +1,77 @@ +{ + "config": { + "chainId":6110, + "homesteadBlock":0, + "eip150Block":0, + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":0, + "muirGlacierBlock":0, + "berlinBlock":0, + "londonBlock":0, + "terminalTotalDifficulty":0, + "cancunTime":0, + "experimentalEipsTime":20, + "clique": { + "period": 5, + "epoch": 30000 + }, + "depositContractAddress": "0x4242424242424242424242424242424242424242" + }, + "nonce":"0x42", + "timestamp":"0x0", + "extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit":"0x1C9C380", + "difficulty":"0x400000000", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "0xa4664C40AACeBD82A2Db79f0ea36C06Bc6A19Adb": { + "balance": "1000000000000000000000000000" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":"0x7" +} diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl b/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl new file mode 100644 index 00000000000..4a646efb5ac --- /dev/null +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl @@ -0,0 +1,77 @@ +{ + "config": { + "chainId":6110, + "homesteadBlock":0, + "eip150Block":0, + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":0, + "muirGlacierBlock":0, + "berlinBlock":0, + "londonBlock":0, + "terminalTotalDifficulty":0, + "cancunTime":0, + "experimentalEipsTime":20, + "clique": { + "period": 5, + "epoch": 30000 + }, + "depositContractAddress": "0x4242424242424242424242424242424242424242" + }, + "nonce":"0x42", + "timestamp":"0x0", + "extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit":"0x1C9C380", + "difficulty":"0x400000000", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "0xa4664C40AACeBD82A2Db79f0ea36C06Bc6A19Adb": { + "balance": "1000000000000000000000000000" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":"0x7" +} From aba9505b68732d0730a07b7b6012a6769749dc4b Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 29 Sep 2023 15:37:57 +0800 Subject: [PATCH 065/155] Template for sim test --- .../beacon-node/test/sim/6110-interop.test.ts | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 packages/beacon-node/test/sim/6110-interop.test.ts diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts new file mode 100644 index 00000000000..7fbeb8a7238 --- /dev/null +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -0,0 +1,141 @@ +import fs from "node:fs"; +import {Context} from "mocha"; +import {fromHexString, toHexString} from "@chainsafe/ssz"; +import {bytesToInt, LogLevel, sleep} from "@lodestar/utils"; +import {TimestampFormatCode} from "@lodestar/logger"; +import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ChainConfig} from "@lodestar/config"; +import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {Epoch, Slot} from "@lodestar/types"; +import {ValidatorProposerConfig} from "@lodestar/validator"; + +import {ChainEvent} from "../../src/chain/index.js"; +import {ClockEvent} from "../../src/util/clock.js"; +import {initializeExecutionEngine} from "../../src/execution/index.js"; +import {bytesToData, dataToBytes} from "../../src/eth1/provider/utils.js"; +import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; + +import {testLogger, TestLoggerOpts} from "../utils/logger.js"; +import {getDevBeaconNode} from "../utils/node/beacon.js"; +import {BeaconRestApiServerOpts} from "../../src/api/index.js"; +import {simTestInfoTracker} from "../utils/node/simTest.js"; +import {getAndInitDevValidators} from "../utils/node/validator.js"; +import {BeaconNode, Eth1Provider} from "../../src/index.js"; +import {ZERO_HASH} from "../../src/constants/index.js"; +import {runEL, ELStartMode, ELClient, sendRawTransactionBig} from "../utils/runEl.js"; +import {logFilesDir} from "./params.js"; +import {shell} from "./shell.js"; +import {defaultExecutionEngineHttpOpts} from "../../src/execution/engine/http.js"; + +// NOTE: How to run +// DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:23.7.3 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts +// ``` + +/* eslint-disable no-console, @typescript-eslint/naming-convention */ + +const jwtSecretHex = "0xdc6457099f127cf0bac78de8b297df04951281909db4f58b43def7c7151e765d"; +const retryAttempts = defaultExecutionEngineHttpOpts.retryAttempts; +const retryDelay = defaultExecutionEngineHttpOpts.retryDelay; + +describe("executionEngine / ExecutionEngineHttp", function () { + if (!process.env.EL_BINARY_DIR || !process.env.EL_SCRIPT_DIR) { + throw Error( + `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` + ); + } + this.timeout("10min"); + + const dataPath = fs.mkdtempSync("lodestar-test-6110"); + const elSetupConfig = { + elScriptDir: process.env.EL_SCRIPT_DIR, + elBinaryDir: process.env.EL_BINARY_DIR, + }; + const elRunOptions = { + dataPath, + jwtSecretHex, + enginePort: parseInt(process.env.ENGINE_PORT ?? "8551"), + ethPort: parseInt(process.env.ETH_PORT ?? "8545"), + }; + + const controller = new AbortController(); + after(async () => { + controller?.abort(); + await shell(`sudo rm -rf ${dataPath}`); + }); + + const afterEachCallbacks: (() => Promise | void)[] = []; + afterEach(async () => { + while (afterEachCallbacks.length > 0) { + const callback = afterEachCallbacks.pop(); + if (callback) await callback(); + } + }); + + it("Send stub payloads to EL", async () => { + const {elClient, tearDownCallBack} = await runEL( + {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "6110.tmpl"}, + {...elRunOptions, ttd: BigInt(0)}, + controller.signal + ); + afterEachCallbacks.push(() => tearDownCallBack()); + const {genesisBlockHash, engineRpcUrl, ethRpcUrl} = elClient; + console.log({genesisBlockHash}); + + const executionEngine = initializeExecutionEngine( + {mode: "http", urls: [engineRpcUrl], jwtSecretHex, retryAttempts, retryDelay}, + {signal: controller.signal, logger: testLogger("executionEngine")} + ); + + const depositReceiptsVector = [ + { + amount: 320000000000, + index: 0n, + pubkey: "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", + signature: "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", + withdrawalCredentials: "0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2" + } + ] + + const deposits = depositReceiptsVector.map((testVec) => ({ + pubkey: dataToBytes(testVec.pubkey, 48), + withdrawalCredentials: dataToBytes(testVec.withdrawalCredentials, 32), + amount: testVec.amount, + signature: dataToBytes(testVec.signature, 96), + index: testVec.index, + })); + + const depositTransaction = "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + + // TODO 6110: Do the following + // 1. Send raw deposit transaction + // 2. Prepare a payload + // With depositReceipts + // 3. Update fork choice + // 4. Get the payload + // Check depositReceipts field contains deposit + }); + + it("Post-merge, run for a few blocks", async function () { + console.log("\n\nPost-merge, run for a few blocks\n\n"); + const {elClient, tearDownCallBack} = await runEL( + {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "6110.tmpl"}, + {...elRunOptions, ttd: BigInt(0)}, + controller.signal + ); + afterEachCallbacks.push(() => tearDownCallBack()); + + await runNodeWithEL.bind(this)({ + elClient, + denebEpoch: 0, + testName: "post-merge", + }); + }); + + async function runNodeWithEL( + this: Context, + {elClient, denebEpoch, testName}: {elClient: ELClient; denebEpoch: Epoch; testName: string} + ): Promise { + // TODO 6110: Implment it + } +}); + From e951cf10515903180f9d014fefb4e2bd77661268 Mon Sep 17 00:00:00 2001 From: navie Date: Sat, 7 Oct 2023 19:27:47 +0800 Subject: [PATCH 066/155] Add unit test for getEth1DepositCount --- packages/state-transition/package.json | 2 +- .../test/unit/util/deposit.test.ts | 117 ++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 packages/state-transition/test/unit/util/deposit.test.ts diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 6916154b473..cb03e601060 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -52,7 +52,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "test:unit": "mocha 'test/unit/**/*.test.ts'", + "test:unit": "mocha 'test/unit/**/deposit.test.ts'", "check-readme": "typescript-docs-verifier" }, "types": "lib/index.d.ts", diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts new file mode 100644 index 00000000000..5f33e573310 --- /dev/null +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -0,0 +1,117 @@ +import {expect} from "chai"; +import {ssz} from "@lodestar/types"; +import {createChainForkConfig} from "@lodestar/config"; +import {CachedBeaconStateEIP6110, getEth1DepositCount} from "../../../src/index.js"; +import { createCachedBeaconStateTest } from "../../utils/state.js"; +import { MAX_DEPOSITS } from "@lodestar/params"; + +describe("getEth1DepositCount", () => { + it("Pre 6110", () => { + const stateView = ssz.altair.BeaconState.defaultViewDU(); + const pre6110State = createCachedBeaconStateTest(stateView); + + if (pre6110State.epochCtx.isAfterEIP6110()) { + throw Error("Not a pre-6110 state"); + } + + pre6110State.eth1Data.depositCount = 123; + + // 1. Should get less than MAX_DEPOSIT + pre6110State.eth1DepositIndex = 120; + expect(getEth1DepositCount(pre6110State)).to.equal( + 3, + ); + + // 2. Should get MAX_DEPOSIT + pre6110State.eth1DepositIndex = 100; + expect(getEth1DepositCount(pre6110State)).to.equal( + MAX_DEPOSITS, + ); + }); + it("Post 6110 with eth1 deposit", () => { + const stateView = ssz.eip6110.BeaconState.defaultViewDU(); + const post6110State = createCachedBeaconStateTest( + stateView, + createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + EIP6110_FORK_EPOCH: 0, + }), + {skipSyncCommitteeCache: true, skipSyncPubkeys: true} + ) as CachedBeaconStateEIP6110; + + if (!post6110State.epochCtx.isAfterEIP6110()) { + throw Error("Not a post-6110 state"); + } + + post6110State.depositReceiptsStartIndex = 1000n; + post6110State.eth1Data.depositCount = 995; + + // 1. Should get less than MAX_DEPOSIT + post6110State.eth1DepositIndex = 990; + expect(getEth1DepositCount(post6110State)).to.equal( + 5, + ); + + // 2. Should get MAX_DEPOSIT + post6110State.eth1DepositIndex = 100; + expect(getEth1DepositCount(post6110State)).to.equal( + MAX_DEPOSITS, + ); + + // 3. Should be 0 + post6110State.eth1DepositIndex = 1000; + expect(getEth1DepositCount(post6110State)).to.equal( + 0, + ); + + }); + it("Post 6110 without eth1 deposit", () => { + const stateView = ssz.eip6110.BeaconState.defaultViewDU(); + const post6110State = createCachedBeaconStateTest( + stateView, + createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + EIP6110_FORK_EPOCH: 0, + }), + {skipSyncCommitteeCache: true, skipSyncPubkeys: true} + ) as CachedBeaconStateEIP6110; + + if (!post6110State.epochCtx.isAfterEIP6110()) { + throw Error("Not a post-6110 state"); + } + + post6110State.depositReceiptsStartIndex = 1000n; + post6110State.eth1Data.depositCount = 1005; + + // Before eth1DepositIndex reaching the start index + // 1. Should get less than MAX_DEPOSIT + post6110State.eth1DepositIndex = 990; + expect(getEth1DepositCount(post6110State)).to.equal( + 10, + ); + + // 2. Should get MAX_DEPOSIT + post6110State.eth1DepositIndex = 983; + expect(getEth1DepositCount(post6110State)).to.equal( + MAX_DEPOSITS, + ); + + // After eth1DepositIndex reaching the start index + // 1. Should be 0 + post6110State.eth1DepositIndex = 1000; + expect(getEth1DepositCount(post6110State)).to.equal( + 0, + ); + post6110State.eth1DepositIndex = 1003; + expect(getEth1DepositCount(post6110State)).to.equal( + 0, + ); + }); +}); + \ No newline at end of file From e55dc5bd26437e2891c66009a28c9aaf2bbfe71f Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 9 Oct 2023 19:49:40 +0800 Subject: [PATCH 067/155] Update sim test --- .../beacon-node/test/sim/6110-interop.test.ts | 100 +++++++++++++----- 1 file changed, 76 insertions(+), 24 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 7fbeb8a7238..ba796619db4 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -6,7 +6,7 @@ import {TimestampFormatCode} from "@lodestar/logger"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {ChainConfig} from "@lodestar/config"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {Epoch, Slot} from "@lodestar/types"; +import {capella, eip6110, Epoch, Slot} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; import {ChainEvent} from "../../src/chain/index.js"; @@ -86,33 +86,85 @@ describe("executionEngine / ExecutionEngineHttp", function () { {signal: controller.signal, logger: testLogger("executionEngine")} ); - const depositReceiptsVector = [ + const depositReceipt = { - amount: 320000000000, - index: 0n, - pubkey: "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", - signature: "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", - withdrawalCredentials: "0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2" - } - ] - - const deposits = depositReceiptsVector.map((testVec) => ({ - pubkey: dataToBytes(testVec.pubkey, 48), - withdrawalCredentials: dataToBytes(testVec.withdrawalCredentials, 32), - amount: testVec.amount, - signature: dataToBytes(testVec.signature, 96), - index: testVec.index, - })); - - const depositTransaction = "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; - + amount: 32000000000, + index: 0, + pubkey: dataToBytes("0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", 48), + signature: dataToBytes("0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", 96), + withdrawalCredentials: dataToBytes("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2", 32), + }; + // TODO 6110: Do the following // 1. Send raw deposit transaction - // 2. Prepare a payload - // With depositReceipts + const depositTransaction = "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`) + .catch((e) => { + throw Error(`Fail to send raw deposit transaction: ${e.message}`); + }); + + // 2. Create a payload with depositReceipts + const newPayload = { + parentHash: dataToBytes("0xb9203a1bb9ed08e8160522c78039f4b83c7c932012fc3068db7dc9be537f1673", 32), + feeRecipient: dataToBytes("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 20), + stateRoot: dataToBytes("0xa78bb828a9a90729de2d236a057a415fc635ef98e3209a634285713b34d278e8", 32), + logsBloom: dataToBytes("0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", 256), + prevRandao: dataToBytes("0x0", 32), + gasLimit: 30000000, + gasUsed: 84846, + timestamp: 20, + extraData: dataToBytes("0x", 32), + baseFeePerGas: 7n, + excessBlobGas : 0n, + transactions: [ + dataToBytes(depositTransaction, 1073741824) + ], + withdrawals: [], + depositReceipts : [depositReceipt], + blockNumber: 2, + blockHash: dataToBytes("0xd1ba8d4c47dd83ea145f39e27ef680ee3db132af6f71727e291bfd34dda66ce4", 32), + receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), + blobGasUsed : 0n + } + const payloadResult = await executionEngine.notifyNewPayload(ForkName.eip6110, newPayload, [], dataToBytes("0x0", 32)); + if (payloadResult.status !== ExecutionPayloadStatus.VALID) { + throw Error("getPayload returned payload that notifyNewPayload deems invalid"); + } + // 3. Update fork choice - // 4. Get the payload - // Check depositReceipts field contains deposit + const finalizedBlockHash = "0xd1ba8d4c47dd83ea145f39e27ef680ee3db132af6f71727e291bfd34dda66ce4"; + const preparePayloadParams: PayloadAttributes = { + // Note: this is created with a pre-defined genesis.json + timestamp: 30, + prevRandao: dataToBytes("0x0", 32), + suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + withdrawals: [], + parentBeaconBlockRoot: dataToBytes("0x0", 32), + }; + + const payloadId = await executionEngine.notifyForkchoiceUpdate( + ForkName.eip6110, + finalizedBlockHash, + //use finalizedBlockHash as safeBlockHash + finalizedBlockHash, + finalizedBlockHash, + preparePayloadParams + ); + if (!payloadId) throw Error("InvalidPayloadId"); + + + // 4. Get the payload. Check depositReceipts field contains deposit + const payloadAndBlockValue = await executionEngine.getPayload(ForkName.eip6110, payloadId); + const payload = payloadAndBlockValue.executionPayload as eip6110.ExecutionPayload; + + if (payload.transactions[0] !== dataToBytes(depositTransaction, 1073741824)) { + throw Error("Missing transaction") + } + + if (payload.depositReceipts[0] !== depositReceipt) { + throw Error("Missing deposit") + } + }); it("Post-merge, run for a few blocks", async function () { From 5731382f7687f4fd4e0a65a0a773250c7e0ef07b Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 10 Oct 2023 18:50:26 +0800 Subject: [PATCH 068/155] Update besudocker --- .../test/scripts/el-interop/besudocker/post-merge.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh old mode 100644 new mode 100755 index 7d2022524ef..fb091a7d838 --- a/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/post-merge.sh @@ -5,4 +5,4 @@ currentDir=$(pwd) . $scriptDir/common-setup.sh -docker run --rm -u $(id -u ${USER}):$(id -g ${USER}) --name custom-execution --network host -v $currentDir/$DATA_DIR:/data $EL_BINARY_DIR --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json \ No newline at end of file +docker run --rm -u $(id -u ${USER}):$(id -g ${USER}) --name custom-execution -p $ETH_PORT:$ETH_PORT -p $ENGINE_PORT:$ENGINE_PORT -v $currentDir/$DATA_DIR:/data $EL_BINARY_DIR --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json \ No newline at end of file From 7abc6b2c4904663af96e83851c364ba4eef49f40 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 10 Oct 2023 21:42:55 +0800 Subject: [PATCH 069/155] Finish beacon api calls in sim test --- .../src/api/impl/beacon/state/utils.ts | 4 +- packages/beacon-node/src/chain/chain.ts | 2 +- .../test/scripts/el-interop/besu/6110.tmpl | 2 +- .../scripts/el-interop/besu/post-merge.sh | 2 +- .../scripts/el-interop/besudocker/6110.tmpl | 2 +- .../beacon-node/test/sim/6110-interop.test.ts | 198 +++++++++++------- 6 files changed, 132 insertions(+), 78 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 2590b4b9d12..c4fd69697ba 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -4,10 +4,10 @@ import {FAR_FUTURE_EPOCH, GENESIS_SLOT} from "@lodestar/params"; import {BeaconStateAllForks} from "@lodestar/state-transition"; import {BLSPubkey, phase0} from "@lodestar/types"; import {Epoch, ValidatorIndex} from "@lodestar/types"; +import {EpochCache} from "@lodestar/state-transition/src/types.js"; import {IBeaconChain, StateGetOpts} from "../../../../chain/index.js"; import {ApiError, ValidationError} from "../../errors.js"; import {isOptimisticBlock} from "../../../../util/forkChoice.js"; -import { EpochCache } from "@lodestar/state-transition/src/types.js"; export async function resolveStateId( chain: IBeaconChain, @@ -137,7 +137,7 @@ type StateValidatorIndexResponse = {valid: true; validatorIndex: number} | {vali export function getStateValidatorIndex( id: routes.beacon.ValidatorId | BLSPubkey, state: BeaconStateAllForks, - epochCache: EpochCache, + epochCache: EpochCache ): StateValidatorIndexResponse { let validatorIndex: ValidatorIndex | undefined; if (typeof id === "string") { diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 5883c0507a8..b5e262e3965 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -227,7 +227,7 @@ export class BeaconChain implements IBeaconChain { }); // Persist single global instance of state caches - this.pubkey2index = cachedState.epochCtx.finalizedPubkey2index; + this.pubkey2index = cachedState.epochCtx.finalizedPubkey2index; this.index2pubkey = cachedState.epochCtx.finalizedIndex2pubkey; const stateCache = new StateContextCache({metrics}); diff --git a/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl b/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl index 4a646efb5ac..7a63bfbe36d 100644 --- a/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl +++ b/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl @@ -14,7 +14,7 @@ "londonBlock":0, "terminalTotalDifficulty":0, "cancunTime":0, - "experimentalEipsTime":20, + "experimentalEipsTime":10, "clique": { "period": 5, "epoch": 30000 diff --git a/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh index ccfa609ec5d..47bec71cf8b 100755 --- a/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh +++ b/packages/beacon-node/test/scripts/el-interop/besu/post-merge.sh @@ -5,4 +5,4 @@ currentDir=$(pwd) . $scriptDir/common-setup.sh -$EL_BINARY_DIR/besu --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-jwt-secret /data/jwtsecret --data-path /data/besu --data-storage-format BONSAI --genesis-file /data/genesis.json \ No newline at end of file +$EL_BINARY_DIR/besu --engine-rpc-enabled --rpc-http-enabled --rpc-http-api ADMIN,ETH,MINER,NET --rpc-http-port $ETH_PORT --engine-rpc-port $ENGINE_PORT --engine-jwt-secret $currentDir/$DATA_DIR/jwtsecret --data-path $DATA_DIR --data-storage-format BONSAI --genesis-file $DATA_DIR/genesis.json \ No newline at end of file diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl b/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl index 4a646efb5ac..7a63bfbe36d 100644 --- a/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl +++ b/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl @@ -14,7 +14,7 @@ "londonBlock":0, "terminalTotalDifficulty":0, "cancunTime":0, - "experimentalEipsTime":20, + "experimentalEipsTime":10, "clique": { "period": 5, "epoch": 30000 diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index ba796619db4..cc8a0e6b61d 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -1,34 +1,24 @@ import fs from "node:fs"; import {Context} from "mocha"; -import {fromHexString, toHexString} from "@chainsafe/ssz"; -import {bytesToInt, LogLevel, sleep} from "@lodestar/utils"; -import {TimestampFormatCode} from "@lodestar/logger"; +import _ from "lodash"; +import {sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {ChainConfig} from "@lodestar/config"; -import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {capella, eip6110, Epoch, Slot} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; -import {ChainEvent} from "../../src/chain/index.js"; -import {ClockEvent} from "../../src/util/clock.js"; import {initializeExecutionEngine} from "../../src/execution/index.js"; import {bytesToData, dataToBytes} from "../../src/eth1/provider/utils.js"; import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; import {testLogger, TestLoggerOpts} from "../utils/logger.js"; -import {getDevBeaconNode} from "../utils/node/beacon.js"; -import {BeaconRestApiServerOpts} from "../../src/api/index.js"; -import {simTestInfoTracker} from "../utils/node/simTest.js"; -import {getAndInitDevValidators} from "../utils/node/validator.js"; -import {BeaconNode, Eth1Provider} from "../../src/index.js"; -import {ZERO_HASH} from "../../src/constants/index.js"; -import {runEL, ELStartMode, ELClient, sendRawTransactionBig} from "../utils/runEl.js"; -import {logFilesDir} from "./params.js"; -import {shell} from "./shell.js"; +import {runEL, ELStartMode, ELClient, sendRawTransactionBig, ethGetBlockByNumber} from "../utils/runEl.js"; import {defaultExecutionEngineHttpOpts} from "../../src/execution/engine/http.js"; +import {shell} from "./shell.js"; // NOTE: How to run // DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:23.7.3 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts +// or +// DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn mocha test/sim/6110-interop.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention */ @@ -71,7 +61,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { } }); - it("Send stub payloads to EL", async () => { + it("Send and get payloads with depositReceipts to/from EL", async () => { const {elClient, tearDownCallBack} = await runEL( {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "6110.tmpl"}, {...elRunOptions, ttd: BigInt(0)}, @@ -86,85 +76,150 @@ describe("executionEngine / ExecutionEngineHttp", function () { {signal: controller.signal, logger: testLogger("executionEngine")} ); - const depositReceipt = - { - amount: 32000000000, - index: 0, - pubkey: dataToBytes("0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", 48), - signature: dataToBytes("0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", 96), - withdrawalCredentials: dataToBytes("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2", 32), - }; - - // TODO 6110: Do the following - // 1. Send raw deposit transaction - const depositTransaction = "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; - sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`) - .catch((e) => { - throw Error(`Fail to send raw deposit transaction: ${e.message}`); - }); - - // 2. Create a payload with depositReceipts + // 1. Prepare payload + const preparePayloadParams: PayloadAttributes = { + // Note: this is created with a pre-defined genesis.json + timestamp: 10, + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + withdrawals: [], + parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + }; + const payloadId = await executionEngine.notifyForkchoiceUpdate( + ForkName.eip6110, + genesisBlockHash, + //use finalizedBlockHash as safeBlockHash + genesisBlockHash, + genesisBlockHash, + preparePayloadParams + ); + if (!payloadId) throw Error("InvalidPayloadId"); + + // 2. Send raw deposit transaction A and B. tx A is to be imported via newPayload, tx B is to be included in payload via getPayload + const depositTransactionA = + "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + const depositReceiptA = { + amount: 32000000000, + index: 0, + pubkey: dataToBytes( + "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", + 48 + ), + signature: dataToBytes( + "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", + 96 + ), + withdrawalCredentials: dataToBytes("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2", 32), + }; + + const depositTransactionB = + "0x02f9021c8217de018459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120a18b4c7cab0afa273ea9504904521ea8421a4e32740b7611bd3d5095ca99f0cb0000000000000000000000000000000000000000000000000000000000000030a5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca00000000000000000000000000000000000000000000000000000000000000609561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1c001a0644e0a763a34b4bfb9f56a677857b57fcf15e3db57e2f57060e92084f75f3d82a018ba8eaacbd8e6f6917675b1d0362b12ca82850ca8ef9c010430760c2b2e0cb5"; + const depositReceiptB = { + amount: 32000000000, + index: 1, + pubkey: dataToBytes( + "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b", + 48 + ), + signature: dataToBytes( + "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1", + 96 + ), + withdrawalCredentials: dataToBytes("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca", 32), + }; + + sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e) => { + throw Error(`Fail to send raw deposit transaction A: ${e.message}`); + }); + + sendRawTransactionBig(ethRpcUrl, depositTransactionB, `${dataPath}/deposit.json`).catch((e) => { + throw Error(`Fail to send raw deposit transaction B: ${e.message}`); + }); + + // 3. Import new payload with tx A and deposit receipt A + const newPayloadBlockHash = "0xfd1189e6ea0814b7d40d4e50b31ae5feabbb2acff39399457bbdda7cb5ccd490"; const newPayload = { - parentHash: dataToBytes("0xb9203a1bb9ed08e8160522c78039f4b83c7c932012fc3068db7dc9be537f1673", 32), + parentHash: dataToBytes("0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42", 32), feeRecipient: dataToBytes("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 20), - stateRoot: dataToBytes("0xa78bb828a9a90729de2d236a057a415fc635ef98e3209a634285713b34d278e8", 32), - logsBloom: dataToBytes("0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", 256), - prevRandao: dataToBytes("0x0", 32), + stateRoot: dataToBytes("0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa", 32), + logsBloom: dataToBytes( + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", + 256 + ), + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), gasLimit: 30000000, gasUsed: 84846, - timestamp: 20, - extraData: dataToBytes("0x", 32), + timestamp: 16, + extraData: dataToBytes("0x", 0), baseFeePerGas: 7n, - excessBlobGas : 0n, - transactions: [ - dataToBytes(depositTransaction, 1073741824) - ], + excessBlobGas: 0n, + transactions: [dataToBytes(depositTransactionA, null)], withdrawals: [], - depositReceipts : [depositReceipt], - blockNumber: 2, - blockHash: dataToBytes("0xd1ba8d4c47dd83ea145f39e27ef680ee3db132af6f71727e291bfd34dda66ce4", 32), + depositReceipts: [depositReceiptA], + blockNumber: 1, + blockHash: dataToBytes(newPayloadBlockHash, 32), receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), - blobGasUsed : 0n - } - const payloadResult = await executionEngine.notifyNewPayload(ForkName.eip6110, newPayload, [], dataToBytes("0x0", 32)); + blobGasUsed: 0n, + }; + const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); + const payloadResult = await executionEngine.notifyNewPayload( + ForkName.eip6110, + newPayload, + [], + parentBeaconBlockRoot + ); if (payloadResult.status !== ExecutionPayloadStatus.VALID) { throw Error("getPayload returned payload that notifyNewPayload deems invalid"); } - // 3. Update fork choice - const finalizedBlockHash = "0xd1ba8d4c47dd83ea145f39e27ef680ee3db132af6f71727e291bfd34dda66ce4"; - const preparePayloadParams: PayloadAttributes = { - // Note: this is created with a pre-defined genesis.json - timestamp: 30, - prevRandao: dataToBytes("0x0", 32), + // 4. Update fork choice + const preparePayloadParams2: PayloadAttributes = { + timestamp: 48, + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", withdrawals: [], - parentBeaconBlockRoot: dataToBytes("0x0", 32), + parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), }; - const payloadId = await executionEngine.notifyForkchoiceUpdate( + const payloadId2 = await executionEngine.notifyForkchoiceUpdate( ForkName.eip6110, - finalizedBlockHash, + newPayloadBlockHash, //use finalizedBlockHash as safeBlockHash - finalizedBlockHash, - finalizedBlockHash, - preparePayloadParams + newPayloadBlockHash, + newPayloadBlockHash, + preparePayloadParams2 ); - if (!payloadId) throw Error("InvalidPayloadId"); + if (!payloadId2) throw Error("InvalidPayloadId"); + // 4. Get the payload. Check depositReceipts field contains deposit - // 4. Get the payload. Check depositReceipts field contains deposit - const payloadAndBlockValue = await executionEngine.getPayload(ForkName.eip6110, payloadId); + // Wait a bit first for besu to pick up tx from the tx pool. + await sleep(1000); + const payloadAndBlockValue = await executionEngine.getPayload(ForkName.eip6110, payloadId2); const payload = payloadAndBlockValue.executionPayload as eip6110.ExecutionPayload; - - if (payload.transactions[0] !== dataToBytes(depositTransaction, 1073741824)) { - throw Error("Missing transaction") + + if (payload.transactions.length !== 1) { + throw Error(`Number of transactions mismatched. Expected: 1, actual: ${payload.transactions.length}`); + } else { + const actualTransaction = bytesToData(payload.transactions[0]); + + if (actualTransaction !== depositTransactionB) { + throw Error(`Transaction mismatched. Expected: ${depositTransactionB}, actual: ${actualTransaction}`); + } } - if (payload.depositReceipts[0] !== depositReceipt) { - throw Error("Missing deposit") + if (payload.depositReceipts.length !== 1) { + throw Error(`Number of depositReceipts mismatched. Expected: 1, actual: ${payload.depositReceipts.length}`); } + const actualDepositReceipt = payload.depositReceipts[0]; + if (!_.isEqual(actualDepositReceipt, depositReceiptB)) { + throw Error( + `Deposit receipts mismatched. Expected: ${JSON.stringify(depositReceiptB)}, actual: ${JSON.stringify( + actualDepositReceipt + )}` + ); + } }); it("Post-merge, run for a few blocks", async function () { @@ -190,4 +245,3 @@ describe("executionEngine / ExecutionEngineHttp", function () { // TODO 6110: Implment it } }); - From 63231a8938db6c6c663482d4b25550d137bac196 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 11 Oct 2023 17:29:06 +0800 Subject: [PATCH 070/155] Update epochCache.createFromState() --- packages/state-transition/src/cache/epochCache.ts | 7 ++++--- packages/state-transition/src/cache/stateCache.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 8a4b7bab2b6..6532f52688a 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -36,6 +36,7 @@ import { syncPubkeys, toMemoryEfficientHexStr, PubkeyHex, + newUnfinalizedPubkeyIndexMap, } from "./pubkeyCache.js"; import {BeaconStateAllForks, BeaconStateAltair} from "./types.js"; import { @@ -262,7 +263,6 @@ export class EpochCache { static createFromState( state: BeaconStateAllForks, {config, finalizedPubkey2index, finalizedIndex2pubkey}: EpochCacheImmutableData, - unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap, opts?: EpochCacheOpts ): EpochCache { // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches @@ -408,7 +408,8 @@ export class EpochCache { config, finalizedPubkey2index, finalizedIndex2pubkey, - unfinalizedPubkey2index, + // `createFromState()` creates cache with empty unfinalizedPubkey2index. Be cautious to only pass in finalized state + unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics proposersPrevEpoch: null, @@ -445,7 +446,7 @@ export class EpochCache { // Common append-only structures shared with all states, no need to clone finalizedPubkey2index: this.finalizedPubkey2index, finalizedIndex2pubkey: this.finalizedIndex2pubkey, - // Fork-aware cache needs to be cloned. But by the virtue of it being persistent, we don't need to do anything here + // No need to clone this reference. On each mutation the `unfinalizedPubkey2index` reference is replaced, @see `addPubkey` unfinalizedPubkey2index: this.unfinalizedPubkey2index, // Immutable data proposers: this.proposers, diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 3aee1291b45..25230100c03 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -143,7 +143,7 @@ export function createCachedBeaconState( ): T & BeaconStateCache { return getCachedBeaconState(state, { config: immutableData.config, - epochCtx: EpochCache.createFromState(state, immutableData, newUnfinalizedPubkeyIndexMap(), opts), + epochCtx: EpochCache.createFromState(state, immutableData, opts), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, From eb131456da99d6fc5348b90b37049511f53d9b32 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 12 Oct 2023 19:06:58 +0800 Subject: [PATCH 071/155] Fix bug unfinalized validators are not finalized --- packages/state-transition/src/cache/epochCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 6532f52688a..39c2adac22a 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -558,7 +558,7 @@ export class EpochCache { const validators = state.validators; for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { const validator = validators.getReadonly(index); - if (validator.activationEpoch == expectedActivationEligibilityEpoch) { + if (validator.activationEligibilityEpoch == expectedActivationEligibilityEpoch) { this.addFinalizedPubkey(validator.pubkey, index); } else { break; From e2442f2ed2519ae2cdc29f282a5122765f1887ac Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 12 Oct 2023 19:53:17 +0800 Subject: [PATCH 072/155] Add sim test to run a few blocks --- .../beacon-node/test/sim/6110-interop.test.ts | 245 +++++++++++++++--- 1 file changed, 207 insertions(+), 38 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index cc8a0e6b61d..f6744eea527 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -1,19 +1,27 @@ import fs from "node:fs"; import {Context} from "mocha"; import _ from "lodash"; -import {sleep} from "@lodestar/utils"; +import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {capella, eip6110, Epoch, Slot} from "@lodestar/types"; +import {eip6110, Epoch} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; import {initializeExecutionEngine} from "../../src/execution/index.js"; -import {bytesToData, dataToBytes} from "../../src/eth1/provider/utils.js"; import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; import {testLogger, TestLoggerOpts} from "../utils/logger.js"; -import {runEL, ELStartMode, ELClient, sendRawTransactionBig, ethGetBlockByNumber} from "../utils/runEl.js"; +import {runEL, ELStartMode, ELClient, sendRawTransactionBig} from "../utils/runEl.js"; import {defaultExecutionEngineHttpOpts} from "../../src/execution/engine/http.js"; import {shell} from "./shell.js"; +import {getDevBeaconNode} from "../utils/node/beacon.js"; +import { ChainConfig } from "@lodestar/config"; +import { logFilesDir } from "./params.js"; +import { TimestampFormatCode } from "@lodestar/logger"; +import { BeaconRestApiServerOpts } from "../../src/api/index.js"; +import { fromHexString, toHexString } from "@chainsafe/ssz"; +import { simTestInfoTracker } from "../utils/node/simTest.js"; +import { getAndInitDevValidators } from "../utils/node/validator.js"; +import { ClockEvent } from "../../src/util/clock.js"; // NOTE: How to run // DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:23.7.3 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts @@ -80,10 +88,10 @@ describe("executionEngine / ExecutionEngineHttp", function () { const preparePayloadParams: PayloadAttributes = { // Note: this is created with a pre-defined genesis.json timestamp: 10, - prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + prevRandao: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", withdrawals: [], - parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + parentBeaconBlockRoot: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), }; const payloadId = await executionEngine.notifyForkchoiceUpdate( ForkName.eip6110, @@ -101,15 +109,13 @@ describe("executionEngine / ExecutionEngineHttp", function () { const depositReceiptA = { amount: 32000000000, index: 0, - pubkey: dataToBytes( - "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", - 48 + pubkey: fromHexString( + "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9" ), - signature: dataToBytes( - "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", - 96 + signature: fromHexString( + "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9" ), - withdrawalCredentials: dataToBytes("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2", 32), + withdrawalCredentials: fromHexString("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2"), }; const depositTransactionB = @@ -117,15 +123,13 @@ describe("executionEngine / ExecutionEngineHttp", function () { const depositReceiptB = { amount: 32000000000, index: 1, - pubkey: dataToBytes( - "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b", - 48 + pubkey: fromHexString( + "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b" ), - signature: dataToBytes( - "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1", - 96 + signature: fromHexString( + "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1" ), - withdrawalCredentials: dataToBytes("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca", 32), + withdrawalCredentials: fromHexString("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca"), }; sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e) => { @@ -139,29 +143,28 @@ describe("executionEngine / ExecutionEngineHttp", function () { // 3. Import new payload with tx A and deposit receipt A const newPayloadBlockHash = "0xfd1189e6ea0814b7d40d4e50b31ae5feabbb2acff39399457bbdda7cb5ccd490"; const newPayload = { - parentHash: dataToBytes("0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42", 32), - feeRecipient: dataToBytes("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 20), - stateRoot: dataToBytes("0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa", 32), - logsBloom: dataToBytes( - "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", - 256 + parentHash: fromHexString("0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42"), + feeRecipient: fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"), + stateRoot: fromHexString("0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa"), + logsBloom: fromHexString( + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000" ), - prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + prevRandao: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), gasLimit: 30000000, gasUsed: 84846, timestamp: 16, - extraData: dataToBytes("0x", 0), + extraData: fromHexString("0x"), baseFeePerGas: 7n, excessBlobGas: 0n, - transactions: [dataToBytes(depositTransactionA, null)], + transactions: [fromHexString(depositTransactionA)], withdrawals: [], depositReceipts: [depositReceiptA], blockNumber: 1, - blockHash: dataToBytes(newPayloadBlockHash, 32), - receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), + blockHash: fromHexString(newPayloadBlockHash), + receiptsRoot: fromHexString("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9"), blobGasUsed: 0n, }; - const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); + const parentBeaconBlockRoot = fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"); const payloadResult = await executionEngine.notifyNewPayload( ForkName.eip6110, newPayload, @@ -175,10 +178,10 @@ describe("executionEngine / ExecutionEngineHttp", function () { // 4. Update fork choice const preparePayloadParams2: PayloadAttributes = { timestamp: 48, - prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + prevRandao: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", withdrawals: [], - parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), + parentBeaconBlockRoot: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), }; const payloadId2 = await executionEngine.notifyForkchoiceUpdate( @@ -201,7 +204,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (payload.transactions.length !== 1) { throw Error(`Number of transactions mismatched. Expected: 1, actual: ${payload.transactions.length}`); } else { - const actualTransaction = bytesToData(payload.transactions[0]); + const actualTransaction = toHexString(payload.transactions[0]); if (actualTransaction !== depositTransactionB) { throw Error(`Transaction mismatched. Expected: ${depositTransactionB}, actual: ${actualTransaction}`); @@ -233,15 +236,181 @@ describe("executionEngine / ExecutionEngineHttp", function () { await runNodeWithEL.bind(this)({ elClient, - denebEpoch: 0, + eip6110Epoch: 0, testName: "post-merge", }); }); + // Want to test 2 things: + + /** + * Want to test two things: + * 1) Send two raw deposit transactions, and see if two new validators with corrent balances show up in the state.validators and unfinalized cache + * 2) Upon state-transition, see if the two new validators move from unfinalized cache to finalized cache + */ async function runNodeWithEL( this: Context, - {elClient, denebEpoch, testName}: {elClient: ELClient; denebEpoch: Epoch; testName: string} + {elClient, eip6110Epoch, testName}: {elClient: ELClient; eip6110Epoch: Epoch; testName: string} ): Promise { - // TODO 6110: Implment it + const {genesisBlockHash, ttd, engineRpcUrl, ethRpcUrl} = elClient; + const validatorClientCount = 1; + const validatorsPerClient = 32; + + const testParams: Pick = { + SECONDS_PER_SLOT: 2, + GENESIS_FORK_VERSION: fromHexString("0x00000000"), + EIP6110_FORK_VERSION: fromHexString("0x60000060"), + }; + + // Just finish the run within first epoch as we only need to test if withdrawals started + const expectedEpochsToFinish = 1; + // 1 epoch of margin of error + const epochsOfMargin = 1; + const timeoutSetupMargin = 30 * 1000; // Give extra 30 seconds of margin + + // delay a bit so regular sync sees it's up to date and sync is completed from the beginning + const genesisSlotsDelay = 8; + + const expectedDepositBlocks = 4; + + const timeout = + ((epochsOfMargin + expectedEpochsToFinish) * SLOTS_PER_EPOCH + genesisSlotsDelay) * + testParams.SECONDS_PER_SLOT * + 1000; + + this.timeout(timeout + 2 * timeoutSetupMargin); + + const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; + + const testLoggerOpts: TestLoggerOpts = { + level: LogLevel.info, + file: { + filepath: `${logFilesDir}/mergemock-${testName}.log`, + level: LogLevel.debug, + }, + timestampFormat: { + format: TimestampFormatCode.EpochSlot, + genesisTime, + slotsPerEpoch: SLOTS_PER_EPOCH, + secondsPerSlot: testParams.SECONDS_PER_SLOT, + }, + }; + const loggerNodeA = testLogger("Node-A", testLoggerOpts); + + const bn = await getDevBeaconNode({ + params: { + ...testParams, + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + EIP6110_FORK_EPOCH: eip6110Epoch, + TERMINAL_TOTAL_DIFFICULTY: ttd, + }, + options: { + api: {rest: {enabled: true} as BeaconRestApiServerOpts}, + sync: {isSingleNode: true}, + network: {allowPublishToZeroPeers: true, discv5: null}, + // Now eth deposit/merge tracker methods directly available on engine endpoints + eth1: {enabled: false, providerUrls: [engineRpcUrl], jwtSecretHex}, + executionEngine: {urls: [engineRpcUrl], jwtSecretHex}, + chain: {suggestedFeeRecipient: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, + }, + validatorCount: validatorClientCount * validatorsPerClient, + logger: loggerNodeA, + genesisTime, + eth1BlockHash: fromHexString(genesisBlockHash), + withEth1Credentials: true, + }); + + afterEachCallbacks.push(async function () { + await bn.close(); + await sleep(1000); + }); + + const stopInfoTracker = simTestInfoTracker(bn, loggerNodeA); + const valProposerConfig = { + defaultConfig: { + feeRecipient: "0xcccccccccccccccccccccccccccccccccccccccc", + }, + } as ValidatorProposerConfig; + + const {validators} = await getAndInitDevValidators({ + node: bn, + validatorsPerClient, + validatorClientCount, + startIndex: 0, + // At least one sim test must use the REST API for beacon <-> validator comms + useRestApi: true, + testLoggerOpts, + valProposerConfig, + }); + + + bn.chain.clock.on(ClockEvent.slot, (slot) => { + // send raw tx at slot 1 + console.log(slot); + if (slot === 1) { + const depositTransactionA = "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e) => { + throw Error(`Fail to send raw deposit transaction A: ${e.message}`); + }); + } + // Expect new validator to be in unfinalized cache, in state.validators and not in finalized cache + if (slot === 5) { + const headState = bn.chain.getHeadState(); + const epochCtx = headState.epochCtx; + console.log(`At slot 5: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}`); + if (headState.validators.length !== 33 || headState.balances.length !== 33) { + throw Error("New validator is not reflected in the beacon state."); + } + if (epochCtx.finalizedIndex2pubkey.length !== 32 || epochCtx.finalizedPubkey2index.size !== 32) { + throw Error("Finalized cache is modified."); + } + if (epochCtx.unfinalizedPubkey2index.size !== 1) { + throw Error(`Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}`) + } + } + }); + + afterEachCallbacks.push(async function () { + await Promise.all(validators.map((v) => v.close())); + }); + + await new Promise((resolve, _reject) => { + bn.chain.clock.on(ClockEvent.epoch, (epoch) => { + // Resolve only if the finalized checkpoint includes execution payload + if (epoch >= expectedEpochsToFinish) { + console.log("\nGot event epoch, stopping validators and nodes\n"); + resolve(); + } + }); + }); + + // Stop chain and un-subscribe events so the execution engine won't update it's head + // Allow some time to broadcast finalized events and complete the importBlock routine + await Promise.all(validators.map((v) => v.close())); + await bn.close(); + await sleep(500); + + // Check if new validator is in finalized cache + const headState = bn.chain.getHeadState(); + const epochCtx = headState.epochCtx; + console.log(`At slot 8: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}`); + + if (headState.validators.length !== 33 || headState.balances.length !== 33) { + throw Error("New validator is not reflected in the beacon state."); + } + if (epochCtx.finalizedIndex2pubkey.length !== 33 || epochCtx.finalizedPubkey2index.size !== 33) { + throw Error("New validator is not in finalized cache"); + } + if (!epochCtx.unfinalizedPubkey2index.isEmpty()) { + throw Error(`Unfinalized cache still contains new validator`); + } + + // wait for 1 slot to print current epoch stats + await sleep(1 * bn.config.SECONDS_PER_SLOT * 1000); + stopInfoTracker(); + console.log("\n\nDone\n\n"); } }); From 960a5bb5a1df8946261d39c8efab3f9868948cb6 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 12 Oct 2023 19:59:36 +0800 Subject: [PATCH 073/155] Lint --- .../beacon-node/test/sim/6110-interop.test.ts | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index f6744eea527..aac5a439bfb 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -1,27 +1,27 @@ import fs from "node:fs"; import {Context} from "mocha"; import _ from "lodash"; +import {fromHexString, toHexString} from "@chainsafe/ssz"; import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {eip6110, Epoch} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; +import {ChainConfig} from "@lodestar/config"; +import {TimestampFormatCode} from "@lodestar/logger"; import {initializeExecutionEngine} from "../../src/execution/index.js"; import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; import {testLogger, TestLoggerOpts} from "../utils/logger.js"; import {runEL, ELStartMode, ELClient, sendRawTransactionBig} from "../utils/runEl.js"; import {defaultExecutionEngineHttpOpts} from "../../src/execution/engine/http.js"; -import {shell} from "./shell.js"; import {getDevBeaconNode} from "../utils/node/beacon.js"; -import { ChainConfig } from "@lodestar/config"; -import { logFilesDir } from "./params.js"; -import { TimestampFormatCode } from "@lodestar/logger"; -import { BeaconRestApiServerOpts } from "../../src/api/index.js"; -import { fromHexString, toHexString } from "@chainsafe/ssz"; -import { simTestInfoTracker } from "../utils/node/simTest.js"; -import { getAndInitDevValidators } from "../utils/node/validator.js"; -import { ClockEvent } from "../../src/util/clock.js"; +import {BeaconRestApiServerOpts} from "../../src/api/index.js"; +import {simTestInfoTracker} from "../utils/node/simTest.js"; +import {getAndInitDevValidators} from "../utils/node/validator.js"; +import {ClockEvent} from "../../src/util/clock.js"; +import {logFilesDir} from "./params.js"; +import {shell} from "./shell.js"; // NOTE: How to run // DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:23.7.3 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts @@ -34,7 +34,6 @@ import { ClockEvent } from "../../src/util/clock.js"; const jwtSecretHex = "0xdc6457099f127cf0bac78de8b297df04951281909db4f58b43def7c7151e765d"; const retryAttempts = defaultExecutionEngineHttpOpts.retryAttempts; const retryDelay = defaultExecutionEngineHttpOpts.retryDelay; - describe("executionEngine / ExecutionEngineHttp", function () { if (!process.env.EL_BINARY_DIR || !process.env.EL_SCRIPT_DIR) { throw Error( @@ -132,11 +131,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { withdrawalCredentials: fromHexString("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca"), }; - sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e) => { + sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { throw Error(`Fail to send raw deposit transaction A: ${e.message}`); }); - sendRawTransactionBig(ethRpcUrl, depositTransactionB, `${dataPath}/deposit.json`).catch((e) => { + sendRawTransactionBig(ethRpcUrl, depositTransactionB, `${dataPath}/deposit.json`).catch((e: Error) => { throw Error(`Fail to send raw deposit transaction B: ${e.message}`); }); @@ -242,11 +241,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); // Want to test 2 things: - + /** * Want to test two things: * 1) Send two raw deposit transactions, and see if two new validators with corrent balances show up in the state.validators and unfinalized cache - * 2) Upon state-transition, see if the two new validators move from unfinalized cache to finalized cache + * 2) Upon state-transition, see if the two new validators move from unfinalized cache to finalized cache */ async function runNodeWithEL( this: Context, @@ -271,8 +270,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { // delay a bit so regular sync sees it's up to date and sync is completed from the beginning const genesisSlotsDelay = 8; - const expectedDepositBlocks = 4; - const timeout = ((epochsOfMargin + expectedEpochsToFinish) * SLOTS_PER_EPOCH + genesisSlotsDelay) * testParams.SECONDS_PER_SLOT * @@ -346,13 +343,13 @@ describe("executionEngine / ExecutionEngineHttp", function () { valProposerConfig, }); - bn.chain.clock.on(ClockEvent.slot, (slot) => { // send raw tx at slot 1 console.log(slot); if (slot === 1) { - const depositTransactionA = "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; - sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e) => { + const depositTransactionA = + "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { throw Error(`Fail to send raw deposit transaction A: ${e.message}`); }); } @@ -360,7 +357,9 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (slot === 5) { const headState = bn.chain.getHeadState(); const epochCtx = headState.epochCtx; - console.log(`At slot 5: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}`); + console.log( + `At slot 5: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}` + ); if (headState.validators.length !== 33 || headState.balances.length !== 33) { throw Error("New validator is not reflected in the beacon state."); } @@ -368,7 +367,9 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Finalized cache is modified."); } if (epochCtx.unfinalizedPubkey2index.size !== 1) { - throw Error(`Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}`) + throw Error( + `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` + ); } } }); @@ -396,7 +397,9 @@ describe("executionEngine / ExecutionEngineHttp", function () { // Check if new validator is in finalized cache const headState = bn.chain.getHeadState(); const epochCtx = headState.epochCtx; - console.log(`At slot 8: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}`); + console.log( + `At slot 8: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}` + ); if (headState.validators.length !== 33 || headState.balances.length !== 33) { throw Error("New validator is not reflected in the beacon state."); @@ -405,7 +408,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("New validator is not in finalized cache"); } if (!epochCtx.unfinalizedPubkey2index.isEmpty()) { - throw Error(`Unfinalized cache still contains new validator`); + throw Error("Unfinalized cache still contains new validator"); } // wait for 1 slot to print current epoch stats From 30ef95192e6e0bd3a9ce6f616ea939e360795e70 Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 13 Oct 2023 17:48:08 +0800 Subject: [PATCH 074/155] Merge branch 'unstable' into 611 --- packages/beacon-node/test/spec/utils/specTestIterator.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index a9310d53ac8..4b24bdd845e 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -56,7 +56,6 @@ const coveredTestRunners = [ // ], // ``` export const defaultSkipOpts: SkipOpts = { - skippedForks: ["eip6110"], // TODO: capella // BeaconBlockBody proof in lightclient is the new addition in v1.3.0-rc.2-hotfix // Skip them for now to enable subsequently From 9c45121971350cea90ffb3c53dc20bbde5d97a77 Mon Sep 17 00:00:00 2001 From: naviechan Date: Fri, 13 Oct 2023 21:28:14 +0800 Subject: [PATCH 075/155] Add more check to sim test --- packages/beacon-node/test/sim/6110-interop.test.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index aac5a439bfb..8b822df65ed 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -3,7 +3,7 @@ import {Context} from "mocha"; import _ from "lodash"; import {fromHexString, toHexString} from "@chainsafe/ssz"; import {LogLevel, sleep} from "@lodestar/utils"; -import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {eip6110, Epoch} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; @@ -22,6 +22,7 @@ import {getAndInitDevValidators} from "../utils/node/validator.js"; import {ClockEvent} from "../../src/util/clock.js"; import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; +import { CachedBeaconStateEIP6110 } from "@lodestar/state-transition"; // NOTE: How to run // DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:23.7.3 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts @@ -395,7 +396,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { await sleep(500); // Check if new validator is in finalized cache - const headState = bn.chain.getHeadState(); + const headState = bn.chain.getHeadState() as CachedBeaconStateEIP6110; const epochCtx = headState.epochCtx; console.log( `At slot 8: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}` @@ -411,6 +412,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Unfinalized cache still contains new validator"); } + console.log(`${headState.depositReceiptsStartIndex} === ${UNSET_DEPOSIT_RECEIPTS_START_INDEX}`); + if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { + throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt"); + } + // wait for 1 slot to print current epoch stats await sleep(1 * bn.config.SECONDS_PER_SLOT * 1000); stopInfoTracker(); From 8e4fb25cf32d310f04fd0e9bbd640fec96b4e06e Mon Sep 17 00:00:00 2001 From: naviechan Date: Fri, 13 Oct 2023 21:54:18 +0800 Subject: [PATCH 076/155] Update besu docker image instruction --- packages/beacon-node/test/sim/6110-interop.test.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 8b822df65ed..e9acebdcd23 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -25,7 +25,8 @@ import {shell} from "./shell.js"; import { CachedBeaconStateEIP6110 } from "@lodestar/state-transition"; // NOTE: How to run -// DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:23.7.3 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts +// DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:develop EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts +// TODO: Use a personal docker image instead of develop image from hyperledger // or // DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn mocha test/sim/6110-interop.test.ts // ``` @@ -256,10 +257,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { const validatorClientCount = 1; const validatorsPerClient = 32; - const testParams: Pick = { + const testParams: Pick = { SECONDS_PER_SLOT: 2, - GENESIS_FORK_VERSION: fromHexString("0x00000000"), - EIP6110_FORK_VERSION: fromHexString("0x60000060"), }; // Just finish the run within first epoch as we only need to test if withdrawals started @@ -412,7 +411,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Unfinalized cache still contains new validator"); } - console.log(`${headState.depositReceiptsStartIndex} === ${UNSET_DEPOSIT_RECEIPTS_START_INDEX}`); if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt"); } From 0abcf9ff4b94149ed2b81ca0eaeb3ce699a09f01 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 16 Oct 2023 16:46:16 +0800 Subject: [PATCH 077/155] Update sim test with correct tx --- packages/beacon-node/test/sim/6110-interop.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index e9acebdcd23..9e34d3fbc26 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -348,7 +348,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { console.log(slot); if (slot === 1) { const depositTransactionA = - "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"; + "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { throw Error(`Fail to send raw deposit transaction A: ${e.message}`); }); From dc71603b3d47083bd1ee6d29080aa93ae64682b3 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 16 Oct 2023 17:13:44 +0800 Subject: [PATCH 078/155] Address comment + cleanup --- .../beacon-node/test/sim/6110-interop.test.ts | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 9e34d3fbc26..f0013772e08 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -1,7 +1,6 @@ import fs from "node:fs"; import {Context} from "mocha"; import _ from "lodash"; -import {fromHexString, toHexString} from "@chainsafe/ssz"; import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {eip6110, Epoch} from "@lodestar/types"; @@ -23,6 +22,8 @@ import {ClockEvent} from "../../src/util/clock.js"; import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; import { CachedBeaconStateEIP6110 } from "@lodestar/state-transition"; +import { dataToBytes } from "../../src/eth1/provider/utils.js"; +import { bytesToData } from "../../lib/eth1/provider/utils.js"; // NOTE: How to run // DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:develop EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts @@ -89,10 +90,10 @@ describe("executionEngine / ExecutionEngineHttp", function () { const preparePayloadParams: PayloadAttributes = { // Note: this is created with a pre-defined genesis.json timestamp: 10, - prevRandao: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", withdrawals: [], - parentBeaconBlockRoot: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), + parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), }; const payloadId = await executionEngine.notifyForkchoiceUpdate( ForkName.eip6110, @@ -110,13 +111,15 @@ describe("executionEngine / ExecutionEngineHttp", function () { const depositReceiptA = { amount: 32000000000, index: 0, - pubkey: fromHexString( - "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9" + pubkey: dataToBytes( + "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9", + 48 ), - signature: fromHexString( - "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9" + signature: dataToBytes( + "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9", + 96 ), - withdrawalCredentials: fromHexString("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2"), + withdrawalCredentials: dataToBytes("0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2", 32), }; const depositTransactionB = @@ -124,13 +127,15 @@ describe("executionEngine / ExecutionEngineHttp", function () { const depositReceiptB = { amount: 32000000000, index: 1, - pubkey: fromHexString( - "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b" + pubkey: dataToBytes( + "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b", + 48 ), - signature: fromHexString( - "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1" + signature: dataToBytes( + "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1", + 96 ), - withdrawalCredentials: fromHexString("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca"), + withdrawalCredentials: dataToBytes("0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca", 32), }; sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { @@ -144,28 +149,29 @@ describe("executionEngine / ExecutionEngineHttp", function () { // 3. Import new payload with tx A and deposit receipt A const newPayloadBlockHash = "0xfd1189e6ea0814b7d40d4e50b31ae5feabbb2acff39399457bbdda7cb5ccd490"; const newPayload = { - parentHash: fromHexString("0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42"), - feeRecipient: fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"), - stateRoot: fromHexString("0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa"), - logsBloom: fromHexString( - "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000" + parentHash: dataToBytes("0x26118cf71453320edcebbc4ebb34af5b578087a32385b80108bf691fa23efc42", 32), + feeRecipient: dataToBytes("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 20), + stateRoot: dataToBytes("0x14208ac0e218167936e220b72d5d5887a963cb858ea2f2d268518f014a3da3fa", 32), + logsBloom: dataToBytes( + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", + 256 ), - prevRandao: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), gasLimit: 30000000, gasUsed: 84846, timestamp: 16, - extraData: fromHexString("0x"), + extraData: dataToBytes("0x", 0), baseFeePerGas: 7n, excessBlobGas: 0n, - transactions: [fromHexString(depositTransactionA)], + transactions: [dataToBytes(depositTransactionA, null)], withdrawals: [], depositReceipts: [depositReceiptA], blockNumber: 1, - blockHash: fromHexString(newPayloadBlockHash), - receiptsRoot: fromHexString("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9"), + blockHash: dataToBytes(newPayloadBlockHash, 32), + receiptsRoot: dataToBytes("0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", 32), blobGasUsed: 0n, }; - const parentBeaconBlockRoot = fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"); + const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); const payloadResult = await executionEngine.notifyNewPayload( ForkName.eip6110, newPayload, @@ -179,10 +185,10 @@ describe("executionEngine / ExecutionEngineHttp", function () { // 4. Update fork choice const preparePayloadParams2: PayloadAttributes = { timestamp: 48, - prevRandao: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), + prevRandao: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), suggestedFeeRecipient: "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", withdrawals: [], - parentBeaconBlockRoot: fromHexString("0x0000000000000000000000000000000000000000000000000000000000000000"), + parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), }; const payloadId2 = await executionEngine.notifyForkchoiceUpdate( @@ -205,7 +211,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (payload.transactions.length !== 1) { throw Error(`Number of transactions mismatched. Expected: 1, actual: ${payload.transactions.length}`); } else { - const actualTransaction = toHexString(payload.transactions[0]); + const actualTransaction = bytesToData(payload.transactions[0]); if (actualTransaction !== depositTransactionB) { throw Error(`Transaction mismatched. Expected: ${depositTransactionB}, actual: ${actualTransaction}`); @@ -242,8 +248,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); }); - // Want to test 2 things: - /** * Want to test two things: * 1) Send two raw deposit transactions, and see if two new validators with corrent balances show up in the state.validators and unfinalized cache @@ -316,7 +320,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { validatorCount: validatorClientCount * validatorsPerClient, logger: loggerNodeA, genesisTime, - eth1BlockHash: fromHexString(genesisBlockHash), + eth1BlockHash: dataToBytes(genesisBlockHash, 32), withEth1Credentials: true, }); @@ -345,7 +349,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { bn.chain.clock.on(ClockEvent.slot, (slot) => { // send raw tx at slot 1 - console.log(slot); if (slot === 1) { const depositTransactionA = "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; @@ -357,9 +360,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (slot === 5) { const headState = bn.chain.getHeadState(); const epochCtx = headState.epochCtx; - console.log( - `At slot 5: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}` - ); if (headState.validators.length !== 33 || headState.balances.length !== 33) { throw Error("New validator is not reflected in the beacon state."); } @@ -397,9 +397,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { // Check if new validator is in finalized cache const headState = bn.chain.getHeadState() as CachedBeaconStateEIP6110; const epochCtx = headState.epochCtx; - console.log( - `At slot 8: ${headState.validators.length}, ${headState.balances.length}, ${epochCtx.finalizedIndex2pubkey.length}, ${epochCtx.finalizedPubkey2index.size}, ${epochCtx.unfinalizedPubkey2index.size}` - ); if (headState.validators.length !== 33 || headState.balances.length !== 33) { throw Error("New validator is not reflected in the beacon state."); From 755d23aaf4846539468804d9c5c546a0a23be4ec Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 16 Oct 2023 17:15:09 +0800 Subject: [PATCH 079/155] Clean up code --- packages/beacon-node/test/sim/6110-interop.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index f0013772e08..e10488a843a 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -350,10 +350,10 @@ describe("executionEngine / ExecutionEngineHttp", function () { bn.chain.clock.on(ClockEvent.slot, (slot) => { // send raw tx at slot 1 if (slot === 1) { - const depositTransactionA = + const depositTransaction = "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; - sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { - throw Error(`Fail to send raw deposit transaction A: ${e.message}`); + sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`).catch((e: Error) => { + throw Error(`Fail to send raw deposit transaction: ${e.message}`); }); } // Expect new validator to be in unfinalized cache, in state.validators and not in finalized cache From 973b80b2cdd914d5888ac86e5b9eadce0a7c28ae Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 16 Oct 2023 18:02:53 +0800 Subject: [PATCH 080/155] Properly handle promise rejection --- .../beacon-node/test/sim/6110-interop.test.ts | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index e10488a843a..5a87ac3e543 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -81,9 +81,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { const {genesisBlockHash, engineRpcUrl, ethRpcUrl} = elClient; console.log({genesisBlockHash}); + const loggerExecutionEngine = testLogger("executionEngine"); + const executionEngine = initializeExecutionEngine( {mode: "http", urls: [engineRpcUrl], jwtSecretHex, retryAttempts, retryDelay}, - {signal: controller.signal, logger: testLogger("executionEngine")} + {signal: controller.signal, logger: loggerExecutionEngine} ); // 1. Prepare payload @@ -139,11 +141,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; sendRawTransactionBig(ethRpcUrl, depositTransactionA, `${dataPath}/deposit.json`).catch((e: Error) => { - throw Error(`Fail to send raw deposit transaction A: ${e.message}`); + loggerExecutionEngine.error("Fail to send raw deposit transaction A", undefined, e); }); sendRawTransactionBig(ethRpcUrl, depositTransactionB, `${dataPath}/deposit.json`).catch((e: Error) => { - throw Error(`Fail to send raw deposit transaction B: ${e.message}`); + loggerExecutionEngine.error("Fail to send raw deposit transaction B", undefined, e); }); // 3. Import new payload with tx A and deposit receipt A @@ -347,38 +349,35 @@ describe("executionEngine / ExecutionEngineHttp", function () { valProposerConfig, }); - bn.chain.clock.on(ClockEvent.slot, (slot) => { - // send raw tx at slot 1 - if (slot === 1) { - const depositTransaction = - "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; - sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`).catch((e: Error) => { - throw Error(`Fail to send raw deposit transaction: ${e.message}`); - }); - } - // Expect new validator to be in unfinalized cache, in state.validators and not in finalized cache - if (slot === 5) { - const headState = bn.chain.getHeadState(); - const epochCtx = headState.epochCtx; - if (headState.validators.length !== 33 || headState.balances.length !== 33) { - throw Error("New validator is not reflected in the beacon state."); - } - if (epochCtx.finalizedIndex2pubkey.length !== 32 || epochCtx.finalizedPubkey2index.size !== 32) { - throw Error("Finalized cache is modified."); - } - if (epochCtx.unfinalizedPubkey2index.size !== 1) { - throw Error( - `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` - ); - } - } - }); - afterEachCallbacks.push(async function () { await Promise.all(validators.map((v) => v.close())); }); - await new Promise((resolve, _reject) => { + await new Promise((resolve, reject) => { + bn.chain.clock.on(ClockEvent.slot, (slot) => { + // send raw tx at slot 1 + if (slot === 1) { + const depositTransaction = + "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; + sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`).catch((e: Error) => { + loggerNodeA.error("Fail to send raw deposit transaction", undefined, e); + }); + } + // Expect new validator to be in unfinalized cache, in state.validators and not in finalized cache + if (slot === 5) { + const headState = bn.chain.getHeadState(); + const epochCtx = headState.epochCtx; + if (headState.validators.length !== 33 || headState.balances.length !== 33) { + reject(Error("New validator is not reflected in the beacon state.")); + } + if (epochCtx.finalizedIndex2pubkey.length !== 32 || epochCtx.finalizedPubkey2index.size !== 32) { + reject(Error("Finalized cache is modified.")); + } + if (epochCtx.unfinalizedPubkey2index.size !== 1) { + reject(Error(`Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}`)); + } + } + }); bn.chain.clock.on(ClockEvent.epoch, (epoch) => { // Resolve only if the finalized checkpoint includes execution payload if (epoch >= expectedEpochsToFinish) { From 6a160d30e038e35362ef4ecd5b2cb2bc11b9648d Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 16 Oct 2023 18:05:01 +0800 Subject: [PATCH 081/155] Lint --- packages/beacon-node/test/sim/6110-interop.test.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 5a87ac3e543..d80d41d5d9e 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -8,6 +8,7 @@ import {ValidatorProposerConfig} from "@lodestar/validator"; import {ChainConfig} from "@lodestar/config"; import {TimestampFormatCode} from "@lodestar/logger"; +import {CachedBeaconStateEIP6110} from "@lodestar/state-transition"; import {initializeExecutionEngine} from "../../src/execution/index.js"; import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; @@ -19,11 +20,10 @@ import {BeaconRestApiServerOpts} from "../../src/api/index.js"; import {simTestInfoTracker} from "../utils/node/simTest.js"; import {getAndInitDevValidators} from "../utils/node/validator.js"; import {ClockEvent} from "../../src/util/clock.js"; +import {dataToBytes} from "../../src/eth1/provider/utils.js"; +import {bytesToData} from "../../lib/eth1/provider/utils.js"; import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; -import { CachedBeaconStateEIP6110 } from "@lodestar/state-transition"; -import { dataToBytes } from "../../src/eth1/provider/utils.js"; -import { bytesToData } from "../../lib/eth1/provider/utils.js"; // NOTE: How to run // DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:develop EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts @@ -263,7 +263,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { const validatorClientCount = 1; const validatorsPerClient = 32; - const testParams: Pick = { + const testParams: Pick = { SECONDS_PER_SLOT: 2, }; @@ -374,7 +374,11 @@ describe("executionEngine / ExecutionEngineHttp", function () { reject(Error("Finalized cache is modified.")); } if (epochCtx.unfinalizedPubkey2index.size !== 1) { - reject(Error(`Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}`)); + reject( + Error( + `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` + ) + ); } } }); From ad61461b1bd614ef6b52660a5bb68846796f646b Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 17 Oct 2023 16:26:13 +0800 Subject: [PATCH 082/155] Update packages/beacon-node/src/execution/engine/types.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> --- packages/beacon-node/src/execution/engine/types.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index dbdedc29aa7..5708da9c3da 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -303,9 +303,7 @@ export function parseExecutionPayload( `depositReceipts missing for ${fork} >= eip6110 executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as eip6110.ExecutionPayload).depositReceipts = depositReceipts.map((d) => - deserializeDepositReceipts(d) - ); + (executionPayload as eip6110.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipts); } return {executionPayload, blockValue, blobsBundle}; From c6d29eb339d46333947a815eefd2eabae7e8f655 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 17 Oct 2023 16:51:04 +0800 Subject: [PATCH 083/155] Update comments --- packages/state-transition/package.json | 2 +- packages/state-transition/src/cache/epochCache.ts | 6 ++++-- packages/state-transition/src/cache/pubkeyCache.ts | 1 - 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 67d7985afd2..5b68ca782ef 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -52,7 +52,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "test:unit": "mocha 'test/unit/**/deposit.test.ts'", + "test:unit": "mocha 'test/unit/**/*.test.ts'", "check-readme": "typescript-docs-verifier" }, "types": "lib/index.d.ts", diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 3fb441005ad..ea3561afb74 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -94,7 +94,8 @@ export class EpochCache { * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies * - * New: This would include only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. + * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is + * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued * * $VALIDATOR_COUNT x 192 char String -> Number Map */ @@ -102,7 +103,8 @@ export class EpochCache { /** * Unique globally shared pubkey registry. There should only exist one for the entire application. * - * New: This would include only validators whose activation_eligibility_epoch is finalized and hence it is insert only. Validators may still be in the activation queue. + * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is + * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 6725238651d..5e71b7124f7 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -62,7 +62,6 @@ export class PubkeyIndexMap { * * If pubkey caches are empty: SLOW CODE - 🐢 * - * TODO: Deal with this */ export function syncPubkeys( state: BeaconStateAllForks, From 38b3a7115466a35df9b7e9cfdf525fe967a99d27 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 17 Oct 2023 17:39:47 +0800 Subject: [PATCH 084/155] Accept type undefined in ExecutionPayloadBodyRpc --- packages/beacon-node/src/execution/engine/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 5708da9c3da..93daa55b68d 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -115,8 +115,8 @@ type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithBlo export type ExecutionPayloadBodyRpc = { transactions: DATA[]; - withdrawals: WithdrawalV1[] | null; - depositReceipts: DepositReceiptV1[] | null; + withdrawals: WithdrawalV1[] | null | undefined; + depositReceipts: DepositReceiptV1[] | null | undefined; }; export type ExecutionPayloadBody = { From adac370996278c8cbfaead6a15ca83f541fe76b7 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 17 Oct 2023 19:01:13 +0800 Subject: [PATCH 085/155] Update comment and semantic --- packages/state-transition/src/util/deposit.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index c7e636517f7..db0e52cd675 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -5,13 +5,15 @@ import {CachedBeaconStateAllForks, CachedBeaconStateEIP6110} from "../types.js"; export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 { if (state.config.getForkSeq(state.slot) >= ForkSeq.eip6110) { const eip6110State = state as CachedBeaconStateEIP6110; + // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 + // since the result lies within upper and lower bound of UintNum64 const eth1DataIndexLimit = - state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex + (state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex ? state.eth1Data.depositCount - : eip6110State.depositReceiptsStartIndex; + : eip6110State.depositReceiptsStartIndex) as UintNum64; if (state.eth1DepositIndex < eth1DataIndexLimit) { - return Math.min(MAX_DEPOSITS, Number(eth1DataIndexLimit) - state.eth1DepositIndex); // eth1DataIndexLimit can be safely casted as number + return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); } else { return 0; } From 3a8e76f16bd6b1ed184dbf042b18b5f02bc4d3e7 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 17 Oct 2023 20:25:29 +0800 Subject: [PATCH 086/155] Remove if statement when adding finalized validator --- packages/state-transition/src/cache/epochCache.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index ea3561afb74..04d822425f3 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -506,7 +506,6 @@ export class EpochCache { ): void { this.previousShuffling = this.currentShuffling; this.currentShuffling = this.nextShuffling; - const prevEpoch = this.previousShuffling.epoch; const currEpoch = this.currentShuffling.epoch; const nextEpoch = currEpoch + 1; @@ -574,17 +573,13 @@ export class EpochCache { this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); - // To populate finalized cache and prune unfinalized cache with validators that just entered the activation queue + // To populate finalized cache and prune unfinalized cache with validators that are just initialized if (this.isAfterEIP6110()) { - const expectedActivationEligibilityEpoch = prevEpoch + 1; + const expectedActivationEligibilityEpoch = currEpoch; const validators = state.validators; for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { const validator = validators.getReadonly(index); - if (validator.activationEligibilityEpoch == expectedActivationEligibilityEpoch) { - this.addFinalizedPubkey(validator.pubkey, index); - } else { - break; - } + this.addFinalizedPubkey(validator.pubkey, index); } } } From 8e3b1b604a9be47cd85e0ef81fd3a18c967f2d3c Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 17 Oct 2023 20:54:41 +0800 Subject: [PATCH 087/155] Comment on repeated insert on finalized cache --- .../state-transition/src/cache/epochCache.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 04d822425f3..aa758b006bc 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -575,7 +575,6 @@ export class EpochCache { // To populate finalized cache and prune unfinalized cache with validators that are just initialized if (this.isAfterEIP6110()) { - const expectedActivationEligibilityEpoch = currEpoch; const validators = state.validators; for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { const validator = validators.getReadonly(index); @@ -799,7 +798,7 @@ export class EpochCache { /** * - * Given a validator whose activation_epoch has just been set, we move its pubkey from unfinalized cache to finalized cache + * Given a validator whose activationEligibilityEpoch has just been set, we move its pubkey from unfinalized cache to finalized cache * */ addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { @@ -807,8 +806,18 @@ export class EpochCache { throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } - if (this.finalizedPubkey2index.get(pubkey) !== undefined) { - return; // Repeated insert. Should not happen except 6110 activation + const existingIndex = this.finalizedPubkey2index.get(pubkey); + + if (existingIndex != undefined) { + if (existingIndex === index){ + // Repeated insert. Should not happen except during the first few epochs of 6110 activation + // Unfinalized validator added to finalizedPubkey2index pre-6110 by calling addPubkey() + // when it become finalized in post-6110, addFinalizedPubkey() is called to cause repeated insert + return; + } else { + // attempt to insert the same pubkey with different index, should never happen. + throw Error("inserted existing pubkey into finalizedPubkey2index cache with a different index") + } } this.finalizedPubkey2index.set(pubkey, index); From c024a00813e4524a2947ae0028d19fef432884d4 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 18 Oct 2023 16:45:23 +0800 Subject: [PATCH 088/155] rename createFromState --- packages/state-transition/src/cache/epochCache.ts | 6 +++--- packages/state-transition/src/cache/stateCache.ts | 2 +- packages/state-transition/src/slot/upgradeStateToAltair.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index aa758b006bc..3691aff58b9 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -266,11 +266,11 @@ export class EpochCache { /** * Create an epoch cache - * @param validators cached validators that matches `state.validators` + * @param state a finalized beacon state. Passing in unfinalized state may cause unexpected behaviour eg. empty unfinalized cache * * SLOW CODE - 🐢 */ - static createFromState( + static createFromFinalizedState( state: BeaconStateAllForks, {config, finalizedPubkey2index, finalizedIndex2pubkey}: EpochCacheImmutableData, opts?: EpochCacheOpts @@ -423,7 +423,7 @@ export class EpochCache { config, finalizedPubkey2index, finalizedIndex2pubkey, - // `createFromState()` creates cache with empty unfinalizedPubkey2index. Be cautious to only pass in finalized state + // `createFromFinalizedState()` creates cache with empty unfinalizedPubkey2index. Be cautious to only pass in finalized state unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), proposers, // On first epoch, set to null to prevent unnecessary work since this is only used for metrics diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 25230100c03..0b692189ec6 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -143,7 +143,7 @@ export function createCachedBeaconState( ): T & BeaconStateCache { return getCachedBeaconState(state, { config: immutableData.config, - epochCtx: EpochCache.createFromState(state, immutableData, opts), + epochCtx: EpochCache.createFromFinalizedState(state, immutableData, opts), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, diff --git a/packages/state-transition/src/slot/upgradeStateToAltair.ts b/packages/state-transition/src/slot/upgradeStateToAltair.ts index 0afa43930ef..ef270019cc5 100644 --- a/packages/state-transition/src/slot/upgradeStateToAltair.ts +++ b/packages/state-transition/src/slot/upgradeStateToAltair.ts @@ -99,7 +99,7 @@ export function upgradeStateToAltair(statePhase0: CachedBeaconStatePhase0): Cach // currentTargetUnslashedBalanceIncrements is rotated to previousTargetUnslashedBalanceIncrements // // Here target balance is computed in full, which is slightly less performant than doing so in the loop - // above but gurantees consistency with EpochCache.createFromState(). Note execution order below: + // above but gurantees consistency with EpochCache.createFromFinalizedState(). Note execution order below: // ``` // processEpoch() // epochCtx.afterProcessEpoch() From ce377f6da95931e5d29c2563320b5c9d7d8a1a13 Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 18 Oct 2023 16:57:29 +0800 Subject: [PATCH 089/155] Add comment on getPubkey() --- packages/state-transition/src/cache/epochCache.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 3691aff58b9..1880c9a7c11 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -768,6 +768,12 @@ export class EpochCache { return isAggregatorFromCommitteeLength(committee.length, slotSignature); } + /** + * Return finalized pubkey given the validator index. + * Only finalized pubkey as we do not store unfinalized pubkey because no where in the spec has a + * need to make such enquiry + * + */ getPubkey(index: ValidatorIndex): PublicKey { return this.finalizedIndex2pubkey[index]; } From 29a1fa46b2a4a25a8fdf6bf4e310e853754de2b7 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 19:41:09 +0800 Subject: [PATCH 090/155] Stash change to reduce diffs --- .../src/api/impl/beacon/state/index.ts | 12 ++-- .../src/api/impl/beacon/state/utils.ts | 10 ++-- .../src/api/impl/validator/index.ts | 2 +- packages/beacon-node/src/chain/chain.ts | 10 ++-- .../src/chain/validation/aggregateAndProof.ts | 2 +- .../signatureSets/contributionAndProof.ts | 2 +- .../validation/signatureSets/syncCommittee.ts | 2 +- .../syncCommitteeSelectionProof.ts | 2 +- .../syncCommitteeContributionAndProof.ts | 4 +- .../beacon-node/test/sim/6110-interop.test.ts | 4 +- .../unit/api/impl/beacon/state/utils.test.ts | 16 ++--- packages/beacon-node/test/utils/state.ts | 12 ++-- .../test/utils/validationData/attestation.ts | 4 +- .../unit/isValidLightClientHeader.test.ts | 34 +---------- .../src/block/processDeposit.ts | 2 +- .../src/block/processExecutionPayload.ts | 12 ++-- .../src/block/processSyncCommittee.ts | 2 +- .../state-transition/src/cache/epochCache.ts | 60 +++++++++---------- .../state-transition/src/cache/pubkeyCache.ts | 1 - .../state-transition/src/cache/stateCache.ts | 3 +- .../src/signatureSets/attesterSlashings.ts | 2 +- .../src/signatureSets/indexedAttestation.ts | 2 +- .../src/signatureSets/proposer.ts | 4 +- .../src/signatureSets/proposerSlashings.ts | 2 +- .../src/signatureSets/randao.ts | 2 +- .../src/signatureSets/voluntaryExits.ts | 2 +- .../src/slot/upgradeStateToAltair.ts | 2 +- packages/state-transition/src/util/deposit.ts | 6 +- packages/state-transition/src/util/genesis.ts | 4 +- packages/state-transition/test/perf/util.ts | 12 ++-- .../test/unit/cachedBeaconState.test.ts | 8 +-- .../test/unit/upgradeState.test.ts | 8 +-- .../test/unit/util/cachedBeaconState.test.ts | 4 +- packages/state-transition/test/utils/state.ts | 8 +-- 34 files changed, 114 insertions(+), 148 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index e38d0cda114..54d663234af 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -59,12 +59,12 @@ export function getBeaconStateApi({ const {state, executionOptimistic} = await resolveStateId(chain, stateId); const currentEpoch = getCurrentEpoch(state); const {validators, balances} = state; // Get the validators sub tree once for all the loop - const epochCache = chain.getHeadState().epochCtx; + const {pubkey2index} = chain.getHeadState().epochCtx; const validatorResponses: routes.beacon.ValidatorResponse[] = []; if (filters?.id) { for (const id of filters.id) { - const resp = getStateValidatorIndex(id, state, epochCache); + const resp = getStateValidatorIndex(id, state, pubkey2index); if (resp.valid) { const validatorIndex = resp.validatorIndex; const validator = validators.getReadonly(validatorIndex); @@ -85,7 +85,7 @@ export function getBeaconStateApi({ data: validatorResponses, }; } else if (filters?.status) { - const validatorsByStatus = filterStateValidatorsByStatus(filters.status, state, epochCache, currentEpoch); + const validatorsByStatus = filterStateValidatorsByStatus(filters.status, state, pubkey2index, currentEpoch); return { executionOptimistic, data: validatorsByStatus, @@ -108,9 +108,9 @@ export function getBeaconStateApi({ async getStateValidator(stateId, validatorId) { const {state, executionOptimistic} = await resolveStateId(chain, stateId); - const epochCache = chain.getHeadState().epochCtx; + const {pubkey2index} = chain.getHeadState().epochCtx; - const resp = getStateValidatorIndex(validatorId, state, epochCache); + const resp = getStateValidatorIndex(validatorId, state, pubkey2index); if (!resp.valid) { throw new ApiError(resp.code, resp.reason); } @@ -140,7 +140,7 @@ export function getBeaconStateApi({ } balances.push({index: id, balance: state.balances.get(id)}); } else { - const index = headState.epochCtx.getValidatorIndex(id); + const index = headState.epochCtx.pubkey2index.get(id); if (index != null && index <= state.validators.length) { balances.push({index, balance: state.balances.get(index)}); } diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index c4fd69697ba..48bcf66c715 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -1,7 +1,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {routes} from "@lodestar/api"; import {FAR_FUTURE_EPOCH, GENESIS_SLOT} from "@lodestar/params"; -import {BeaconStateAllForks} from "@lodestar/state-transition"; +import {BeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {BLSPubkey, phase0} from "@lodestar/types"; import {Epoch, ValidatorIndex} from "@lodestar/types"; import {EpochCache} from "@lodestar/state-transition/src/types.js"; @@ -112,7 +112,7 @@ export function toValidatorResponse( export function filterStateValidatorsByStatus( statuses: string[], state: BeaconStateAllForks, - epochCache: EpochCache, + pubkey2index: PubkeyIndexMap, currentEpoch: Epoch ): routes.beacon.ValidatorResponse[] { const responses: routes.beacon.ValidatorResponse[] = []; @@ -122,7 +122,7 @@ export function filterStateValidatorsByStatus( for (const validator of validatorsArr) { const validatorStatus = getValidatorStatus(validator, currentEpoch); - const resp = getStateValidatorIndex(validator.pubkey, state, epochCache); + const resp = getStateValidatorIndex(validator.pubkey, state, pubkey2index); if (resp.valid && statusSet.has(validatorStatus)) { responses.push( toValidatorResponse(resp.validatorIndex, validator, state.balances.get(resp.validatorIndex), currentEpoch) @@ -137,7 +137,7 @@ type StateValidatorIndexResponse = {valid: true; validatorIndex: number} | {vali export function getStateValidatorIndex( id: routes.beacon.ValidatorId | BLSPubkey, state: BeaconStateAllForks, - epochCache: EpochCache + pubkey2index: PubkeyIndexMap ): StateValidatorIndexResponse { let validatorIndex: ValidatorIndex | undefined; if (typeof id === "string") { @@ -162,7 +162,7 @@ export function getStateValidatorIndex( } // typeof id === Uint8Array - validatorIndex = epochCache.getValidatorIndex(id as BLSPubkey); + validatorIndex = pubkey2index.get(id as BLSPubkey); if (validatorIndex === undefined) { return {valid: false, code: 404, reason: "Validator pubkey not found in state"}; } diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index b4d8df7d957..c827e121da6 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -827,7 +827,7 @@ export function getValidatorApi({ const filteredRegistrations = registrations.filter((registration) => { const {pubkey} = registration.message; - const validatorIndex = headState.epochCtx.getValidatorIndex(pubkey); + const validatorIndex = headState.epochCtx.pubkey2index.get(pubkey); if (validatorIndex === undefined) return false; const validator = headState.validators.getReadonly(validatorIndex); diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 1a713ce6e4e..edfab4eb689 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -221,13 +221,13 @@ export class BeaconChain implements IBeaconChain { ? anchorState : createCachedBeaconState(anchorState, { config, - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }); // Persist single global instance of state caches - this.pubkey2index = cachedState.epochCtx.finalizedPubkey2index; - this.index2pubkey = cachedState.epochCtx.finalizedIndex2pubkey; + this.pubkey2index = cachedState.epochCtx.pubkey2index; + this.index2pubkey = cachedState.epochCtx.index2pubkey; const stateCache = new StateContextCache({metrics}); const checkpointStateCache = new CheckpointStateCache({metrics}); @@ -484,7 +484,7 @@ export class BeaconChain implements IBeaconChain { ); const parentBlockRoot = fromHexString(head.blockRoot); const proposerIndex = state.epochCtx.getBeaconProposer(slot); - const proposerPubKey = state.epochCtx.getPubkey(proposerIndex).toBytes(); + const proposerPubKey = state.epochCtx.index2pubkey[proposerIndex].toBytes(); const {body, blobs, blockValue} = await produceBlockBody.call(this, blockType, state, { randaoReveal, diff --git a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts index 31625508f7f..0cd96a8278e 100644 --- a/packages/beacon-node/src/chain/validation/aggregateAndProof.ts +++ b/packages/beacon-node/src/chain/validation/aggregateAndProof.ts @@ -185,7 +185,7 @@ async function validateAggregateAndProof( // by the validator with index aggregate_and_proof.aggregator_index. // [REJECT] The aggregator signature, signed_aggregate_and_proof.signature, is valid. // [REJECT] The signature of aggregate is valid. - const aggregator = attHeadState.epochCtx.getPubkey(aggregateAndProof.aggregatorIndex); + const aggregator = attHeadState.epochCtx.index2pubkey[aggregateAndProof.aggregatorIndex]; let indexedAttestationSignatureSet: ISignatureSet; if (cachedAttData) { const {signingRoot} = cachedAttData; diff --git a/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts index 2a46dd048b0..21e447b8367 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/contributionAndProof.ts @@ -20,7 +20,7 @@ export function getContributionAndProofSignatureSet( const signingData = signedContributionAndProof.message; return { type: SignatureSetType.single, - pubkey: epochCtx.getPubkey(signedContributionAndProof.message.aggregatorIndex), + pubkey: epochCtx.index2pubkey[signedContributionAndProof.message.aggregatorIndex], signingRoot: computeSigningRoot(ssz.altair.ContributionAndProof, signingData, domain), signature: signedContributionAndProof.signature, }; diff --git a/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts b/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts index e82382eda5c..ce2b2e2484a 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/syncCommittee.ts @@ -15,7 +15,7 @@ export function getSyncCommitteeSignatureSet( return { type: SignatureSetType.single, - pubkey: state.epochCtx.getPubkey(syncCommittee.validatorIndex), + pubkey: state.epochCtx.index2pubkey[syncCommittee.validatorIndex], signingRoot: computeSigningRoot(ssz.Root, syncCommittee.beaconBlockRoot, domain), signature: syncCommittee.signature, }; diff --git a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts index fe17946dcc0..14fcfad2b92 100644 --- a/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +++ b/packages/beacon-node/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts @@ -20,7 +20,7 @@ export function getSyncCommitteeSelectionProofSignatureSet( }; return { type: SignatureSetType.single, - pubkey: epochCtx.getPubkey(contributionAndProof.aggregatorIndex), + pubkey: epochCtx.index2pubkey[contributionAndProof.aggregatorIndex], signingRoot: computeSigningRoot(ssz.altair.SyncAggregatorSelectionData, signingData, domain), signature: contributionAndProof.selectionProof, }; diff --git a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts index 58953e5206f..3f9351f2d0d 100644 --- a/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts +++ b/packages/beacon-node/src/chain/validation/syncCommitteeContributionAndProof.ts @@ -73,8 +73,8 @@ export async function validateSyncCommitteeGossipContributionAndProof( // i.e. state.validators[contribution_and_proof.aggregator_index].pubkey in get_sync_subcommittee_pubkeys(state, contribution.subcommittee_index). // > Checked in validateGossipSyncCommitteeExceptSig() - const participantPubkeys = syncCommitteeParticipantIndices.map((validatorIndex) => - headState.epochCtx.getPubkey(validatorIndex) + const participantPubkeys = syncCommitteeParticipantIndices.map( + (validatorIndex) => headState.epochCtx.index2pubkey[validatorIndex] ); const signatureSets = [ // [REJECT] The contribution_and_proof.selection_proof is a valid signature of the SyncAggregatorSelectionData diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index d80d41d5d9e..e3a6967ac21 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -370,7 +370,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (headState.validators.length !== 33 || headState.balances.length !== 33) { reject(Error("New validator is not reflected in the beacon state.")); } - if (epochCtx.finalizedIndex2pubkey.length !== 32 || epochCtx.finalizedPubkey2index.size !== 32) { + if (epochCtx.index2pubkey.length !== 32 || epochCtx.pubkey2index.size !== 32) { reject(Error("Finalized cache is modified.")); } if (epochCtx.unfinalizedPubkey2index.size !== 1) { @@ -404,7 +404,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (headState.validators.length !== 33 || headState.balances.length !== 33) { throw Error("New validator is not reflected in the beacon state."); } - if (epochCtx.finalizedIndex2pubkey.length !== 33 || epochCtx.finalizedPubkey2index.size !== 33) { + if (epochCtx.index2pubkey.length !== 33 || epochCtx.pubkey2index.size !== 33) { throw Error("New validator is not in finalized cache"); } if (!epochCtx.unfinalizedPubkey2index.isEmpty()) { diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index 5b393521c28..d6afcbcfb6f 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -104,38 +104,38 @@ describe("beacon state api utils", function () { describe("getStateValidatorIndex", async function () { const state = generateCachedAltairState(); - const epochCache = state.epochCtx; + const pubkey2index = state.epochCtx.pubkey2index; it("should return valid: false on invalid input", () => { // "invalid validator id number" - expect(getStateValidatorIndex("foo", state, epochCache).valid).toBe(false); + expect(getStateValidatorIndex("foo", state, pubkey2index).valid).toBe(false); // "invalid hex" - expect(getStateValidatorIndex("0xfoo", state, epochCache).valid).toBe(false); + expect(getStateValidatorIndex("0xfoo", state, pubkey2index).valid).toBe(false); }); it("should return valid: false on validator indices / pubkeys not in the state", () => { // "validator id not in state" - expect(getStateValidatorIndex(String(state.validators.length), state, epochCache).valid).toBe(false); + expect(getStateValidatorIndex(String(state.validators.length), state, pubkey2index).valid).toBe(false); // "validator pubkey not in state" - expect(getStateValidatorIndex("0xabcd", state, epochCache).valid).toBe(false); + expect(getStateValidatorIndex("0xabcd", state, pubkey2index).valid).toBe(false); }); it("should return valid: true on validator indices / pubkeys in the state", () => { const index = state.validators.length - 1; - const resp1 = getStateValidatorIndex(String(index), state, epochCache); + const resp1 = getStateValidatorIndex(String(index), state, pubkey2index); if (resp1.valid) { expect(resp1.validatorIndex).toBe(index); } else { expect.fail("validator index should be found - validator index input"); } const pubkey = state.validators.get(index).pubkey; - const resp2 = getStateValidatorIndex(pubkey, state, epochCache); + const resp2 = getStateValidatorIndex(pubkey, state, pubkey2index); if (resp2.valid) { expect(resp2.validatorIndex).toBe(index); } else { expect.fail("validator index should be found - Uint8Array input"); } - const resp3 = getStateValidatorIndex(toHexString(pubkey), state, epochCache); + const resp3 = getStateValidatorIndex(toHexString(pubkey), state, pubkey2index); if (resp3.valid) { expect(resp3.validatorIndex).toBe(index); } else { diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index e196a5fba7b..429349da2f5 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -107,8 +107,8 @@ export function generateCachedState(opts?: TestBeaconState): CachedBeaconStateAl return createCachedBeaconState(state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a performance test, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }); } @@ -121,8 +121,8 @@ export function generateCachedAltairState(opts?: TestBeaconState, altairForkEpoc return createCachedBeaconState(state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a performance test, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }); } @@ -135,7 +135,7 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac return createCachedBeaconState(state as BeaconStateBellatrix, { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a performance test, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }); } diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index 1ba5e99337b..6f768227e5c 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -9,7 +9,7 @@ import { generateTestCachedBeaconStateOnlyValidators, getSecretKeyFromIndexCached, // eslint-disable-next-line import/no-relative-packages -} from "@lodestar/state-transition"; +} from "../../../../state-transition/test/perf/util.js"; import {IBeaconChain} from "../../../src/chain/index.js"; import {IStateRegenerator} from "../../../src/chain/regen/index.js"; import {ZERO_HASH, ZERO_HASH_HEX} from "../../../src/constants/index.js"; @@ -131,7 +131,7 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { ? new BlsSingleThreadVerifier({metrics: null}) : new BlsMultiThreadWorkerPool({}, {logger: testLogger(), metrics: null}), waitForBlock: () => Promise.resolve(false), - index2pubkey: state.epochCtx.finalizedIndex2pubkey, + index2pubkey: state.epochCtx.index2pubkey, opts: defaultChainOptions, } as Partial as IBeaconChain; diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index fa30bf58d78..b24578d1611 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -10,9 +10,8 @@ describe("isValidLightClientHeader", function () { ...defaultChainConfig, ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, - CAPELLA_FORK_EPOCH: 0, - DENEB_FORK_EPOCH: 1, - EIP6110_FORK_EPOCH: Infinity, + CAPELLA_FORK_EPOCH: 1, + DENEB_FORK_EPOCH: Infinity, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); @@ -40,12 +39,6 @@ describe("isValidLightClientHeader", function () { executionBranch: ssz.deneb.LightClientHeader.fields.executionBranch.defaultValue(), }; - const altairUpgradedEIP6110LCHeader = { - beacon: altairLCHeader.beacon, - execution: ssz.eip6110.LightClientHeader.fields.execution.defaultValue(), - executionBranch: ssz.eip6110.LightClientHeader.fields.executionBranch.defaultValue(), - }; - const capellaLCHeader = { beacon: { slot: 100936, @@ -87,35 +80,12 @@ describe("isValidLightClientHeader", function () { executionBranch: capellaLCHeader.executionBranch, }; - const capellaUpgradedEIP6110Header = { - beacon: capellaLCHeader.beacon, - execution: { - ...capellaLCHeader.execution, - blobGasUsed: 0, - excessBlobGas: 0, - depositReceiptsRoot: new ByteVectorType(32), - }, - executionBranch: capellaLCHeader.executionBranch, - }; - - const denebLCHeader = { - // TODO 6110: Find a denebLCHeader - }; - - const denebUpgradedEIP6110Header = { - // TODO 6110: Find a denebLCHeader - }; - const testCases: [string, allForks.LightClientHeader][] = [ ["altair LC header", altairLCHeader], ["altair upgraded to capella", altairUpgradedCapellaLCHeader], ["altair upgraded to deneb", altairUpgradedDenebLCHeader], - ["altair upgraded to eip6110", altairUpgradedDenebLCHeader], ["capella LC header", capellaLCHeader], ["capella upgraded to deneb LC header", capellaUpgradedDenebHeader], - ["capella upgraded to eip6110 LC header", capellaUpgradedEIP6110Header], - // ["deneb LC header", denebLCHeader], - // ["deneb upgraded to eip6110 LC header", denebUpgradedDenebHeader], ]; testCases.forEach(([name, header]: [string, allForks.LightClientHeader]) => { diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index fa74c638d47..1305826da96 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -117,7 +117,7 @@ function addValidatorToRegistry( epochCtx.effectiveBalanceIncrementsSet(validatorIndex, effectiveBalance); // now that there is a new validator, update the epoch context with the new pubkey - epochCtx.addPubkey(pubkey, validatorIndex); + epochCtx.addPubkey(validatorIndex, pubkey); // Only after altair: if (fork >= ForkSeq.altair) { diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index efc269bc9e0..347cd67bfab 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -84,7 +84,7 @@ export function executionPayloadToPayloadHeader( ): allForks.ExecutionPayloadHeader { const transactionsRoot = ssz.bellatrix.Transactions.hashTreeRoot(payload.transactions); - const payloadFields: allForks.ExecutionPayloadHeader = { // Starts off with bellatrix payload fields as the base + const bellatrixPayloadFields: allForks.ExecutionPayloadHeader = { parentHash: payload.parentHash, feeRecipient: payload.feeRecipient, stateRoot: payload.stateRoot, @@ -102,26 +102,26 @@ export function executionPayloadToPayloadHeader( }; if (fork >= ForkSeq.capella) { - (payloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot( + (bellatrixPayloadFields as capella.ExecutionPayloadHeader).withdrawalsRoot = ssz.capella.Withdrawals.hashTreeRoot( (payload as capella.ExecutionPayload).withdrawals ); } if (fork >= ForkSeq.deneb) { // https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#process_execution_payload - (payloadFields as deneb.ExecutionPayloadHeader).blobGasUsed = ( + (bellatrixPayloadFields as deneb.ExecutionPayloadHeader).blobGasUsed = ( payload as deneb.ExecutionPayloadHeader | deneb.ExecutionPayload ).blobGasUsed; - (payloadFields as deneb.ExecutionPayloadHeader).excessBlobGas = ( + (bellatrixPayloadFields as deneb.ExecutionPayloadHeader).excessBlobGas = ( payload as deneb.ExecutionPayloadHeader | deneb.ExecutionPayload ).excessBlobGas; } if (fork >= ForkSeq.eip6110) { - (payloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = ssz.eip6110.DepositReceipts.hashTreeRoot( + (bellatrixPayloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = ssz.eip6110.DepositReceipts.hashTreeRoot( (payload as eip6110.ExecutionPayload).depositReceipts ); } - return payloadFields; + return bellatrixPayloadFields; } diff --git a/packages/state-transition/src/block/processSyncCommittee.ts b/packages/state-transition/src/block/processSyncCommittee.ts index 75bd07c4cc5..e0bfc318e05 100644 --- a/packages/state-transition/src/block/processSyncCommittee.ts +++ b/packages/state-transition/src/block/processSyncCommittee.ts @@ -104,7 +104,7 @@ export function getSyncCommitteeSignatureSet( return { type: SignatureSetType.aggregate, - pubkeys: participantIndices.map((i) => epochCtx.getPubkey(i)), + pubkeys: participantIndices.map((i) => epochCtx.index2pubkey[i]), signingRoot: computeSigningRoot(ssz.Root, rootSigned, domain), signature, }; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 1880c9a7c11..1780b8c684e 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -52,8 +52,8 @@ export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PR export type EpochCacheImmutableData = { config: BeaconConfig; - finalizedPubkey2index: PubkeyIndexMap; - finalizedIndex2pubkey: Index2PubkeyCache; + pubkey2index: PubkeyIndexMap; + index2pubkey: Index2PubkeyCache; }; export type EpochCacheOpts = { @@ -89,7 +89,7 @@ type ProposersDeferred = {computed: false; seed: Uint8Array} | {computed: true; export class EpochCache { config: BeaconConfig; /** - * Unique globally shared pubkey registry. There should only exist one for the entire application. + * Unique globally shared finalized pubkey registry. There should only exist one for the entire application. * * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies @@ -99,16 +99,16 @@ export class EpochCache { * * $VALIDATOR_COUNT x 192 char String -> Number Map */ - finalizedPubkey2index: PubkeyIndexMap; + pubkey2index: PubkeyIndexMap; /** - * Unique globally shared pubkey registry. There should only exist one for the entire application. + * Unique globally shared finalized pubkey registry. There should only exist one for the entire application. * * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) */ - finalizedIndex2pubkey: Index2PubkeyCache; + index2pubkey: Index2PubkeyCache; /** * Unique pubkey registry shared in the same fork. There should only exist one for the fork. */ @@ -212,8 +212,8 @@ export class EpochCache { constructor(data: { config: BeaconConfig; - finalizedPubkey2index: PubkeyIndexMap; - finalizedIndex2pubkey: Index2PubkeyCache; + pubkey2index: PubkeyIndexMap; + index2pubkey: Index2PubkeyCache; unfinalizedPubkey2index: UnfinalizedPubkeyIndexMap; proposers: number[]; proposersPrevEpoch: number[] | null; @@ -238,8 +238,8 @@ export class EpochCache { syncPeriod: SyncPeriod; }) { this.config = data.config; - this.finalizedPubkey2index = data.finalizedPubkey2index; - this.finalizedIndex2pubkey = data.finalizedIndex2pubkey; + this.pubkey2index = data.pubkey2index; + this.index2pubkey = data.index2pubkey; this.unfinalizedPubkey2index = data.unfinalizedPubkey2index; this.proposers = data.proposers; this.proposersPrevEpoch = data.proposersPrevEpoch; @@ -270,15 +270,15 @@ export class EpochCache { * * SLOW CODE - 🐢 */ - static createFromFinalizedState( + static createFromState( state: BeaconStateAllForks, - {config, finalizedPubkey2index, finalizedIndex2pubkey}: EpochCacheImmutableData, + {config, pubkey2index, index2pubkey}: EpochCacheImmutableData, opts?: EpochCacheOpts ): EpochCache { // syncPubkeys here to ensure EpochCacheImmutableData is popualted before computing the rest of caches // - computeSyncCommitteeCache() needs a fully populated pubkey2index cache if (!opts?.skipSyncPubkeys) { - syncPubkeys(state, finalizedPubkey2index, finalizedIndex2pubkey); + syncPubkeys(state, pubkey2index, index2pubkey); } const currentEpoch = computeEpochAtSlot(state.slot); @@ -368,8 +368,8 @@ export class EpochCache { // Allow to skip populating sync committee for initializeBeaconStateFromEth1() if (afterAltairFork && !opts?.skipSyncCommitteeCache) { const altairState = state as BeaconStateAltair; - currentSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.currentSyncCommittee, finalizedPubkey2index); - nextSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.nextSyncCommittee, finalizedPubkey2index); + currentSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.currentSyncCommittee, pubkey2index); + nextSyncCommitteeIndexed = computeSyncCommitteeCache(altairState.nextSyncCommittee, pubkey2index); } else { currentSyncCommitteeIndexed = new SyncCommitteeCacheEmpty(); nextSyncCommitteeIndexed = new SyncCommitteeCacheEmpty(); @@ -421,8 +421,8 @@ export class EpochCache { return new EpochCache({ config, - finalizedPubkey2index, - finalizedIndex2pubkey, + pubkey2index, + index2pubkey, // `createFromFinalizedState()` creates cache with empty unfinalizedPubkey2index. Be cautious to only pass in finalized state unfinalizedPubkey2index: newUnfinalizedPubkeyIndexMap(), proposers, @@ -460,8 +460,8 @@ export class EpochCache { return new EpochCache({ config: this.config, // Common append-only structures shared with all states, no need to clone - finalizedPubkey2index: this.finalizedPubkey2index, - finalizedIndex2pubkey: this.finalizedIndex2pubkey, + pubkey2index: this.pubkey2index, + index2pubkey: this.index2pubkey, // No need to clone this reference. On each mutation the `unfinalizedPubkey2index` reference is replaced, @see `addPubkey` unfinalizedPubkey2index: this.unfinalizedPubkey2index, // Immutable data @@ -775,16 +775,16 @@ export class EpochCache { * */ getPubkey(index: ValidatorIndex): PublicKey { - return this.finalizedIndex2pubkey[index]; + return this.index2pubkey[index]; } getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { if (this.isAfterEIP6110()) { return ( - this.finalizedPubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)) + this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)) ); } else { - return this.finalizedPubkey2index.get(pubkey); + return this.pubkey2index.get(pubkey); } } @@ -793,12 +793,12 @@ export class EpochCache { * Add unfinalized pubkeys * */ - addPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { if (this.isAfterEIP6110()) { this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); } else { - this.finalizedPubkey2index.set(pubkey, index); - this.finalizedIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.pubkey2index.set(pubkey, index); + this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); } } @@ -812,7 +812,7 @@ export class EpochCache { throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } - const existingIndex = this.finalizedPubkey2index.get(pubkey); + const existingIndex = this.pubkey2index.get(pubkey); if (existingIndex != undefined) { if (existingIndex === index){ @@ -826,8 +826,8 @@ export class EpochCache { } } - this.finalizedPubkey2index.set(pubkey, index); - this.finalizedIndex2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.pubkey2index.set(pubkey, index); + this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.delete(toMemoryEfficientHexStr(pubkey)); } @@ -973,7 +973,7 @@ export function createEmptyEpochCacheImmutableData( return { config: createBeaconConfig(chainConfig, state.genesisValidatorsRoot), // This is a test state, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }; } diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 5e71b7124f7..6e6e3b24cd0 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -61,7 +61,6 @@ export class PubkeyIndexMap { * Mutates `pubkey2index` and `index2pubkey` * * If pubkey caches are empty: SLOW CODE - 🐢 - * */ export function syncPubkeys( state: BeaconStateAllForks, diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 0b692189ec6..2f332206623 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -15,7 +15,6 @@ import {newUnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; export type BeaconStateCache = { config: BeaconConfig; epochCtx: EpochCache; - /** Count of clones created from this BeaconStateCache instance. readonly to prevent accidental usage downstream */ readonly clonedCount: number; readonly clonedCountWithTransferCache: number; @@ -143,7 +142,7 @@ export function createCachedBeaconState( ): T & BeaconStateCache { return getCachedBeaconState(state, { config: immutableData.config, - epochCtx: EpochCache.createFromFinalizedState(state, immutableData, opts), + epochCtx: EpochCache.createFromState(state, immutableData, opts), clonedCount: 0, clonedCountWithTransferCache: 0, createdWithTransferCache: false, diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 0ec704e987a..6a985f84f64 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -32,7 +32,7 @@ export function getIndexedAttestationBigintSignatureSet( return { type: SignatureSetType.aggregate, - pubkeys: indexedAttestation.attestingIndices.map((i) => state.epochCtx.getPubkey(i)), + pubkeys: indexedAttestation.attestingIndices.map((i) => state.epochCtx.index2pubkey[i]), signingRoot: computeSigningRoot(ssz.phase0.AttestationDataBigint, indexedAttestation.data, domain), signature: indexedAttestation.signature, }; diff --git a/packages/state-transition/src/signatureSets/indexedAttestation.ts b/packages/state-transition/src/signatureSets/indexedAttestation.ts index e600c1c5993..b5c48a20c9d 100644 --- a/packages/state-transition/src/signatureSets/indexedAttestation.ts +++ b/packages/state-transition/src/signatureSets/indexedAttestation.ts @@ -24,7 +24,7 @@ export function getAttestationWithIndicesSignatureSet( attestingIndices: number[] ): ISignatureSet { return createAggregateSignatureSetFromComponents( - attestingIndices.map((i) => state.epochCtx.getPubkey(i)), + attestingIndices.map((i) => state.epochCtx.index2pubkey[i]), getAttestationDataSigningRoot(state, attestation.data), attestation.signature ); diff --git a/packages/state-transition/src/signatureSets/proposer.ts b/packages/state-transition/src/signatureSets/proposer.ts index a98bebf37c6..a00bcacc7c9 100644 --- a/packages/state-transition/src/signatureSets/proposer.ts +++ b/packages/state-transition/src/signatureSets/proposer.ts @@ -25,7 +25,7 @@ export function getBlockProposerSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.getPubkey(signedBlock.message.proposerIndex), + pubkey: epochCtx.index2pubkey[signedBlock.message.proposerIndex], signingRoot: computeSigningRoot(blockType, signedBlock.message, domain), signature: signedBlock.signature, }; @@ -42,7 +42,7 @@ export function getBlobProposerSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.getPubkey(signedBlob.message.proposerIndex), + pubkey: epochCtx.index2pubkey[signedBlob.message.proposerIndex], signingRoot: computeSigningRoot(blockType, signedBlob.message, domain), signature: signedBlob.signature, }; diff --git a/packages/state-transition/src/signatureSets/proposerSlashings.ts b/packages/state-transition/src/signatureSets/proposerSlashings.ts index 68bcdbd7d1f..46be30c0636 100644 --- a/packages/state-transition/src/signatureSets/proposerSlashings.ts +++ b/packages/state-transition/src/signatureSets/proposerSlashings.ts @@ -11,7 +11,7 @@ export function getProposerSlashingSignatureSets( proposerSlashing: phase0.ProposerSlashing ): ISignatureSet[] { const {epochCtx} = state; - const pubkey = epochCtx.getPubkey(proposerSlashing.signedHeader1.message.proposerIndex); + const pubkey = epochCtx.index2pubkey[proposerSlashing.signedHeader1.message.proposerIndex]; // In state transition, ProposerSlashing headers are only partially validated. Their slot could be higher than the // clock and the slashing would still be valid. Must use bigint variants to hash correctly to all possible values diff --git a/packages/state-transition/src/signatureSets/randao.ts b/packages/state-transition/src/signatureSets/randao.ts index fc987592538..4fc8b77e4e3 100644 --- a/packages/state-transition/src/signatureSets/randao.ts +++ b/packages/state-transition/src/signatureSets/randao.ts @@ -27,7 +27,7 @@ export function getRandaoRevealSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.getPubkey(block.proposerIndex), + pubkey: epochCtx.index2pubkey[block.proposerIndex], signingRoot: computeSigningRoot(ssz.Epoch, epoch, domain), signature: block.body.randaoReveal, }; diff --git a/packages/state-transition/src/signatureSets/voluntaryExits.ts b/packages/state-transition/src/signatureSets/voluntaryExits.ts index 550d8b5dec6..bb86ef41777 100644 --- a/packages/state-transition/src/signatureSets/voluntaryExits.ts +++ b/packages/state-transition/src/signatureSets/voluntaryExits.ts @@ -28,7 +28,7 @@ export function getVoluntaryExitSignatureSet( return { type: SignatureSetType.single, - pubkey: epochCtx.getPubkey(signedVoluntaryExit.message.validatorIndex), + pubkey: epochCtx.index2pubkey[signedVoluntaryExit.message.validatorIndex], signingRoot: computeSigningRoot(ssz.phase0.VoluntaryExit, signedVoluntaryExit.message, domain), signature: signedVoluntaryExit.signature, }; diff --git a/packages/state-transition/src/slot/upgradeStateToAltair.ts b/packages/state-transition/src/slot/upgradeStateToAltair.ts index ef270019cc5..0afa43930ef 100644 --- a/packages/state-transition/src/slot/upgradeStateToAltair.ts +++ b/packages/state-transition/src/slot/upgradeStateToAltair.ts @@ -99,7 +99,7 @@ export function upgradeStateToAltair(statePhase0: CachedBeaconStatePhase0): Cach // currentTargetUnslashedBalanceIncrements is rotated to previousTargetUnslashedBalanceIncrements // // Here target balance is computed in full, which is slightly less performant than doing so in the loop - // above but gurantees consistency with EpochCache.createFromFinalizedState(). Note execution order below: + // above but gurantees consistency with EpochCache.createFromState(). Note execution order below: // ``` // processEpoch() // epochCtx.afterProcessEpoch() diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index db0e52cd675..5b3d3ef6706 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -7,10 +7,10 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 const eip6110State = state as CachedBeaconStateEIP6110; // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 // since the result lies within upper and lower bound of UintNum64 - const eth1DataIndexLimit = - (state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex + const eth1DataIndexLimit: UintNum64 = + state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex ? state.eth1Data.depositCount - : eip6110State.depositReceiptsStartIndex) as UintNum64; + : Number(eip6110State.depositReceiptsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 2d51171ae9b..d2036ec7373 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -234,9 +234,7 @@ export function initializeBeaconStateFromEth1( // - 3. interop state: Only supports starting from genesis at phase0 fork // So it's okay to skip syncing the sync committee cache here and expect it to be // populated latter when the altair fork happens for cases 2, 3. - const state = createCachedBeaconState(stateView, immutableData, { - skipSyncCommitteeCache: true, - }); + const state = createCachedBeaconState(stateView, immutableData, {skipSyncCommitteeCache: true}); applyTimestamp(config, state, eth1Timestamp); applyEth1BlockHash(state, eth1BlockHash); diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 1ce8528ecd1..65c92f629f0 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -127,8 +127,8 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean state.slot -= 1; phase0CachedState23637 = createCachedBeaconState(state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), - finalizedPubkey2index: pubkey2index, - finalizedIndex2pubkey: index2pubkey, + pubkey2index: pubkey2index, + index2pubkey: index2pubkey, }); const currentEpoch = computeEpochAtSlot(state.slot - 1); @@ -225,8 +225,8 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean state.slot -= 1; altairCachedState23637 = createCachedBeaconState(state, { config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), - finalizedPubkey2index: pubkey2index, - finalizedIndex2pubkey: index2pubkey, + pubkey2index: pubkey2index, + index2pubkey: index2pubkey, }); } if (!altairCachedState23638) { @@ -428,8 +428,8 @@ export function generateTestCachedBeaconStateOnlyValidators({ state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), - finalizedPubkey2index: pubkey2index, - finalizedIndex2pubkey: index2pubkey, + pubkey2index: pubkey2index, + index2pubkey: index2pubkey, }, {skipSyncPubkeys: true} ); diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index b02da161f42..f553559f0c0 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -39,10 +39,10 @@ describe("CachedBeaconState", () => { ); const index2 = 456; - state1.epochCtx.addPubkey(pubkey1, index1); + state1.epochCtx.addPubkey(index1, pubkey1); const state2 = state1.clone(); - state2.epochCtx.addPubkey(pubkey2, index2); + state2.epochCtx.addPubkey(index2, pubkey2); expect(state1.epochCtx.getValidatorIndex(pubkey1)).to.equal( index1, @@ -86,10 +86,10 @@ describe("CachedBeaconState", () => { ); const index2 = 456; - state1.epochCtx.addPubkey(pubkey1, index1); + state1.epochCtx.addPubkey(index1, pubkey1); const state2 = state1.clone(); - state2.epochCtx.addPubkey(pubkey2, index2); + state2.epochCtx.addPubkey(index2, pubkey2); expect(state1.epochCtx.getValidatorIndex(pubkey1)).to.equal( index1, diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 415fd0cd124..02dfebf8ad9 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -16,8 +16,8 @@ describe("upgradeState", () => { capellaState, { config: createBeaconConfig(config, capellaState.genesisValidatorsRoot), - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }, {skipSyncCommitteeCache: true} ); @@ -31,8 +31,8 @@ describe("upgradeState", () => { denebState, { config: createBeaconConfig(config, denebState.genesisValidatorsRoot), - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }, {skipSyncCommitteeCache: true} ); diff --git a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts index 5acd024ed2c..1a34e2472b5 100644 --- a/packages/state-transition/test/unit/util/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/util/cachedBeaconState.test.ts @@ -9,8 +9,8 @@ describe("CachedBeaconState", () => { createCachedBeaconState(emptyState, { config: createBeaconConfig(config, emptyState.genesisValidatorsRoot), - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }); }); }); diff --git a/packages/state-transition/test/utils/state.ts b/packages/state-transition/test/utils/state.ts index 6ebae08ce64..614210e44af 100644 --- a/packages/state-transition/test/utils/state.ts +++ b/packages/state-transition/test/utils/state.ts @@ -92,8 +92,8 @@ export function generateCachedState( return createCachedBeaconState(state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), // This is a test state, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }); } @@ -107,8 +107,8 @@ export function createCachedBeaconStateTest( { config: createBeaconConfig(configCustom, state.genesisValidatorsRoot), // This is a test state, there's no need to have a global shared cache of keys - finalizedPubkey2index: new PubkeyIndexMap(), - finalizedIndex2pubkey: [], + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], }, opts ); From 385fca62325abd3c33ac868bcc35b53f21b98b81 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 19:48:08 +0800 Subject: [PATCH 091/155] Stash change to reduce diffs --- .../test/perf/api/impl/validator/attester.test.ts | 2 +- .../test/unit/api/impl/beacon/state/utils.test.ts | 2 +- packages/state-transition/test/perf/util.ts | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts b/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts index 6752f3b0224..10527fdf94b 100644 --- a/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts +++ b/packages/beacon-node/test/perf/api/impl/validator/attester.test.ts @@ -35,7 +35,7 @@ describe("api / impl / validator", () => { noThreshold: true, fn: () => { for (let i = 0; i < reqCount; i++) { - const pubkey = state.epochCtx.getPubkey(i); + const pubkey = state.epochCtx.index2pubkey[i]; pubkey.toBytes(PointFormat.compressed); } }, diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index d6afcbcfb6f..5b09df7195b 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -104,7 +104,7 @@ describe("beacon state api utils", function () { describe("getStateValidatorIndex", async function () { const state = generateCachedAltairState(); - const pubkey2index = state.epochCtx.pubkey2index; + const pubkey2index = state.epochCtx.pubkey2index; it("should return valid: false on invalid input", () => { // "invalid validator id number" diff --git a/packages/state-transition/test/perf/util.ts b/packages/state-transition/test/perf/util.ts index 65c92f629f0..169b205ce5c 100644 --- a/packages/state-transition/test/perf/util.ts +++ b/packages/state-transition/test/perf/util.ts @@ -127,8 +127,8 @@ export function generatePerfTestCachedStatePhase0(opts?: {goBackOneSlot: boolean state.slot -= 1; phase0CachedState23637 = createCachedBeaconState(state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), - pubkey2index: pubkey2index, - index2pubkey: index2pubkey, + pubkey2index, + index2pubkey, }); const currentEpoch = computeEpochAtSlot(state.slot - 1); @@ -225,8 +225,8 @@ export function generatePerfTestCachedStateAltair(opts?: {goBackOneSlot: boolean state.slot -= 1; altairCachedState23637 = createCachedBeaconState(state, { config: createBeaconConfig(altairConfig, state.genesisValidatorsRoot), - pubkey2index: pubkey2index, - index2pubkey: index2pubkey, + pubkey2index, + index2pubkey, }); } if (!altairCachedState23638) { @@ -428,8 +428,8 @@ export function generateTestCachedBeaconStateOnlyValidators({ state, { config: createBeaconConfig(config, state.genesisValidatorsRoot), - pubkey2index: pubkey2index, - index2pubkey: index2pubkey, + pubkey2index, + index2pubkey, }, {skipSyncPubkeys: true} ); From fb97206572240a5ca95d6fb992a15e112df3ba5c Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 23 Oct 2023 20:05:33 +0800 Subject: [PATCH 092/155] Lint --- .../src/api/impl/beacon/state/utils.ts | 1 - .../unit/isValidLightClientHeader.test.ts | 2 +- .../src/block/processExecutionPayload.ts | 5 +- .../state-transition/src/cache/epochCache.ts | 18 +++--- .../state-transition/src/cache/stateCache.ts | 1 - packages/state-transition/src/index.ts | 7 ++- packages/state-transition/src/util/deposit.ts | 6 +- .../test/unit/util/deposit.test.ts | 56 +++++++------------ 8 files changed, 39 insertions(+), 57 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/state/utils.ts b/packages/beacon-node/src/api/impl/beacon/state/utils.ts index 48bcf66c715..3c17fa30ac6 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/utils.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/utils.ts @@ -4,7 +4,6 @@ import {FAR_FUTURE_EPOCH, GENESIS_SLOT} from "@lodestar/params"; import {BeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {BLSPubkey, phase0} from "@lodestar/types"; import {Epoch, ValidatorIndex} from "@lodestar/types"; -import {EpochCache} from "@lodestar/state-transition/src/types.js"; import {IBeaconChain, StateGetOpts} from "../../../../chain/index.js"; import {ApiError, ValidationError} from "../../errors.js"; import {isOptimisticBlock} from "../../../../util/forkChoice.js"; diff --git a/packages/light-client/test/unit/isValidLightClientHeader.test.ts b/packages/light-client/test/unit/isValidLightClientHeader.test.ts index b24578d1611..a28ac65ff61 100644 --- a/packages/light-client/test/unit/isValidLightClientHeader.test.ts +++ b/packages/light-client/test/unit/isValidLightClientHeader.test.ts @@ -1,5 +1,5 @@ import {expect} from "chai"; -import {ByteVectorType, fromHexString} from "@chainsafe/ssz"; +import {fromHexString} from "@chainsafe/ssz"; import {ssz, allForks} from "@lodestar/types"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {isValidLightClientHeader} from "../../src/spec/utils.js"; diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 347cd67bfab..f3521a37204 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -118,9 +118,8 @@ export function executionPayloadToPayloadHeader( } if (fork >= ForkSeq.eip6110) { - (bellatrixPayloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = ssz.eip6110.DepositReceipts.hashTreeRoot( - (payload as eip6110.ExecutionPayload).depositReceipts - ); + (bellatrixPayloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = + ssz.eip6110.DepositReceipts.hashTreeRoot((payload as eip6110.ExecutionPayload).depositReceipts); } return bellatrixPayloadFields; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 1780b8c684e..092fe47f623 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -94,7 +94,7 @@ export class EpochCache { * TODO: this is a hack, we need a safety mechanism in case a bad eth1 majority vote is in, * or handle non finalized data differently, or use an immutable.js structure for cheap copies * - * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is + * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued * * $VALIDATOR_COUNT x 192 char String -> Number Map @@ -103,7 +103,7 @@ export class EpochCache { /** * Unique globally shared finalized pubkey registry. There should only exist one for the entire application. * - * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is + * New: This would include only validators whose activation_eligibility_epoch != FAR_FUTURE_EPOCH and hence it is * insert only. Validators could be 1) Active 2) In the activation queue 3) Initialized but pending queued * * $VALIDATOR_COUNT x BLST deserialized pubkey (Jacobian coordinates) @@ -770,9 +770,9 @@ export class EpochCache { /** * Return finalized pubkey given the validator index. - * Only finalized pubkey as we do not store unfinalized pubkey because no where in the spec has a + * Only finalized pubkey as we do not store unfinalized pubkey because no where in the spec has a * need to make such enquiry - * + * */ getPubkey(index: ValidatorIndex): PublicKey { return this.index2pubkey[index]; @@ -780,9 +780,7 @@ export class EpochCache { getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { if (this.isAfterEIP6110()) { - return ( - this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)) - ); + return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } else { return this.pubkey2index.get(pubkey); } @@ -815,14 +813,14 @@ export class EpochCache { const existingIndex = this.pubkey2index.get(pubkey); if (existingIndex != undefined) { - if (existingIndex === index){ + if (existingIndex === index) { // Repeated insert. Should not happen except during the first few epochs of 6110 activation // Unfinalized validator added to finalizedPubkey2index pre-6110 by calling addPubkey() // when it become finalized in post-6110, addFinalizedPubkey() is called to cause repeated insert - return; + return; } else { // attempt to insert the same pubkey with different index, should never happen. - throw Error("inserted existing pubkey into finalizedPubkey2index cache with a different index") + throw Error("inserted existing pubkey into finalizedPubkey2index cache with a different index"); } } diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 2f332206623..d0e8a3ae644 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -10,7 +10,6 @@ import { BeaconStateDeneb, BeaconStateEIP6110, } from "./types.js"; -import {newUnfinalizedPubkeyIndexMap} from "./pubkeyCache.js"; export type BeaconStateCache = { config: BeaconConfig; diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 9fddc63fc17..e5e32ff9086 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -42,7 +42,12 @@ export { export {type EpochTransitionCache, beforeProcessEpoch} from "./cache/epochTransitionCache.js"; // Aux data-structures -export {PubkeyIndexMap, type Index2PubkeyCache, type UnfinalizedPubkeyIndexMap, newUnfinalizedPubkeyIndexMap} from "./cache/pubkeyCache.js"; +export { + PubkeyIndexMap, + type Index2PubkeyCache, + type UnfinalizedPubkeyIndexMap, + newUnfinalizedPubkeyIndexMap, +} from "./cache/pubkeyCache.js"; export { type EffectiveBalanceIncrements, diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 5b3d3ef6706..26a6e5715a4 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -5,15 +5,15 @@ import {CachedBeaconStateAllForks, CachedBeaconStateEIP6110} from "../types.js"; export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 { if (state.config.getForkSeq(state.slot) >= ForkSeq.eip6110) { const eip6110State = state as CachedBeaconStateEIP6110; - // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 + // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 // since the result lies within upper and lower bound of UintNum64 const eth1DataIndexLimit: UintNum64 = state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex ? state.eth1Data.depositCount - : Number(eip6110State.depositReceiptsStartIndex); + : Number(eip6110State.depositReceiptsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { - return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); + return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); } else { return 0; } diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index 5f33e573310..daea0c369f7 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -1,9 +1,9 @@ import {expect} from "chai"; import {ssz} from "@lodestar/types"; import {createChainForkConfig} from "@lodestar/config"; +import {MAX_DEPOSITS} from "@lodestar/params"; import {CachedBeaconStateEIP6110, getEth1DepositCount} from "../../../src/index.js"; -import { createCachedBeaconStateTest } from "../../utils/state.js"; -import { MAX_DEPOSITS } from "@lodestar/params"; +import {createCachedBeaconStateTest} from "../../utils/state.js"; describe("getEth1DepositCount", () => { it("Pre 6110", () => { @@ -11,28 +11,25 @@ describe("getEth1DepositCount", () => { const pre6110State = createCachedBeaconStateTest(stateView); if (pre6110State.epochCtx.isAfterEIP6110()) { - throw Error("Not a pre-6110 state"); - } + throw Error("Not a pre-6110 state"); + } pre6110State.eth1Data.depositCount = 123; // 1. Should get less than MAX_DEPOSIT pre6110State.eth1DepositIndex = 120; - expect(getEth1DepositCount(pre6110State)).to.equal( - 3, - ); + expect(getEth1DepositCount(pre6110State)).to.equal(3); // 2. Should get MAX_DEPOSIT pre6110State.eth1DepositIndex = 100; - expect(getEth1DepositCount(pre6110State)).to.equal( - MAX_DEPOSITS, - ); + expect(getEth1DepositCount(pre6110State)).to.equal(MAX_DEPOSITS); }); it("Post 6110 with eth1 deposit", () => { const stateView = ssz.eip6110.BeaconState.defaultViewDU(); const post6110State = createCachedBeaconStateTest( stateView, createChainForkConfig({ + /* eslint-disable @typescript-eslint/naming-convention */ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, @@ -43,36 +40,30 @@ describe("getEth1DepositCount", () => { ) as CachedBeaconStateEIP6110; if (!post6110State.epochCtx.isAfterEIP6110()) { - throw Error("Not a post-6110 state"); - } + throw Error("Not a post-6110 state"); + } post6110State.depositReceiptsStartIndex = 1000n; post6110State.eth1Data.depositCount = 995; // 1. Should get less than MAX_DEPOSIT post6110State.eth1DepositIndex = 990; - expect(getEth1DepositCount(post6110State)).to.equal( - 5, - ); + expect(getEth1DepositCount(post6110State)).to.equal(5); // 2. Should get MAX_DEPOSIT post6110State.eth1DepositIndex = 100; - expect(getEth1DepositCount(post6110State)).to.equal( - MAX_DEPOSITS, - ); + expect(getEth1DepositCount(post6110State)).to.equal(MAX_DEPOSITS); // 3. Should be 0 post6110State.eth1DepositIndex = 1000; - expect(getEth1DepositCount(post6110State)).to.equal( - 0, - ); - + expect(getEth1DepositCount(post6110State)).to.equal(0); }); it("Post 6110 without eth1 deposit", () => { const stateView = ssz.eip6110.BeaconState.defaultViewDU(); const post6110State = createCachedBeaconStateTest( stateView, createChainForkConfig({ + /* eslint-disable @typescript-eslint/naming-convention */ ALTAIR_FORK_EPOCH: 0, BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, @@ -83,8 +74,8 @@ describe("getEth1DepositCount", () => { ) as CachedBeaconStateEIP6110; if (!post6110State.epochCtx.isAfterEIP6110()) { - throw Error("Not a post-6110 state"); - } + throw Error("Not a post-6110 state"); + } post6110State.depositReceiptsStartIndex = 1000n; post6110State.eth1Data.depositCount = 1005; @@ -92,26 +83,17 @@ describe("getEth1DepositCount", () => { // Before eth1DepositIndex reaching the start index // 1. Should get less than MAX_DEPOSIT post6110State.eth1DepositIndex = 990; - expect(getEth1DepositCount(post6110State)).to.equal( - 10, - ); + expect(getEth1DepositCount(post6110State)).to.equal(10); // 2. Should get MAX_DEPOSIT post6110State.eth1DepositIndex = 983; - expect(getEth1DepositCount(post6110State)).to.equal( - MAX_DEPOSITS, - ); + expect(getEth1DepositCount(post6110State)).to.equal(MAX_DEPOSITS); // After eth1DepositIndex reaching the start index // 1. Should be 0 post6110State.eth1DepositIndex = 1000; - expect(getEth1DepositCount(post6110State)).to.equal( - 0, - ); + expect(getEth1DepositCount(post6110State)).to.equal(0); post6110State.eth1DepositIndex = 1003; - expect(getEth1DepositCount(post6110State)).to.equal( - 0, - ); + expect(getEth1DepositCount(post6110State)).to.equal(0); }); }); - \ No newline at end of file From 4c607894a5b3becee7e3da7820305d084e2eb3f4 Mon Sep 17 00:00:00 2001 From: naviechan Date: Fri, 27 Oct 2023 01:25:04 +0800 Subject: [PATCH 093/155] addFinalizedPubkey on finalized checkpoint --- packages/beacon-node/src/chain/chain.ts | 13 +++++++++++++ .../state-transition/src/cache/epochCache.ts | 17 +++++------------ .../state-transition/src/cache/pubkeyCache.ts | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index edfab4eb689..15241ad5d1f 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -853,6 +853,19 @@ export class BeaconChain implements IBeaconChain { if (headState) { this.opPool.pruneAll(headState, finalizedState); } + + // Populate finalized pubkey cache + if (finalizedState?.epochCtx.isAfterEIP6110()) { + const pivotValidatorIndex = finalizedState.validators.length; + // TODO 6110: If we are not considering EIP-6914 see if there is any + // data structure like OrderedMap in immutabe-js so we can do slicing instead of filter + const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.filter((index, _pubkey) => index < pivotValidatorIndex); + + newFinalizedValidators.forEach((index, pubkey) => { + finalizedState.epochCtx.addFinalizedPubkey(index, pubkey); + }) + + } } async updateBeaconProposerData(epoch: Epoch, proposers: ProposerPreparationData[]): Promise { diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 092fe47f623..01e2b667026 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -573,14 +573,6 @@ export class EpochCache { this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); - // To populate finalized cache and prune unfinalized cache with validators that are just initialized - if (this.isAfterEIP6110()) { - const validators = state.validators; - for (const index of epochTransitionCache.indicesEligibleForActivationQueue) { - const validator = validators.getReadonly(index); - this.addFinalizedPubkey(validator.pubkey, index); - } - } } beforeEpochTransition(): void { @@ -803,9 +795,10 @@ export class EpochCache { /** * * Given a validator whose activationEligibilityEpoch has just been set, we move its pubkey from unfinalized cache to finalized cache + * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly * */ - addFinalizedPubkey(pubkey: Uint8Array, index: ValidatorIndex): void { + addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex): void { if (!this.isAfterEIP6110()) { throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } @@ -816,7 +809,7 @@ export class EpochCache { if (existingIndex === index) { // Repeated insert. Should not happen except during the first few epochs of 6110 activation // Unfinalized validator added to finalizedPubkey2index pre-6110 by calling addPubkey() - // when it become finalized in post-6110, addFinalizedPubkey() is called to cause repeated insert + // when it becomes finalized in post-6110, addFinalizedPubkey() is called to cause repeated insert return; } else { // attempt to insert the same pubkey with different index, should never happen. @@ -825,9 +818,9 @@ export class EpochCache { } this.pubkey2index.set(pubkey, index); - this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + this.index2pubkey[index] = bls.PublicKey.fromHex(pubkey); - this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.delete(toMemoryEfficientHexStr(pubkey)); + this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.delete(pubkey); } getShufflingAtSlot(slot: Slot): EpochShuffling { diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 6e6e3b24cd0..0f8c532148e 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -50,7 +50,7 @@ export class PubkeyIndexMap { return this.map.get(toMemoryEfficientHexStr(key)); } - set(key: Uint8Array, value: ValidatorIndex): void { + set(key: Uint8Array | PubkeyHex, value: ValidatorIndex): void { this.map.set(toMemoryEfficientHexStr(key), value); } } From 902e0bbc4534142297c97a044f85d76247a4b3fc Mon Sep 17 00:00:00 2001 From: naviechan Date: Sat, 28 Oct 2023 17:54:19 +0800 Subject: [PATCH 094/155] Update comment --- packages/beacon-node/src/chain/chain.ts | 2 ++ packages/state-transition/src/cache/stateCache.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 15241ad5d1f..e99e222fb30 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -855,6 +855,8 @@ export class BeaconChain implements IBeaconChain { } // Populate finalized pubkey cache + // TODO: finalizedState may not be available after https://github.com/ChainSafe/lodestar/issues/5968. + // In that case implement getCheckpointStateValidatorCount() in regen and use headState instead if (finalizedState?.epochCtx.isAfterEIP6110()) { const pivotValidatorIndex = finalizedState.validators.length; // TODO 6110: If we are not considering EIP-6914 see if there is any diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index d0e8a3ae644..33d7106edf9 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -133,6 +133,7 @@ export type CachedBeaconStateAllForks = CachedBeaconState; export type CachedBeaconStateExecutions = CachedBeaconState; /** * Create CachedBeaconState computing a new EpochCache instance + * TODO 6110: rename this to createFinalizedCachedBeaconState() as it's intended for finalized state only */ export function createCachedBeaconState( state: T, From 6c870250aed5463df2f74cf8b90c1bb2aa4b17ba Mon Sep 17 00:00:00 2001 From: naviechan Date: Sat, 28 Oct 2023 18:23:47 +0800 Subject: [PATCH 095/155] Use OrderedMap for unfinalized cache --- packages/beacon-node/src/chain/chain.ts | 5 ++--- packages/state-transition/src/cache/pubkeyCache.ts | 8 +++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index e99e222fb30..d8f66067095 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -859,9 +859,8 @@ export class BeaconChain implements IBeaconChain { // In that case implement getCheckpointStateValidatorCount() in regen and use headState instead if (finalizedState?.epochCtx.isAfterEIP6110()) { const pivotValidatorIndex = finalizedState.validators.length; - // TODO 6110: If we are not considering EIP-6914 see if there is any - // data structure like OrderedMap in immutabe-js so we can do slicing instead of filter - const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.filter((index, _pubkey) => index < pivotValidatorIndex); + // Note EIP-6914 will break this logic + const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile((index, _pubkey) => index < pivotValidatorIndex); newFinalizedValidators.forEach((index, pubkey) => { finalizedState.epochCtx.addFinalizedPubkey(index, pubkey); diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 0f8c532148e..192e60aca9d 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -5,7 +5,13 @@ import {ValidatorIndex} from "@lodestar/types"; import {BeaconStateAllForks} from "./types.js"; export type Index2PubkeyCache = PublicKey[]; -export type UnfinalizedPubkeyIndexMap = immutable.Map; +/** + * OrderedMap preserves the order of entries in which they are `set()`. + * We assume `values()` yields validator indices in strictly increasing order + * as new validator indices are assigned in increasing order. + * EIP-6914 will break this assumption. + */ +export type UnfinalizedPubkeyIndexMap = immutable.OrderedMap; export type PubkeyHex = string; From cdcc5d63045f45032f224c0cc5755a5fae0f1604 Mon Sep 17 00:00:00 2001 From: naviechan Date: Sat, 28 Oct 2023 19:10:31 +0800 Subject: [PATCH 096/155] Pull out logic of deleting pubkeys for batch op --- packages/state-transition/src/cache/epochCache.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 01e2b667026..891159d13d1 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -793,10 +793,8 @@ export class EpochCache { } /** - * - * Given a validator whose activationEligibilityEpoch has just been set, we move its pubkey from unfinalized cache to finalized cache + * Add finalized validator index and pubkey into finalized cache. * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly - * */ addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex): void { if (!this.isAfterEIP6110()) { @@ -820,7 +818,13 @@ export class EpochCache { this.pubkey2index.set(pubkey, index); this.index2pubkey[index] = bls.PublicKey.fromHex(pubkey); - this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.delete(pubkey); + } + + /** + * Delete pubkeys from unfinalized cache + */ + deleteUnfinalizedPubkeys(pubkeys: PubkeyHex[]): void { + this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.deleteAll(pubkeys); } getShufflingAtSlot(slot: Slot): EpochShuffling { From c811411810c58cf67bd7da4ccfc00628f96f5e0c Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 30 Oct 2023 14:54:38 +0800 Subject: [PATCH 097/155] Add updateUnfinalizedPubkeys in regen --- packages/beacon-node/src/chain/chain.ts | 8 +++--- .../beacon-node/src/chain/regen/queued.ts | 10 +++++++- .../src/chain/stateCache/stateContextCache.ts | 25 ++++++++++++++++++- .../stateContextCheckpointsCache.ts | 22 +++++++++++++++- .../state-transition/src/cache/epochCache.ts | 4 +++ 5 files changed, 61 insertions(+), 8 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index d8f66067095..657151100e8 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -854,17 +854,15 @@ export class BeaconChain implements IBeaconChain { this.opPool.pruneAll(headState, finalizedState); } - // Populate finalized pubkey cache + // Populate finalized pubkey cache and remove unfinalized pubkey cache // TODO: finalizedState may not be available after https://github.com/ChainSafe/lodestar/issues/5968. // In that case implement getCheckpointStateValidatorCount() in regen and use headState instead if (finalizedState?.epochCtx.isAfterEIP6110()) { const pivotValidatorIndex = finalizedState.validators.length; // Note EIP-6914 will break this logic const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile((index, _pubkey) => index < pivotValidatorIndex); - - newFinalizedValidators.forEach((index, pubkey) => { - finalizedState.epochCtx.addFinalizedPubkey(index, pubkey); - }) + + this.regen.updateUnfinalizedPubkeys(newFinalizedValidators, cp.epoch); } } diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index dd111f14b4d..197e850eea2 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -1,7 +1,7 @@ import {toHexString} from "@chainsafe/ssz"; import {phase0, Slot, allForks, RootHex, Epoch} from "@lodestar/types"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; -import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap, computeEpochAtSlot} from "@lodestar/state-transition"; import {Logger} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {CheckpointHex, CheckpointStateCache, StateContextCache, toCheckpointHex} from "../stateCache/index.js"; @@ -121,6 +121,14 @@ export class QueuedStateRegenerator implements IStateRegenerator { return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch); } + /** + * Remove validators from unfinalized cache and add them to finalized cache for all related state context cache + */ + updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap, epoch: Epoch): void { + this.checkpointStateCache.updateUnfinalizedPubkeys(validators, epoch); + this.stateCache.updateUnfinalizedPubkeys(validators, epoch); + } + /** * Get the state to run with `block`. * - State after `block.parentRoot` dialed forward to block.slot diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 44523abf799..8d2342913ef 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -1,6 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; import {Epoch, RootHex} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap} from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; import {Metrics} from "../../metrics/index.js"; import {MapTracker} from "./mapMetrics.js"; @@ -84,6 +84,29 @@ export class StateContextCache { return this.cache.size; } + /** + * + */ + updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap, epoch: Epoch): void { + const cpKeySets = Array.from(this.epochIndex.entries()) + .filter(([e, _]) => e >= epoch) + .map(([_, cpKey]) => cpKey); + + const cpKeys = new Set(function* () { + for (const cpKeySet of cpKeySets) { + yield* cpKeySet; + } + }()); + + for (const cpKey in cpKeys) { + const cachedState = this.cache.get(cpKey); + if (cachedState) { + cachedState.epochCtx.addFinalizedPubkeys(validators); + cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + } + } + } + /** * TODO make this more robust. * Without more thought, this currently breaks our assumptions about recent state availablity diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 0cb48f0e2de..d75d3fcc244 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -1,6 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; import {phase0, Epoch, RootHex} from "@lodestar/types"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap} from "@lodestar/state-transition"; import {MapDef} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {Metrics} from "../../metrics/index.js"; @@ -90,6 +90,26 @@ export class CheckpointStateCache { return previousHits; } + updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap, epoch: Epoch): void { + const cpKeySets = Array.from(this.epochIndex.entries()) + .filter(([e, _]) => e >= epoch) + .map(([_, cpKey]) => cpKey); + + const cpKeys = new Set(function* () { + for (const cpKeySet of cpKeySets) { + yield* cpKeySet; + } + }()); + + for (const cpKey in cpKeys) { + const cachedState = this.cache.get(cpKey); + if (cachedState) { + cachedState.epochCtx.addFinalizedPubkeys(validators); + cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + } + } + } + pruneFinalized(finalizedEpoch: Epoch): void { for (const epoch of this.epochIndex.keys()) { if (epoch < finalizedEpoch) { diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 891159d13d1..5ad87145a30 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -792,6 +792,10 @@ export class EpochCache { } } + addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap): void { + Array.from(pubkeyMap.entries()).forEach(([pubkey, index]) => this.addFinalizedPubkey(index, pubkey)); + } + /** * Add finalized validator index and pubkey into finalized cache. * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly From 51bb3bba8170aca0cb045db2637c0bca7b6c5a44 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 30 Oct 2023 19:52:57 +0800 Subject: [PATCH 098/155] Update updateUnfinalizedPubkeys logic --- packages/beacon-node/src/chain/chain.ts | 2 +- packages/beacon-node/src/chain/regen/queued.ts | 6 +++--- .../beacon-node/src/chain/stateCache/stateContextCache.ts | 6 ++---- .../src/chain/stateCache/stateContextCheckpointsCache.ts | 6 ++---- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 657151100e8..237f9e2c878 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -862,7 +862,7 @@ export class BeaconChain implements IBeaconChain { // Note EIP-6914 will break this logic const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile((index, _pubkey) => index < pivotValidatorIndex); - this.regen.updateUnfinalizedPubkeys(newFinalizedValidators, cp.epoch); + this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); } } diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 197e850eea2..77a4325a902 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -124,9 +124,9 @@ export class QueuedStateRegenerator implements IStateRegenerator { /** * Remove validators from unfinalized cache and add them to finalized cache for all related state context cache */ - updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap, epoch: Epoch): void { - this.checkpointStateCache.updateUnfinalizedPubkeys(validators, epoch); - this.stateCache.updateUnfinalizedPubkeys(validators, epoch); + updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { + this.checkpointStateCache.updateUnfinalizedPubkeys(validators); + this.stateCache.updateUnfinalizedPubkeys(validators); } /** diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 8d2342913ef..5f6176e2160 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -87,10 +87,8 @@ export class StateContextCache { /** * */ - updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap, epoch: Epoch): void { - const cpKeySets = Array.from(this.epochIndex.entries()) - .filter(([e, _]) => e >= epoch) - .map(([_, cpKey]) => cpKey); + updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { + const cpKeySets = Array.from(this.epochIndex.values()) const cpKeys = new Set(function* () { for (const cpKeySet of cpKeySets) { diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index d75d3fcc244..c2feb995f45 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -90,10 +90,8 @@ export class CheckpointStateCache { return previousHits; } - updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap, epoch: Epoch): void { - const cpKeySets = Array.from(this.epochIndex.entries()) - .filter(([e, _]) => e >= epoch) - .map(([_, cpKey]) => cpKey); + updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { + const cpKeySets = Array.from(this.epochIndex.values()) const cpKeys = new Set(function* () { for (const cpKeySet of cpKeySets) { From 836b96f80ddee8d9dba29ce099eb1fc8847546b3 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 30 Oct 2023 19:53:04 +0800 Subject: [PATCH 099/155] Add comment --- packages/beacon-node/src/chain/chain.ts | 2 +- packages/beacon-node/src/chain/regen/queued.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 237f9e2c878..6c5a188f866 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -854,7 +854,6 @@ export class BeaconChain implements IBeaconChain { this.opPool.pruneAll(headState, finalizedState); } - // Populate finalized pubkey cache and remove unfinalized pubkey cache // TODO: finalizedState may not be available after https://github.com/ChainSafe/lodestar/issues/5968. // In that case implement getCheckpointStateValidatorCount() in regen and use headState instead if (finalizedState?.epochCtx.isAfterEIP6110()) { @@ -862,6 +861,7 @@ export class BeaconChain implements IBeaconChain { // Note EIP-6914 will break this logic const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile((index, _pubkey) => index < pivotValidatorIndex); + // Populate finalized pubkey cache and remove unfinalized pubkey cache this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); } diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 77a4325a902..f0b7a0d8c42 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -122,7 +122,8 @@ export class QueuedStateRegenerator implements IStateRegenerator { } /** - * Remove validators from unfinalized cache and add them to finalized cache for all related state context cache + * Remove `validators` from all unfinalized cache's epochCtx.UnfinalizedPubkey2Index, + * and add them to epochCtx.pubkey2index and epochCtx.index2pubkey */ updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { this.checkpointStateCache.updateUnfinalizedPubkeys(validators); From aa818a49577b5e4363fe87d007fe8784167f7a9d Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 31 Oct 2023 19:55:49 +0800 Subject: [PATCH 100/155] Add metrics for state context caches --- .../src/chain/stateCache/stateContextCache.ts | 17 +++++++++-- .../stateContextCheckpointsCache.ts | 14 +++++++++ .../src/metrics/metrics/lodestar.ts | 30 +++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 5f6176e2160..77593bd8e98 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -84,11 +84,11 @@ export class StateContextCache { return this.cache.size; } - /** - * - */ updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { const cpKeySets = Array.from(this.epochIndex.values()) + let totalAddTime = 0; + let totalDeleteTime = 0; + let totalNumStatesUpdated = 0; const cpKeys = new Set(function* () { for (const cpKeySet of cpKeySets) { @@ -99,10 +99,21 @@ export class StateContextCache { for (const cpKey in cpKeys) { const cachedState = this.cache.get(cpKey); if (cachedState) { + const addStartTime = Date.now(); cachedState.epochCtx.addFinalizedPubkeys(validators); + totalAddTime += Date.now() - addStartTime; + + const deleteStartTime = Date.now(); cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + totalDeleteTime += Date.now() - deleteStartTime; + + totalNumStatesUpdated++; } } + + this.metrics?.addPubkeyTime.observe(totalAddTime / 1000); + this.metrics?.deletePubkeyTime.observe(totalAddTime / 1000); + this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); } /** diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index c2feb995f45..967d431f4e7 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -92,6 +92,9 @@ export class CheckpointStateCache { updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { const cpKeySets = Array.from(this.epochIndex.values()) + let totalAddTime = 0; + let totalDeleteTime = 0; + let totalNumStatesUpdated = 0; const cpKeys = new Set(function* () { for (const cpKeySet of cpKeySets) { @@ -102,10 +105,21 @@ export class CheckpointStateCache { for (const cpKey in cpKeys) { const cachedState = this.cache.get(cpKey); if (cachedState) { + const addStartTime = Date.now(); cachedState.epochCtx.addFinalizedPubkeys(validators); + totalAddTime += Date.now() - addStartTime; + + const deleteStartTime = Date.now(); cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + totalDeleteTime += Date.now() - deleteStartTime; + + totalNumStatesUpdated++; } } + + this.metrics?.addPubkeyTime.observe(totalAddTime / 1000); + this.metrics?.deletePubkeyTime.observe(totalAddTime / 1000); + this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); } pruneFinalized(finalizedEpoch: Epoch): void { diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index b6f0d78f3b0..7d4330f6f04 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1018,6 +1018,21 @@ export function createLodestarMetrics( help: "Histogram of cloned count per state every time state.clone() is called", buckets: [1, 2, 5, 10, 50, 250], }), + numStatesUpdated: register.histogram({ + name: "lodestar_state_cache_state_updated_count", + help: "Histogram of number of state cache items updated every time removing and adding pubkeys to pubkey cache", + buckets: [1, 2, 5, 10, 50, 250], + }), + addPubkeyTime: register.histogram({ + name: "lodestar_state_cache_state_add_pubkey_time_seconds", + help: "Historgram of time spent on adding pubkeys to all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), + deletePubkeyTime: register.histogram({ + name: "lodestar_state_cache_state_delete_pubkey_time_seconds", + help: "Histrogram of time spent on deleting pubkeys from all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), }, cpStateCache: { @@ -1054,6 +1069,21 @@ export function createLodestarMetrics( help: "Histogram of cloned count per state every time state.clone() is called", buckets: [1, 2, 5, 10, 50, 250], }), + numStatesUpdated: register.histogram({ + name: "lodestar_cp_state_cache_state_updated_count", + help: "Histogram of number of state cache items updated every time removing and adding pubkeys to pubkey cache", + buckets: [1, 2, 5, 10, 50, 250], + }), + addPubkeyTime: register.histogram({ + name: "lodestar_cp_state_cache_state_add_pubkey_time_seconds", + help: "Avg min max of total time spent on adding pubkeys to all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), + deletePubkeyTime: register.histogram({ + name: "lodestar_cp_state_cache_state_delete_pubkey_time_seconds", + help: "Avg min max of total time spent on deleting pubkeys from all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), }, balancesCache: { From d545bc4426a4de223633fda2257872eb4d8502c7 Mon Sep 17 00:00:00 2001 From: naviechan Date: Tue, 31 Oct 2023 21:03:26 +0800 Subject: [PATCH 101/155] Address comment --- packages/beacon-node/src/eth1/utils/deposits.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index cdc36580e13..3baae0c7393 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -24,6 +24,10 @@ export async function getDeposits( const depositsLen = getEth1DepositCount(state); + if (depositsLen === 0) { + return []; // If depositsLen === 0, we can return early since no deposit with be returned from depositsGetter + } + const indexRange = {gte: depositIndex, lt: depositIndex + depositsLen}; const deposits = await depositsGetter(indexRange, eth1Data); From dfa0d671d2fb9d913b20eb3603fbcaca64d52d4c Mon Sep 17 00:00:00 2001 From: naviechan Date: Wed, 1 Nov 2023 14:24:28 +0800 Subject: [PATCH 102/155] Address comment --- packages/beacon-node/src/eth1/eth1DepositDataTracker.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index 6f163e0ddbe..3867934ebdf 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -113,6 +113,10 @@ export class Eth1DepositDataTracker { * Return eth1Data and deposits ready for block production for a given state */ async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { + if (state.epochCtx.isAfterEIP6110() && state.eth1DepositIndex >= (state as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { + // No need to poll eth1Data since EIP6110 deprecates the mechanism after depositReceiptsStartIndex is reached + return {eth1Data: state.eth1Data, deposits: []}; + } const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state)); const deposits = await this.getDeposits(state, eth1Data); return {eth1Data, deposits}; From 75cedd82e96805acb15c293e48cc71b5609dd993 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 2 Nov 2023 15:36:57 +0800 Subject: [PATCH 103/155] Deprecate eth1Data polling when condition is reached --- packages/beacon-node/src/chain/chain.ts | 5 +++++ .../beacon-node/src/eth1/eth1DepositDataTracker.ts | 10 ++++++++-- packages/beacon-node/src/eth1/index.ts | 8 ++++++++ packages/beacon-node/src/eth1/interface.ts | 5 +++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 6c5a188f866..73529294020 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -11,6 +11,7 @@ import { isCachedBeaconState, Index2PubkeyCache, PubkeyIndexMap, + CachedBeaconStateEIP6110, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; import { @@ -864,6 +865,10 @@ export class BeaconChain implements IBeaconChain { // Populate finalized pubkey cache and remove unfinalized pubkey cache this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); + if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { + // Signal eth1 to stop polling eth1Data + this.eth1.stopPollingEth1Data(); + } } } diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index 3867934ebdf..5e33a1b823b 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -1,6 +1,6 @@ import {phase0, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {BeaconStateAllForks, CachedBeaconStateAllForks, becomesNewEth1Data} from "@lodestar/state-transition"; +import {BeaconStateAllForks, CachedBeaconStateAllForks, CachedBeaconStateEIP6110, becomesNewEth1Data} from "@lodestar/state-transition"; import {ErrorAborted, TimeoutError, fromHex, Logger, isErrorAborted, sleep} from "@lodestar/utils"; import {IBeaconDb} from "../db/index.js"; @@ -67,6 +67,8 @@ export class Eth1DepositDataTracker { /** Dynamically adjusted batch size to fetch deposit logs */ private eth1GetLogsBatchSizeDynamic = MAX_BLOCKS_PER_LOG_QUERY; private readonly forcedEth1DataVote: phase0.Eth1Data | null; + /** To stop `runAutoUpdate()` in addition to AbortSignal */ + private stopPolling: Boolean = false; constructor( opts: Eth1Options, @@ -109,6 +111,10 @@ export class Eth1DepositDataTracker { } } + stopPollingEth1Data(): void { + this.stopPolling = true; + } + /** * Return eth1Data and deposits ready for block production for a given state */ @@ -169,7 +175,7 @@ export class Eth1DepositDataTracker { private async runAutoUpdate(): Promise { let lastRunMs = 0; - while (!this.signal.aborted) { + while (!this.signal.aborted && !this.stopPolling) { lastRunMs = Date.now(); try { diff --git a/packages/beacon-node/src/eth1/index.ts b/packages/beacon-node/src/eth1/index.ts index 9fdba90258a..a8ba55c5414 100644 --- a/packages/beacon-node/src/eth1/index.ts +++ b/packages/beacon-node/src/eth1/index.ts @@ -106,6 +106,10 @@ export class Eth1ForBlockProduction implements IEth1ForBlockProduction { startPollingMergeBlock(): void { return this.eth1MergeBlockTracker.startPollingMergeBlock(); } + + stopPollingEth1Data(): void { + return this.eth1DepositDataTracker?.stopPollingEth1Data(); + } } /** @@ -140,4 +144,8 @@ export class Eth1ForBlockProductionDisabled implements IEth1ForBlockProduction { startPollingMergeBlock(): void { // Ignore } + + stopPollingEth1Data(): void { + // Ignore + } } diff --git a/packages/beacon-node/src/eth1/interface.ts b/packages/beacon-node/src/eth1/interface.ts index fc9626eb5b8..4b5dd922601 100644 --- a/packages/beacon-node/src/eth1/interface.ts +++ b/packages/beacon-node/src/eth1/interface.ts @@ -62,6 +62,11 @@ export interface IEth1ForBlockProduction { * - head state not isMergeTransitionComplete */ startPollingMergeBlock(): void; + + /** + * Should stop polling eth1Data after a 6110 block is finalized AND deposit_receipts_start_index is reached + */ + stopPollingEth1Data(): void; } /** Different Eth1Block from phase0.Eth1Block with blockHash */ From 3a7574bb8f5d57d1aa350797631fa643cd30f97a Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 2 Nov 2023 16:53:44 +0800 Subject: [PATCH 104/155] Fix conflicts --- .../test/unit/cachedBeaconState.test.ts | 2 +- packages/types/src/allForks/sszTypes.ts | 1 + packages/types/src/allForks/types.ts | 2 +- packages/types/src/eip6110/sszTypes.ts | 10 +++++++++- packages/types/src/eip6110/types.ts | 2 ++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index a8fefa57f8d..8973706c50e 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -3,7 +3,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; import {toHexString} from "@lodestar/utils"; import {config} from "@lodestar/config/default"; -import {createBeaconConfig} from "@lodestar/config"; +import {createBeaconConfig, createChainForkConfig} from "@lodestar/config"; import {createCachedBeaconStateTest} from "../utils/state.js"; import {PubkeyIndexMap} from "../../src/cache/pubkeyCache.js"; import {createCachedBeaconState, loadUnfinalizedCachedBeaconState} from "../../src/cache/stateCache.js"; diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 12913e63d9d..cedf4844149 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -195,5 +195,6 @@ export const allForksBlobs = { eip6110: { BlobSidecar: deneb.BlobSidecar, BlindedBlobSidecar: deneb.BlindedBlobSidecar, + ExecutionPayloadAndBlobsBundle: eip6110.ExecutionPayloadAndBlobsBundle, }, }; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index e923ce265bb..42a353bf5a9 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -121,7 +121,7 @@ export type SignedBuilderBid = | capella.SignedBuilderBid | deneb.SignedBuilderBid | eip6110.SignedBuilderBid; -export type ExecutionPayloadAndBlobsBundle = deneb.ExecutionPayloadAndBlobsBundle; +export type ExecutionPayloadAndBlobsBundle = deneb.ExecutionPayloadAndBlobsBundle | eip6110.ExecutionPayloadAndBlobsBundle; export type LightClientHeader = | altair.LightClientHeader diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index 6136fe6cb86..f4380bd6002 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -100,9 +100,9 @@ export const SignedBlindedBeaconBlock = new ContainerType( export const BuilderBid = new ContainerType( { header: ExecutionPayloadHeader, // Modified in EIP6110 + blindedBlobsBundle: denebSsz.BlindedBlobsBundle, value: UintBn256, pubkey: BLSPubkey, - blobKzgCommitments: denebSsz.BuilderBid.fields.blobKzgCommitments, }, {typeName: "BuilderBid", jsonCase: "eth2"} ); @@ -115,6 +115,14 @@ export const SignedBuilderBid = new ContainerType( {typeName: "SignedBuilderBid", jsonCase: "eth2"} ); +export const ExecutionPayloadAndBlobsBundle = new ContainerType( + { + executionPayload: ExecutionPayload, // Modified in EIP6110 + blobsBundle: denebSsz.BlobsBundle, + }, + {typeName: "ExecutionPayloadAndBlobsBundle", jsonCase: "eth2"} +); + // We don't spread deneb.BeaconState fields since we need to replace // latestExecutionPayloadHeader and we cannot keep order doing that export const BeaconState = new ContainerType( diff --git a/packages/types/src/eip6110/types.ts b/packages/types/src/eip6110/types.ts index 42d0187309d..3286c10a033 100644 --- a/packages/types/src/eip6110/types.ts +++ b/packages/types/src/eip6110/types.ts @@ -7,6 +7,8 @@ export type DepositReceipts = ValueOf; export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; +export type ExecutionPayloadAndBlobsBundle = ValueOf; + export type BeaconBlockBody = ValueOf; export type BeaconBlock = ValueOf; export type SignedBeaconBlock = ValueOf; From 871de7b169bfb2e30dc467e11aa897a095d80d96 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 2 Nov 2023 18:10:27 +0800 Subject: [PATCH 105/155] Fix sim test --- packages/beacon-node/test/sim/6110-interop.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index e3a6967ac21..1788be3c828 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -340,6 +340,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { const {validators} = await getAndInitDevValidators({ node: bn, + logPrefix: "Node-A", validatorsPerClient, validatorClientCount, startIndex: 0, From 884ec354becee68f9f77d06870e7a5cad4cab8a6 Mon Sep 17 00:00:00 2001 From: naviechan Date: Thu, 2 Nov 2023 18:12:21 +0800 Subject: [PATCH 106/155] Lint --- packages/beacon-node/src/chain/chain.ts | 8 +++++--- packages/beacon-node/src/chain/regen/queued.ts | 2 +- .../src/chain/stateCache/stateContextCache.ts | 14 ++++++++------ .../stateCache/stateContextCheckpointsCache.ts | 14 ++++++++------ .../beacon-node/src/eth1/eth1DepositDataTracker.ts | 14 +++++++++++--- packages/state-transition/src/cache/pubkeyCache.ts | 4 ++-- packages/types/src/allForks/types.ts | 4 +++- 7 files changed, 38 insertions(+), 22 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 0eceba541ec..573dac83642 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -879,11 +879,13 @@ export class BeaconChain implements IBeaconChain { if (finalizedState?.epochCtx.isAfterEIP6110()) { const pivotValidatorIndex = finalizedState.validators.length; // Note EIP-6914 will break this logic - const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile((index, _pubkey) => index < pivotValidatorIndex); - + const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile( + (index, _pubkey) => index < pivotValidatorIndex + ); + // Populate finalized pubkey cache and remove unfinalized pubkey cache this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); - + if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { // Signal eth1 to stop polling eth1Data this.eth1.stopPollingEth1Data(); diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index f0b7a0d8c42..791cb8a1e42 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -122,7 +122,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { } /** - * Remove `validators` from all unfinalized cache's epochCtx.UnfinalizedPubkey2Index, + * Remove `validators` from all unfinalized cache's epochCtx.UnfinalizedPubkey2Index, * and add them to epochCtx.pubkey2index and epochCtx.index2pubkey */ updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 77593bd8e98..59cd61c542f 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -85,16 +85,18 @@ export class StateContextCache { } updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - const cpKeySets = Array.from(this.epochIndex.values()) + const cpKeySets = Array.from(this.epochIndex.values()); let totalAddTime = 0; let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - const cpKeys = new Set(function* () { - for (const cpKeySet of cpKeySets) { - yield* cpKeySet; - } - }()); + const cpKeys = new Set( + (function* () { + for (const cpKeySet of cpKeySets) { + yield* cpKeySet; + } + })() + ); for (const cpKey in cpKeys) { const cachedState = this.cache.get(cpKey); diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 967d431f4e7..664238b663d 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -91,16 +91,18 @@ export class CheckpointStateCache { } updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - const cpKeySets = Array.from(this.epochIndex.values()) + const cpKeySets = Array.from(this.epochIndex.values()); let totalAddTime = 0; let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - const cpKeys = new Set(function* () { - for (const cpKeySet of cpKeySets) { - yield* cpKeySet; - } - }()); + const cpKeys = new Set( + (function* () { + for (const cpKeySet of cpKeySets) { + yield* cpKeySet; + } + })() + ); for (const cpKey in cpKeys) { const cachedState = this.cache.get(cpKey); diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index 5e33a1b823b..d30c80f4d81 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -1,6 +1,11 @@ import {phase0, ssz} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; -import {BeaconStateAllForks, CachedBeaconStateAllForks, CachedBeaconStateEIP6110, becomesNewEth1Data} from "@lodestar/state-transition"; +import { + BeaconStateAllForks, + CachedBeaconStateAllForks, + CachedBeaconStateEIP6110, + becomesNewEth1Data, +} from "@lodestar/state-transition"; import {ErrorAborted, TimeoutError, fromHex, Logger, isErrorAborted, sleep} from "@lodestar/utils"; import {IBeaconDb} from "../db/index.js"; @@ -68,7 +73,7 @@ export class Eth1DepositDataTracker { private eth1GetLogsBatchSizeDynamic = MAX_BLOCKS_PER_LOG_QUERY; private readonly forcedEth1DataVote: phase0.Eth1Data | null; /** To stop `runAutoUpdate()` in addition to AbortSignal */ - private stopPolling: Boolean = false; + private stopPolling: boolean = false; constructor( opts: Eth1Options, @@ -119,7 +124,10 @@ export class Eth1DepositDataTracker { * Return eth1Data and deposits ready for block production for a given state */ async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { - if (state.epochCtx.isAfterEIP6110() && state.eth1DepositIndex >= (state as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { + if ( + state.epochCtx.isAfterEIP6110() && + state.eth1DepositIndex >= (state as CachedBeaconStateEIP6110).depositReceiptsStartIndex + ) { // No need to poll eth1Data since EIP6110 deprecates the mechanism after depositReceiptsStartIndex is reached return {eth1Data: state.eth1Data, deposits: []}; } diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 192e60aca9d..37ace620c21 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -6,8 +6,8 @@ import {BeaconStateAllForks} from "./types.js"; export type Index2PubkeyCache = PublicKey[]; /** - * OrderedMap preserves the order of entries in which they are `set()`. - * We assume `values()` yields validator indices in strictly increasing order + * OrderedMap preserves the order of entries in which they are `set()`. + * We assume `values()` yields validator indices in strictly increasing order * as new validator indices are assigned in increasing order. * EIP-6914 will break this assumption. */ diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 42a353bf5a9..7cd5969800f 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -121,7 +121,9 @@ export type SignedBuilderBid = | capella.SignedBuilderBid | deneb.SignedBuilderBid | eip6110.SignedBuilderBid; -export type ExecutionPayloadAndBlobsBundle = deneb.ExecutionPayloadAndBlobsBundle | eip6110.ExecutionPayloadAndBlobsBundle; +export type ExecutionPayloadAndBlobsBundle = + | deneb.ExecutionPayloadAndBlobsBundle + | eip6110.ExecutionPayloadAndBlobsBundle; export type LightClientHeader = | altair.LightClientHeader From 9d92e2cf69198742dce91252dcd4bcaac31c0054 Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 3 Nov 2023 16:26:36 +0800 Subject: [PATCH 107/155] Fix type --- packages/beacon-node/test/utils/state.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 429349da2f5..04a333345b1 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -92,7 +92,7 @@ export function generateState( if (forkSeq >= ForkSeq.eip6110) { const stateEIP6110 = state as eip6110.BeaconState; - stateEIP6110.depositReceiptsStartIndex = 2023; + stateEIP6110.depositReceiptsStartIndex = 2023n; } return config.getForkTypes(stateSlot).BeaconState.toViewDU(state); From 9c03611de6fc55b6412ba1aa6b660e4a40b83e5a Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 6 Nov 2023 18:38:56 +0800 Subject: [PATCH 108/155] Fix test --- packages/beacon-node/test/unit/eth1/utils/deposits.test.ts | 2 +- packages/beacon-node/test/unit/executionEngine/http.test.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 7ab64ac3a7b..d849c75ea5d 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -2,7 +2,6 @@ import {describe, it, expect} from "vitest"; import {phase0, ssz} from "@lodestar/types"; import {MAX_DEPOSITS, SLOTS_PER_EPOCH} from "@lodestar/params"; import {verifyMerkleBranch} from "@lodestar/utils"; -import {minimalChainConfig} from "@lodestar/config/lib/presets.js"; import {createChainForkConfig} from "@lodestar/config"; import {filterBy} from "../../../utils/db.js"; import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; @@ -11,6 +10,7 @@ import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src/eth1/utils/deposits.js"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; +import { minimalChainConfig } from "@lodestar/config/presets"; describe("eth1 / util / deposits", function () { describe("getDeposits", () => { diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index 250b433214c..fc668d00e91 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -188,6 +188,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], + depositReceipts: null, // depositReceipts is null pre-6110 }, null, // null returned for missing blocks { @@ -196,6 +197,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella + depositReceipts: null, // depositReceipts is null pre-6110 }, ], }; @@ -243,6 +245,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], + depositReceipts: null, // depositReceipts is null pre-6110 }, null, // null returned for missing blocks { @@ -251,6 +254,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella + depositReceipts: null, // depositReceipts is null pre-6110 }, ], }; From 38560a083fbfeaa7dceb60f0f392c901ed6c6bc5 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 6 Nov 2023 20:19:12 +0800 Subject: [PATCH 109/155] Fix test --- packages/beacon-node/src/eth1/utils/deposits.ts | 2 +- .../beacon-node/test/unit/eth1/utils/deposits.test.ts | 9 +++++---- packages/beacon-node/test/utils/state.ts | 2 ++ packages/state-transition/src/util/deposit.ts | 11 ++++++----- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/beacon-node/src/eth1/utils/deposits.ts b/packages/beacon-node/src/eth1/utils/deposits.ts index 3baae0c7393..7cf64d4455d 100644 --- a/packages/beacon-node/src/eth1/utils/deposits.ts +++ b/packages/beacon-node/src/eth1/utils/deposits.ts @@ -22,7 +22,7 @@ export async function getDeposits( throw new Eth1Error({code: Eth1ErrorCode.DEPOSIT_INDEX_TOO_HIGH, depositIndex, depositCount}); } - const depositsLen = getEth1DepositCount(state); + const depositsLen = getEth1DepositCount(state, eth1Data); if (depositsLen === 0) { return []; // If depositsLen === 0, we can return early since no deposit with be returned from depositsGetter diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index d849c75ea5d..acf7de3abbd 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -87,7 +87,7 @@ describe("eth1 / util / deposits", function () { depositCount: 2022, eth1DepositIndex: 2018, depositIndexes: Array.from({length: 2022}, (_, i) => i), - expectedReturnedIndexes: [2018, 2019, 2020, 2021, 2022], + expectedReturnedIndexes: [2018, 2019, 2020, 2021], post6110: true, }, { @@ -100,15 +100,16 @@ describe("eth1 / util / deposits", function () { }, ]; - const post6110Slot = minimalChainConfig.EIP6110_FORK_EPOCH * SLOTS_PER_EPOCH + 1; + const post6110Config = createChainForkConfig({ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 2, CAPELLA_FORK_EPOCH: 3, DENEB_FORK_EPOCH: 4, EIP6110_FORK_EPOCH: 5}) + const post6110Slot = post6110Config.EIP6110_FORK_EPOCH * SLOTS_PER_EPOCH + 1; for (const testCase of testCases) { const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error, post6110} = testCase; it(id, async function () { const state = post6110 - ? generateState({slot: post6110Slot, eth1DepositIndex}) + ? generateState({slot: post6110Slot, eth1DepositIndex}, post6110Config) : generateState({eth1DepositIndex}); - const cachedState = createCachedBeaconStateTest(state, createChainForkConfig({})); + const cachedState = createCachedBeaconStateTest(state, post6110 ? post6110Config : createChainForkConfig({})); const eth1Data = generateEth1Data(depositCount); const deposits = depositIndexes.map((index) => generateDepositEvent(index)); const depositsGetter: DepositGetter = async (indexRange) => diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 04a333345b1..f5a14a4d9c0 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -62,6 +62,7 @@ export function generateState( : generateValidators(numValidators, validatorOpts)); state.genesisTime = Math.floor(Date.now() / 1000); + state.slot = stateSlot; state.fork.previousVersion = config.GENESIS_FORK_VERSION; state.fork.currentVersion = config.GENESIS_FORK_VERSION; state.latestBlockHeader.bodyRoot = ssz.phase0.BeaconBlockBody.hashTreeRoot(ssz.phase0.BeaconBlockBody.defaultValue()); @@ -93,6 +94,7 @@ export function generateState( if (forkSeq >= ForkSeq.eip6110) { const stateEIP6110 = state as eip6110.BeaconState; stateEIP6110.depositReceiptsStartIndex = 2023n; + stateEIP6110.latestExecutionPayloadHeader = ssz.eip6110.ExecutionPayloadHeader.defaultValue(); } return config.getForkTypes(stateSlot).BeaconState.toViewDU(state); diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 26a6e5715a4..56b9aef9bd9 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -1,15 +1,16 @@ import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; -import {UintNum64} from "@lodestar/types"; +import {UintNum64, phase0} from "@lodestar/types"; import {CachedBeaconStateAllForks, CachedBeaconStateEIP6110} from "../types.js"; -export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 { +export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: phase0.Eth1Data): UintNum64 { + const eth1DataToUse = eth1Data ?? state.eth1Data; if (state.config.getForkSeq(state.slot) >= ForkSeq.eip6110) { const eip6110State = state as CachedBeaconStateEIP6110; // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 // since the result lies within upper and lower bound of UintNum64 const eth1DataIndexLimit: UintNum64 = - state.eth1Data.depositCount < eip6110State.depositReceiptsStartIndex - ? state.eth1Data.depositCount + eth1DataToUse.depositCount < eip6110State.depositReceiptsStartIndex + ? eth1DataToUse.depositCount : Number(eip6110State.depositReceiptsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { @@ -18,6 +19,6 @@ export function getEth1DepositCount(state: CachedBeaconStateAllForks): UintNum64 return 0; } } else { - return Math.min(MAX_DEPOSITS, state.eth1Data.depositCount - state.eth1DepositIndex); + return Math.min(MAX_DEPOSITS, eth1DataToUse.depositCount - state.eth1DepositIndex); } } From e365e9b2e823bcf730a7e7449f9f1c2743b01646 Mon Sep 17 00:00:00 2001 From: naviechan Date: Mon, 6 Nov 2023 20:44:33 +0800 Subject: [PATCH 110/155] Lint --- .../beacon-node/test/unit/eth1/utils/deposits.test.ts | 10 ++++++++-- .../src/block/processExecutionPayload.ts | 2 +- packages/state-transition/src/cache/epochCache.ts | 2 -- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index acf7de3abbd..50ecc2e48eb 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -3,6 +3,7 @@ import {phase0, ssz} from "@lodestar/types"; import {MAX_DEPOSITS, SLOTS_PER_EPOCH} from "@lodestar/params"; import {verifyMerkleBranch} from "@lodestar/utils"; import {createChainForkConfig} from "@lodestar/config"; +import {minimalChainConfig} from "@lodestar/config/presets"; import {filterBy} from "../../../utils/db.js"; import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; import {generateState} from "../../../utils/state.js"; @@ -10,7 +11,6 @@ import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {getDeposits, getDepositsWithProofs, DepositGetter} from "../../../../src/eth1/utils/deposits.js"; import {DepositTree} from "../../../../src/db/repositories/depositDataRoot.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; -import { minimalChainConfig } from "@lodestar/config/presets"; describe("eth1 / util / deposits", function () { describe("getDeposits", () => { @@ -100,7 +100,13 @@ describe("eth1 / util / deposits", function () { }, ]; - const post6110Config = createChainForkConfig({ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 2, CAPELLA_FORK_EPOCH: 3, DENEB_FORK_EPOCH: 4, EIP6110_FORK_EPOCH: 5}) + const post6110Config = createChainForkConfig({ + ALTAIR_FORK_EPOCH: 1, + BELLATRIX_FORK_EPOCH: 2, + CAPELLA_FORK_EPOCH: 3, + DENEB_FORK_EPOCH: 4, + EIP6110_FORK_EPOCH: 5, + }); const post6110Slot = post6110Config.EIP6110_FORK_EPOCH * SLOTS_PER_EPOCH + 1; for (const testCase of testCases) { diff --git a/packages/state-transition/src/block/processExecutionPayload.ts b/packages/state-transition/src/block/processExecutionPayload.ts index 910d6282e1f..b589436012a 100644 --- a/packages/state-transition/src/block/processExecutionPayload.ts +++ b/packages/state-transition/src/block/processExecutionPayload.ts @@ -81,4 +81,4 @@ export function processExecutionPayload( state.latestExecutionPayloadHeader = state.config .getExecutionForkTypes(state.slot) .ExecutionPayloadHeader.toViewDU(payloadHeader) as typeof state.latestExecutionPayloadHeader; -} \ No newline at end of file +} diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 7378ed381ea..340255c80bd 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -584,7 +584,6 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); - } beforeEpochTransition(): void { @@ -833,7 +832,6 @@ export class EpochCache { this.pubkey2index.set(pubkey, index); this.index2pubkey[index] = bls.PublicKey.fromHex(pubkey); - } /** From 0a8d07af9278ebb4accb80c52eeb2a60bc84d300 Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 9 Nov 2023 18:49:11 +0300 Subject: [PATCH 111/155] Update packages/light-client/src/spec/utils.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> --- packages/light-client/src/spec/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index 3bd208ac2dc..5a8c9ea9b01 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -111,7 +111,7 @@ export function upgradeLightClientHeader( (upgradedHeader as eip6110.LightClientHeader).execution.depositReceiptsRoot = ssz.eip6110.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue(); - // Break if no further upgradation is required else fall through + // Break if no further upgrades is required else fall through if (ForkSeq[targetFork] <= ForkSeq.eip6110) break; } return upgradedHeader; From 4996cb391803272c6d2c046ddfe90834de13d9e3 Mon Sep 17 00:00:00 2001 From: navie Date: Sat, 11 Nov 2023 13:25:12 +0300 Subject: [PATCH 112/155] Fix spec test --- packages/state-transition/src/util/execution.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 7ac4da4aeec..9bd2f8fc4ec 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -1,4 +1,4 @@ -import {allForks, bellatrix, capella, deneb, isBlindedBeaconBlockBody, ssz} from "@lodestar/types"; +import {allForks, bellatrix, capella, deneb, eip6110, isBlindedBeaconBlockBody, ssz} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import { @@ -170,5 +170,11 @@ export function executionPayloadToPayloadHeader( ).excessBlobGas; } + if (fork >= ForkSeq.eip6110) { + (bellatrixPayloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = ssz.eip6110.DepositReceipts.hashTreeRoot( + (payload as eip6110.ExecutionPayload).depositReceipts + ); + } + return bellatrixPayloadFields; } From a2494e9eebaadcbb17244a2628bbea8e518e192a Mon Sep 17 00:00:00 2001 From: navie Date: Sat, 11 Nov 2023 14:13:37 +0300 Subject: [PATCH 113/155] Address comments --- packages/beacon-node/src/chain/chain.ts | 4 +++- packages/state-transition/src/cache/epochCache.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 573dac83642..94d24c4003d 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -876,7 +876,9 @@ export class BeaconChain implements IBeaconChain { // TODO: finalizedState may not be available after https://github.com/ChainSafe/lodestar/issues/5968. // In that case implement getCheckpointStateValidatorCount() in regen and use headState instead - if (finalizedState?.epochCtx.isAfterEIP6110()) { + if (finalizedState === null) { + this.logger.verbose("Finalized state is null"); + } else if (finalizedState.epochCtx.isAfterEIP6110()) { const pivotValidatorIndex = finalizedState.validators.length; // Note EIP-6914 will break this logic const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile( diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 340255c80bd..7f773750dbc 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -777,7 +777,7 @@ export class EpochCache { * need to make such enquiry * */ - getPubkey(index: ValidatorIndex): PublicKey { + getPubkey(index: ValidatorIndex): PublicKey | undefined { return this.index2pubkey[index]; } @@ -804,7 +804,7 @@ export class EpochCache { } addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap): void { - Array.from(pubkeyMap.entries()).forEach(([pubkey, index]) => this.addFinalizedPubkey(index, pubkey)); + pubkeyMap.forEach((index, pubkey) => this.addFinalizedPubkey(index, pubkey)); } /** From 9822a12f2fadcd426ed95b543fb2a1ddf4c2db87 Mon Sep 17 00:00:00 2001 From: navie Date: Sat, 11 Nov 2023 18:02:45 +0300 Subject: [PATCH 114/155] Improve cache logic on checkpoint finalized --- packages/beacon-node/src/chain/chain.ts | 6 ++-- .../src/chain/stateCache/stateContextCache.ts | 30 +++++++------------ .../stateContextCheckpointsCache.ts | 30 +++++++------------ 3 files changed, 24 insertions(+), 42 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 94d24c4003d..21fdab9e7e5 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -886,14 +886,16 @@ export class BeaconChain implements IBeaconChain { ); // Populate finalized pubkey cache and remove unfinalized pubkey cache - this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); + if (!newFinalizedValidators.isEmpty()) { + this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); + } if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { // Signal eth1 to stop polling eth1Data this.eth1.stopPollingEth1Data(); } } - } + } async updateBeaconProposerData(epoch: Epoch, proposers: ProposerPreparationData[]): Promise { proposers.forEach((proposer) => { diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 59cd61c542f..15a0be96f7d 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -85,36 +85,26 @@ export class StateContextCache { } updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - const cpKeySets = Array.from(this.epochIndex.values()); let totalAddTime = 0; let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - const cpKeys = new Set( - (function* () { - for (const cpKeySet of cpKeySets) { - yield* cpKeySet; - } - })() - ); - for (const cpKey in cpKeys) { - const cachedState = this.cache.get(cpKey); - if (cachedState) { - const addStartTime = Date.now(); - cachedState.epochCtx.addFinalizedPubkeys(validators); - totalAddTime += Date.now() - addStartTime; + for (const cachedState of this.cache.values()) { + const addStartTime = Date.now(); + cachedState.epochCtx.addFinalizedPubkeys(validators); + totalAddTime += Date.now() - addStartTime; - const deleteStartTime = Date.now(); - cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); - totalDeleteTime += Date.now() - deleteStartTime; + const deleteStartTime = Date.now(); + cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + totalDeleteTime += Date.now() - deleteStartTime; - totalNumStatesUpdated++; - } + totalNumStatesUpdated++; } + this.metrics?.addPubkeyTime.observe(totalAddTime / 1000); - this.metrics?.deletePubkeyTime.observe(totalAddTime / 1000); + this.metrics?.deletePubkeyTime.observe(totalDeleteTime / 1000); this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); } diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 664238b663d..62911c7c68b 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -91,36 +91,26 @@ export class CheckpointStateCache { } updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - const cpKeySets = Array.from(this.epochIndex.values()); let totalAddTime = 0; let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - const cpKeys = new Set( - (function* () { - for (const cpKeySet of cpKeySets) { - yield* cpKeySet; - } - })() - ); - for (const cpKey in cpKeys) { - const cachedState = this.cache.get(cpKey); - if (cachedState) { - const addStartTime = Date.now(); - cachedState.epochCtx.addFinalizedPubkeys(validators); - totalAddTime += Date.now() - addStartTime; - const deleteStartTime = Date.now(); - cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); - totalDeleteTime += Date.now() - deleteStartTime; + for (const cachedState of this.cache.values()) { + const addStartTime = Date.now(); + cachedState.epochCtx.addFinalizedPubkeys(validators); + totalAddTime += Date.now() - addStartTime; - totalNumStatesUpdated++; - } + const deleteStartTime = Date.now(); + cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + totalDeleteTime += Date.now() - deleteStartTime; + + totalNumStatesUpdated++; } this.metrics?.addPubkeyTime.observe(totalAddTime / 1000); - this.metrics?.deletePubkeyTime.observe(totalAddTime / 1000); + this.metrics?.deletePubkeyTime.observe(totalDeleteTime / 1000); this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); } From d6d1aed30aadcb99598df834f08a6971f46f428a Mon Sep 17 00:00:00 2001 From: navie Date: Sat, 11 Nov 2023 18:03:21 +0300 Subject: [PATCH 115/155] Update sim test according to new cache logic --- .../beacon-node/test/sim/6110-interop.test.ts | 81 +++++++++++-------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 1788be3c828..30e6a208082 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -3,7 +3,7 @@ import {Context} from "mocha"; import _ from "lodash"; import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; -import {eip6110, Epoch} from "@lodestar/types"; +import {eip6110, Epoch, Slot} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; import {ChainConfig} from "@lodestar/config"; @@ -22,6 +22,7 @@ import {getAndInitDevValidators} from "../utils/node/validator.js"; import {ClockEvent} from "../../src/util/clock.js"; import {dataToBytes} from "../../src/eth1/provider/utils.js"; import {bytesToData} from "../../lib/eth1/provider/utils.js"; +import {BeaconNode} from "../../src/index.js"; import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; @@ -267,8 +268,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { SECONDS_PER_SLOT: 2, }; - // Just finish the run within first epoch as we only need to test if withdrawals started - const expectedEpochsToFinish = 1; + // Just enough to have a checkpoint finalized + const expectedEpochsToFinish = 4; // 1 epoch of margin of error const epochsOfMargin = 1; const timeoutSetupMargin = 30 * 1000; // Give extra 30 seconds of margin @@ -354,35 +355,32 @@ describe("executionEngine / ExecutionEngineHttp", function () { await Promise.all(validators.map((v) => v.close())); }); - await new Promise((resolve, reject) => { - bn.chain.clock.on(ClockEvent.slot, (slot) => { - // send raw tx at slot 1 - if (slot === 1) { - const depositTransaction = - "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; - sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`).catch((e: Error) => { - loggerNodeA.error("Fail to send raw deposit transaction", undefined, e); - }); - } - // Expect new validator to be in unfinalized cache, in state.validators and not in finalized cache - if (slot === 5) { - const headState = bn.chain.getHeadState(); - const epochCtx = headState.epochCtx; - if (headState.validators.length !== 33 || headState.balances.length !== 33) { - reject(Error("New validator is not reflected in the beacon state.")); - } - if (epochCtx.index2pubkey.length !== 32 || epochCtx.pubkey2index.size !== 32) { - reject(Error("Finalized cache is modified.")); - } - if (epochCtx.unfinalizedPubkey2index.size !== 1) { - reject( - Error( - `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` - ) - ); - } - } - }); + await waitForSlot(bn, 1); + + // send raw tx at slot 1 + const depositTransaction = + "0x02f9021e8217de8085012a05f20085019254d380830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120ef950826b191ebea0bbafa92a2c6bffa8239c6f456d92891ce2852b8360f0d30000000000000000000000000000000000000000000000000000000000000003095e4f91aea91a9e00387fad9d60997cff6cbf68d42d1b6629a7b248cdef255f94a2a2381e5d4125273fe42da5f7aa0e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b6c06e65228046268aa918baf78e072c25e65aa0bcf258cefcac3371c47df81bc4d43ca942f5fc28f9a563e925fd9c5010bc8c300add3faf3af0d61fabaaf03694020feaafb03e47c1bc4fcf082684c7ed3f7d5839d1722214b24f95ad2b226cc080a0be1161617492e4ca2fcb89edcadf5e71e8cac0d6447d18cfde9b55e5a8412417a07ec8c47dd484036c745049bb2e2980d44e38d4dacac50dc4a14a2f23c52f2e5f"; + sendRawTransactionBig(ethRpcUrl, depositTransaction, `${dataPath}/deposit.json`).catch((e: Error) => { + loggerNodeA.error("Fail to send raw deposit transaction", undefined, e); + }); + + await waitForSlot(bn, 5); + // Expect new validator to be in unfinalized cache, in state.validators and not in finalized cache + let headState = bn.chain.getHeadState(); + let epochCtx = headState.epochCtx; + if (headState.validators.length !== 33 || headState.balances.length !== 33) { + throw Error("New validator is not reflected in the beacon state at slot 5"); + } + if (epochCtx.index2pubkey.length !== 32 || epochCtx.pubkey2index.size !== 32) { + throw Error("Finalized cache is modified."); + } + if (epochCtx.unfinalizedPubkey2index.size !== 1) { + throw Error( + `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` + ); + } + + await new Promise((resolve, _reject) => { bn.chain.clock.on(ClockEvent.epoch, (epoch) => { // Resolve only if the finalized checkpoint includes execution payload if (epoch >= expectedEpochsToFinish) { @@ -392,6 +390,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); }); + // Stop chain and un-subscribe events so the execution engine won't update it's head // Allow some time to broadcast finalized events and complete the importBlock routine await Promise.all(validators.map((v) => v.close())); @@ -399,8 +398,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { await sleep(500); // Check if new validator is in finalized cache - const headState = bn.chain.getHeadState() as CachedBeaconStateEIP6110; - const epochCtx = headState.epochCtx; + headState = bn.chain.getHeadState() as CachedBeaconStateEIP6110; + epochCtx = headState.epochCtx; if (headState.validators.length !== 33 || headState.balances.length !== 33) { throw Error("New validator is not reflected in the beacon state."); @@ -422,3 +421,17 @@ describe("executionEngine / ExecutionEngineHttp", function () { console.log("\n\nDone\n\n"); } }); + +async function waitForSlot(bn: BeaconNode, targetSlot: Slot): Promise { + await new Promise((resolve, reject) => { + bn.chain.clock.on(ClockEvent.slot, (currentSlot) => { + if (currentSlot === targetSlot) { + resolve(); + return; + } + if (currentSlot > targetSlot) { + reject(Error(`Beacon node has passed target slot ${targetSlot}. Current slot ${currentSlot}`)); + } + }); + }); +} From f0eb5d62d75fb7e30e8e56f452c8b2b457aeeca3 Mon Sep 17 00:00:00 2001 From: navie Date: Sat, 11 Nov 2023 18:03:30 +0300 Subject: [PATCH 116/155] Update comment --- packages/state-transition/src/cache/epochCache.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 7f773750dbc..aa2efe8bec2 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -820,9 +820,8 @@ export class EpochCache { if (existingIndex != undefined) { if (existingIndex === index) { - // Repeated insert. Should not happen except during the first few epochs of 6110 activation - // Unfinalized validator added to finalizedPubkey2index pre-6110 by calling addPubkey() - // when it becomes finalized in post-6110, addFinalizedPubkey() is called to cause repeated insert + // Repeated insert. + // TODO: Add metric return; } else { // attempt to insert the same pubkey with different index, should never happen. From d55039e6560ebc1705b8fecb596348a17001af94 Mon Sep 17 00:00:00 2001 From: navie Date: Sat, 11 Nov 2023 18:14:20 +0300 Subject: [PATCH 117/155] Lint --- packages/beacon-node/src/chain/chain.ts | 2 +- .../beacon-node/src/chain/stateCache/stateContextCache.ts | 2 -- .../src/chain/stateCache/stateContextCheckpointsCache.ts | 2 -- packages/beacon-node/test/sim/6110-interop.test.ts | 1 - packages/state-transition/src/util/execution.ts | 5 ++--- 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 21fdab9e7e5..34e01881e1b 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -895,7 +895,7 @@ export class BeaconChain implements IBeaconChain { this.eth1.stopPollingEth1Data(); } } - } + } async updateBeaconProposerData(epoch: Epoch, proposers: ProposerPreparationData[]): Promise { proposers.forEach((proposer) => { diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 15a0be96f7d..c5f69256b9a 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -89,7 +89,6 @@ export class StateContextCache { let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - for (const cachedState of this.cache.values()) { const addStartTime = Date.now(); cachedState.epochCtx.addFinalizedPubkeys(validators); @@ -102,7 +101,6 @@ export class StateContextCache { totalNumStatesUpdated++; } - this.metrics?.addPubkeyTime.observe(totalAddTime / 1000); this.metrics?.deletePubkeyTime.observe(totalDeleteTime / 1000); this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 62911c7c68b..654d461410e 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -95,8 +95,6 @@ export class CheckpointStateCache { let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - - for (const cachedState of this.cache.values()) { const addStartTime = Date.now(); cachedState.epochCtx.addFinalizedPubkeys(validators); diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 30e6a208082..eef51c1964c 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -390,7 +390,6 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); }); - // Stop chain and un-subscribe events so the execution engine won't update it's head // Allow some time to broadcast finalized events and complete the importBlock routine await Promise.all(validators.map((v) => v.close())); diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 9bd2f8fc4ec..eb1f35f6973 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -171,9 +171,8 @@ export function executionPayloadToPayloadHeader( } if (fork >= ForkSeq.eip6110) { - (bellatrixPayloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = ssz.eip6110.DepositReceipts.hashTreeRoot( - (payload as eip6110.ExecutionPayload).depositReceipts - ); + (bellatrixPayloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = + ssz.eip6110.DepositReceipts.hashTreeRoot((payload as eip6110.ExecutionPayload).depositReceipts); } return bellatrixPayloadFields; From a33186835ba7e45428d7ab2bf034a66a99b9b4bd Mon Sep 17 00:00:00 2001 From: navie Date: Sun, 12 Nov 2023 16:25:32 +0300 Subject: [PATCH 118/155] Finalized pubkey cache only update once per checkpoint --- .../src/chain/stateCache/stateContextCache.ts | 31 +++++++++++-------- .../stateContextCheckpointsCache.ts | 31 +++++++++++-------- .../test/unit/eth1/utils/deposits.test.ts | 2 +- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index c5f69256b9a..7531d781e48 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -85,24 +85,29 @@ export class StateContextCache { } updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - let totalAddTime = 0; - let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - for (const cachedState of this.cache.values()) { - const addStartTime = Date.now(); - cachedState.epochCtx.addFinalizedPubkeys(validators); - totalAddTime += Date.now() - addStartTime; - - const deleteStartTime = Date.now(); - cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); - totalDeleteTime += Date.now() - deleteStartTime; + const addTimer = this.metrics?.addPubkeyTime.startTimer(); + try { + if (this.cache.size > 0) { + const st = this.cache.values().next().value as CachedBeaconStateAllForks; + // Only need to insert once since finalized cache is shared across all states globally + st.epochCtx.addFinalizedPubkeys(validators); + } + } finally { + addTimer?.(); + } - totalNumStatesUpdated++; + const deleteTimer = this.metrics?.deletePubkeyTime.startTimer(); + try { + for (const cachedState of this.cache.values()) { + cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + totalNumStatesUpdated++; + } + } finally { + deleteTimer?.(); } - this.metrics?.addPubkeyTime.observe(totalAddTime / 1000); - this.metrics?.deletePubkeyTime.observe(totalDeleteTime / 1000); this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); } diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 654d461410e..1d5789bc906 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -91,24 +91,29 @@ export class CheckpointStateCache { } updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - let totalAddTime = 0; - let totalDeleteTime = 0; let totalNumStatesUpdated = 0; - for (const cachedState of this.cache.values()) { - const addStartTime = Date.now(); - cachedState.epochCtx.addFinalizedPubkeys(validators); - totalAddTime += Date.now() - addStartTime; - - const deleteStartTime = Date.now(); - cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); - totalDeleteTime += Date.now() - deleteStartTime; + const addTimer = this.metrics?.addPubkeyTime.startTimer(); + try { + if (this.cache.size > 0) { + const st = this.cache.values().next().value as CachedBeaconStateAllForks; + // Only need to insert once since finalized cache is shared across all states globally + st.epochCtx.addFinalizedPubkeys(validators); + } + } finally { + addTimer?.(); + } - totalNumStatesUpdated++; + const deleteTimer = this.metrics?.deletePubkeyTime.startTimer(); + try { + for (const cachedState of this.cache.values()) { + cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + totalNumStatesUpdated++; + } + } finally { + deleteTimer?.(); } - this.metrics?.addPubkeyTime.observe(totalAddTime / 1000); - this.metrics?.deletePubkeyTime.observe(totalDeleteTime / 1000); this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); } diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 50ecc2e48eb..581a13ffb8c 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -3,7 +3,6 @@ import {phase0, ssz} from "@lodestar/types"; import {MAX_DEPOSITS, SLOTS_PER_EPOCH} from "@lodestar/params"; import {verifyMerkleBranch} from "@lodestar/utils"; import {createChainForkConfig} from "@lodestar/config"; -import {minimalChainConfig} from "@lodestar/config/presets"; import {filterBy} from "../../../utils/db.js"; import {Eth1ErrorCode} from "../../../../src/eth1/errors.js"; import {generateState} from "../../../utils/state.js"; @@ -100,6 +99,7 @@ describe("eth1 / util / deposits", function () { }, ]; + /* eslint-disable @typescript-eslint/naming-convention */ const post6110Config = createChainForkConfig({ ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 2, From 9c46eb9831bac5b6f5de907777110f4b296fa126 Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 17 Nov 2023 16:38:55 +0300 Subject: [PATCH 119/155] Add perf test for updateUnfinalizedPubkeys --- .../updateUnfinalizedPubkeys.test.ts | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts new file mode 100644 index 00000000000..6864d1d6b71 --- /dev/null +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -0,0 +1,74 @@ +import {itBench, setBenchOpts} from "@dapplion/benchmark"; +import {CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; +import {generateCached6110State} from "../../../utils/state.js"; +import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; + +import {OrderedMap} from "immutable"; +import { interopPubkeysCached } from "../../../../../state-transition/test/utils/interop.js"; + +describe("CheckpointStateCache perf tests", function () { + setBenchOpts({noThreshold: true}); + + const numPubkeysToBeFinalizedCases = [10, 100, 1000] + const numCheckpointStateCache = 10; + const numStateCache = 100; + + let baseState: CachedBeaconStateAllForks; + let checkpointStateCache: CheckpointStateCache; + let stateCache: StateContextCache; + let unfinalizedPubkey2Index: PubkeyIndexMap; + + + for (const numPubkeysToBeFinalized of numPubkeysToBeFinalizedCases) { + itBench({ + id: `updateUnfinalizedPubkeys - updating ${numPubkeysToBeFinalized} pubkeys`, + before: async() => { + unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); + baseState = generateCached6110State(); + }, + beforeEach: async() => { + baseState.epochCtx.unfinalizedPubkey2index = OrderedMap(unfinalizedPubkey2Index.map); + baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); + baseState.epochCtx.index2pubkey = []; + + checkpointStateCache = new CheckpointStateCache({}); + stateCache = new StateContextCache({}); + + for (let i = 0; i < numCheckpointStateCache; i++) { + const clonedState = baseState.clone(); + const checkpoint = ssz.phase0.Checkpoint.defaultValue(); + + clonedState.slot = i; + checkpoint.epoch = i; // Assigning arbitrary non-duplicate values to ensure checkpointStateCache correctly saves all the states + + checkpointStateCache.add(checkpoint, clonedState); + } + + for (let i = 0; i < numStateCache; i++) { + const clonedState = baseState.clone(); + clonedState.slot = i; + stateCache.add(clonedState); + } + }, + fn: async() => { + const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.takeWhile( + (index, _pubkey) => index < numPubkeysToBeFinalized + ); + checkpointStateCache.updateUnfinalizedPubkeys(newFinalizedValidators); + stateCache.updateUnfinalizedPubkeys(newFinalizedValidators); + }}); + } + + function generatePubkey2Index(startIndex: number, endIndex: number): PubkeyIndexMap { + let pubkey2Index = new PubkeyIndexMap(); + const pubkeys = interopPubkeysCached(endIndex - startIndex); + + for (let i = startIndex; i < endIndex; i++) { + pubkey2Index.set(pubkeys[i], i); + } + + return pubkey2Index; + } + +}); From e28506ed9c495ce813e4f8a92495948eb20b97b1 Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 17 Nov 2023 16:45:46 +0300 Subject: [PATCH 120/155] Add perf test for updateUnfinalizedPubkeys --- .../test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 6864d1d6b71..9f26d4b08f6 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -7,7 +7,7 @@ import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/sta import {OrderedMap} from "immutable"; import { interopPubkeysCached } from "../../../../../state-transition/test/utils/interop.js"; -describe("CheckpointStateCache perf tests", function () { +describe("updateUnfinalizedPubkeys perf tests", function () { setBenchOpts({noThreshold: true}); const numPubkeysToBeFinalizedCases = [10, 100, 1000] From ad642d7c1e5a242c7366b1c7c95b9cb0fa7ca4ab Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 20 Nov 2023 22:28:31 +0300 Subject: [PATCH 121/155] Tweak params for perf test --- .../stateCache/updateUnfinalizedPubkeys.test.ts | 4 ++-- packages/beacon-node/test/utils/state.ts | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 9f26d4b08f6..705ab3d113f 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -11,8 +11,8 @@ describe("updateUnfinalizedPubkeys perf tests", function () { setBenchOpts({noThreshold: true}); const numPubkeysToBeFinalizedCases = [10, 100, 1000] - const numCheckpointStateCache = 10; - const numStateCache = 100; + const numCheckpointStateCache = 8; + const numStateCache = 3 * 32; let baseState: CachedBeaconStateAllForks; let checkpointStateCache: CheckpointStateCache; diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index f5a14a4d9c0..b44120cd09a 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -7,6 +7,8 @@ import { PubkeyIndexMap, CachedBeaconStateBellatrix, BeaconStateBellatrix, + CachedBeaconStateEIP6110, + BeaconStateEIP6110, } from "@lodestar/state-transition"; import {allForks, altair, bellatrix, eip6110, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; @@ -141,3 +143,16 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac index2pubkey: [], }); } + +/** + * This generates state with default pubkey + */ +export function generateCached6110State(opts?: TestBeaconState): CachedBeaconStateEIP6110 { + const config = getConfig(ForkName.eip6110); + const state = generateState(opts, config); + return createCachedBeaconState(state as BeaconStateEIP6110, { + config: createBeaconConfig(config, state.genesisValidatorsRoot), + pubkey2index: new PubkeyIndexMap(), + index2pubkey: [], + }); +} \ No newline at end of file From f8a53504b27c28cad5a5484575ac2f091edc8ec2 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 20 Nov 2023 23:06:42 +0300 Subject: [PATCH 122/155] Freeze besu docker image version for 6110 --- packages/beacon-node/test/sim/6110-interop.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index eef51c1964c..8dd44daaf27 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -27,8 +27,7 @@ import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; // NOTE: How to run -// DEV_RUN=true EL_BINARY_DIR=hyperledger/besu:develop EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts -// TODO: Use a personal docker image instead of develop image from hyperledger +// DEV_RUN=true EL_BINARY_DIR=naviechan/besu:v6110 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts // or // DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn mocha test/sim/6110-interop.test.ts // ``` From d1a36ba18154ac50819e3e6d2bcdfa9e60ba6773 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 20 Nov 2023 23:39:59 +0300 Subject: [PATCH 123/155] Add benchmark result --- .../perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 705ab3d113f..157c67c3931 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -7,6 +7,10 @@ import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/sta import {OrderedMap} from "immutable"; import { interopPubkeysCached } from "../../../../../state-transition/test/utils/interop.js"; +// Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz +// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 795.3254 ops/s 1.257347 ms/op - 63 runs 2.86 s +// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 92.20117 ops/s 10.84585 ms/op - 36 runs 1.73 s +// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 3.881592 ops/s 257.6262 ms/op - 16 runs 5.19 s describe("updateUnfinalizedPubkeys perf tests", function () { setBenchOpts({noThreshold: true}); From 757b41e8c94302ee0c15d88e6239b37d7b343fdc Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 21 Nov 2023 00:56:13 +0300 Subject: [PATCH 124/155] Use Map instead of OrderedMap. Update benchmark --- packages/beacon-node/src/chain/chain.ts | 4 +--- .../stateCache/updateUnfinalizedPubkeys.test.ts | 14 ++++++-------- packages/state-transition/src/cache/pubkeyCache.ts | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 34e01881e1b..bcdf035ab8f 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -881,9 +881,7 @@ export class BeaconChain implements IBeaconChain { } else if (finalizedState.epochCtx.isAfterEIP6110()) { const pivotValidatorIndex = finalizedState.validators.length; // Note EIP-6914 will break this logic - const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.takeWhile( - (index, _pubkey) => index < pivotValidatorIndex - ); + const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.filter((index, _pubkey) => index < pivotValidatorIndex); // Populate finalized pubkey cache and remove unfinalized pubkey cache if (!newFinalizedValidators.isEmpty()) { diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 157c67c3931..9b13881a1d5 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -4,13 +4,13 @@ import {ssz} from "@lodestar/types"; import {generateCached6110State} from "../../../utils/state.js"; import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; -import {OrderedMap} from "immutable"; +import {Map} from "immutable"; import { interopPubkeysCached } from "../../../../../state-transition/test/utils/interop.js"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz -// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 795.3254 ops/s 1.257347 ms/op - 63 runs 2.86 s -// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 92.20117 ops/s 10.84585 ms/op - 36 runs 1.73 s -// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 3.881592 ops/s 257.6262 ms/op - 16 runs 5.19 s +// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 998.9062 ops/s 1.001095 ms/op - 645 runs 5.25 s +// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 158.0052 ops/s 6.328905 ms/op - 97 runs 1.97 s +// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 9.148975 ops/s 109.3019 ms/op - 20 runs 3.14 s describe("updateUnfinalizedPubkeys perf tests", function () { setBenchOpts({noThreshold: true}); @@ -32,7 +32,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { baseState = generateCached6110State(); }, beforeEach: async() => { - baseState.epochCtx.unfinalizedPubkey2index = OrderedMap(unfinalizedPubkey2Index.map); + baseState.epochCtx.unfinalizedPubkey2index = Map(unfinalizedPubkey2Index.map); baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); baseState.epochCtx.index2pubkey = []; @@ -56,9 +56,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { } }, fn: async() => { - const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.takeWhile( - (index, _pubkey) => index < numPubkeysToBeFinalized - ); + const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.filter((index, _pubkey) => index < numPubkeysToBeFinalized); checkpointStateCache.updateUnfinalizedPubkeys(newFinalizedValidators); stateCache.updateUnfinalizedPubkeys(newFinalizedValidators); }}); diff --git a/packages/state-transition/src/cache/pubkeyCache.ts b/packages/state-transition/src/cache/pubkeyCache.ts index 37ace620c21..6059bde5368 100644 --- a/packages/state-transition/src/cache/pubkeyCache.ts +++ b/packages/state-transition/src/cache/pubkeyCache.ts @@ -11,7 +11,7 @@ export type Index2PubkeyCache = PublicKey[]; * as new validator indices are assigned in increasing order. * EIP-6914 will break this assumption. */ -export type UnfinalizedPubkeyIndexMap = immutable.OrderedMap; +export type UnfinalizedPubkeyIndexMap = immutable.Map; export type PubkeyHex = string; From d68819de99d5a2f4de463b9707d7ce9d20e8ea6b Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 21 Nov 2023 01:40:59 +0300 Subject: [PATCH 125/155] Minor optimization --- .../beacon-node/src/chain/stateCache/stateContextCache.ts | 2 +- .../src/chain/stateCache/stateContextCheckpointsCache.ts | 2 +- .../perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 7531d781e48..d353af2e196 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -101,7 +101,7 @@ export class StateContextCache { const deleteTimer = this.metrics?.deletePubkeyTime.startTimer(); try { for (const cachedState of this.cache.values()) { - cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + cachedState.epochCtx.deleteUnfinalizedPubkeys(validators.keys()); totalNumStatesUpdated++; } } finally { diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 1d5789bc906..ca9139ad15c 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -107,7 +107,7 @@ export class CheckpointStateCache { const deleteTimer = this.metrics?.deletePubkeyTime.startTimer(); try { for (const cachedState of this.cache.values()) { - cachedState.epochCtx.deleteUnfinalizedPubkeys(Array.from(validators.keys())); + cachedState.epochCtx.deleteUnfinalizedPubkeys(validators.keys()); totalNumStatesUpdated++; } } finally { diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 9b13881a1d5..5aab06be7c4 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -8,9 +8,9 @@ import {Map} from "immutable"; import { interopPubkeysCached } from "../../../../../state-transition/test/utils/interop.js"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz -// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 998.9062 ops/s 1.001095 ms/op - 645 runs 5.25 s -// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 158.0052 ops/s 6.328905 ms/op - 97 runs 1.97 s -// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 9.148975 ops/s 109.3019 ms/op - 20 runs 3.14 s +// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1496.612 ops/s 668.1760 us/op - 276 runs 3.39 s +// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 174.9926 ops/s 5.714528 ms/op - 142 runs 2.19 s +// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 10.17848 ops/s 98.24650 ms/op - 28 runs 3.75 s describe("updateUnfinalizedPubkeys perf tests", function () { setBenchOpts({noThreshold: true}); From 0d3f6411d16d9aeab92585eee808c54fc59e9f70 Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 21 Nov 2023 14:21:37 +0300 Subject: [PATCH 126/155] Minor optimization --- packages/state-transition/src/cache/epochCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index aa2efe8bec2..6f6a06e3fd2 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -836,7 +836,7 @@ export class EpochCache { /** * Delete pubkeys from unfinalized cache */ - deleteUnfinalizedPubkeys(pubkeys: PubkeyHex[]): void { + deleteUnfinalizedPubkeys(pubkeys: Iterable): void { this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.deleteAll(pubkeys); } From e90743d1cd1f8969383ab94fee036be630079bb8 Mon Sep 17 00:00:00 2001 From: navie Date: Wed, 22 Nov 2023 13:15:29 +0300 Subject: [PATCH 127/155] Add memory test for immutable.js --- .../test/memory/unfinalizedPubkey2Index.ts | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts diff --git a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts new file mode 100644 index 00000000000..cee784e5ac0 --- /dev/null +++ b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts @@ -0,0 +1,55 @@ + +import crypto from "node:crypto"; +import {testRunnerMemory} from "./testRunnerMemory.js"; +import { Map } from "immutable"; +import { ValidatorIndex } from "@lodestar/types"; +import { toMemoryEfficientHexStr } from "../../../state-transition/src/cache/pubkeyCache.js"; + +// Results in MacOS Nov 2023 +// +// UnfinalizedPubkey2Index 1000 keys - 274956.5 bytes / instance +// UnfinalizedPubkey2Index 10000 keys - 2591129.3 bytes / instance +// UnfinalizedPubkey2Index 100000 keys - 27261443.4 bytes / instance + +testRunnerMemoryBpi([ + { + id: `UnfinalizedPubkey2Index 1000 keys`, + getInstance: () => getRandomMap(1000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), + }, + { + id: `UnfinalizedPubkey2Index 10000 keys`, + getInstance: () => getRandomMap(10000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), + }, + { + id: `UnfinalizedPubkey2Index 100000 keys`, + getInstance: () => getRandomMap(100000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), + }, +]); + +function getRandomMap(n: number, getKey: (i: number) => string): Map { + let map = Map(); + + return map.withMutations(m => { + for (let i = 0; i < n; i++) { + m.set(getKey(i), i); + } + }); +} + +/** + * Test bytes per instance in different representations of raw binary data + */ +function testRunnerMemoryBpi(testCases: {getInstance: (bytes: number) => unknown; id: string}[]): void { + const longestId = Math.max(...testCases.map(({id}) => id.length)); + + for (const {id, getInstance} of testCases) { + const bpi = testRunnerMemory({ + getInstance, + convergeFactor: 1 / 100, + sampleEvery: 5, + }); + + // eslint-disable-next-line no-console + console.log(`${id.padEnd(longestId)} - ${bpi.toFixed(1)} bytes / instance`); + } +} From f5fb361ea03e0399e08ae2df3076958793a01315 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 23 Nov 2023 20:52:04 +0300 Subject: [PATCH 128/155] Update test --- .../chain/stateCache/updateUnfinalizedPubkeys.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 5aab06be7c4..b3ec22f9770 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -18,19 +18,15 @@ describe("updateUnfinalizedPubkeys perf tests", function () { const numCheckpointStateCache = 8; const numStateCache = 3 * 32; - let baseState: CachedBeaconStateAllForks; let checkpointStateCache: CheckpointStateCache; let stateCache: StateContextCache; - let unfinalizedPubkey2Index: PubkeyIndexMap; + const unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); + const baseState = generateCached6110State(); for (const numPubkeysToBeFinalized of numPubkeysToBeFinalizedCases) { itBench({ id: `updateUnfinalizedPubkeys - updating ${numPubkeysToBeFinalized} pubkeys`, - before: async() => { - unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); - baseState = generateCached6110State(); - }, beforeEach: async() => { baseState.epochCtx.unfinalizedPubkey2index = Map(unfinalizedPubkey2Index.map); baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); From 15e62ccdf87275f8f498d11075e83faa8228d559 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 23 Nov 2023 21:49:54 +0300 Subject: [PATCH 129/155] Reduce code duplication --- .../beacon-node/src/chain/regen/queued.ts | 2 +- .../stateContextCheckpointsCache.ts | 27 ------------------- .../updateUnfinalizedPubkeys.test.ts | 2 +- 3 files changed, 2 insertions(+), 29 deletions(-) diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 791cb8a1e42..2c026ddc86e 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -126,8 +126,8 @@ export class QueuedStateRegenerator implements IStateRegenerator { * and add them to epochCtx.pubkey2index and epochCtx.index2pubkey */ updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - this.checkpointStateCache.updateUnfinalizedPubkeys(validators); this.stateCache.updateUnfinalizedPubkeys(validators); + this.stateCache.updateUnfinalizedPubkeys.bind(this.checkpointStateCache)(validators); } /** diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index ca9139ad15c..5534da8061b 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -90,33 +90,6 @@ export class CheckpointStateCache { return previousHits; } - updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - let totalNumStatesUpdated = 0; - - const addTimer = this.metrics?.addPubkeyTime.startTimer(); - try { - if (this.cache.size > 0) { - const st = this.cache.values().next().value as CachedBeaconStateAllForks; - // Only need to insert once since finalized cache is shared across all states globally - st.epochCtx.addFinalizedPubkeys(validators); - } - } finally { - addTimer?.(); - } - - const deleteTimer = this.metrics?.deletePubkeyTime.startTimer(); - try { - for (const cachedState of this.cache.values()) { - cachedState.epochCtx.deleteUnfinalizedPubkeys(validators.keys()); - totalNumStatesUpdated++; - } - } finally { - deleteTimer?.(); - } - - this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); - } - pruneFinalized(finalizedEpoch: Epoch): void { for (const epoch of this.epochIndex.keys()) { if (epoch < finalizedEpoch) { diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index b3ec22f9770..c6924bc15cd 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -53,8 +53,8 @@ describe("updateUnfinalizedPubkeys perf tests", function () { }, fn: async() => { const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.filter((index, _pubkey) => index < numPubkeysToBeFinalized); - checkpointStateCache.updateUnfinalizedPubkeys(newFinalizedValidators); stateCache.updateUnfinalizedPubkeys(newFinalizedValidators); + stateCache.updateUnfinalizedPubkeys.bind(checkpointStateCache)(newFinalizedValidators); }}); } From 6d85788dd476badcb878699dffb8dc541b8c9cf2 Mon Sep 17 00:00:00 2001 From: navie Date: Thu, 23 Nov 2023 22:04:10 +0300 Subject: [PATCH 130/155] Lint --- packages/beacon-node/src/chain/chain.ts | 4 ++- .../stateContextCheckpointsCache.ts | 2 +- .../test/memory/unfinalizedPubkey2Index.ts | 19 +++++++------ .../updateUnfinalizedPubkeys.test.ts | 27 ++++++++++--------- .../beacon-node/test/sim/6110-interop.test.ts | 3 +-- packages/beacon-node/test/utils/state.ts | 2 +- 6 files changed, 29 insertions(+), 28 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index bcdf035ab8f..1dbd48f8f88 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -881,7 +881,9 @@ export class BeaconChain implements IBeaconChain { } else if (finalizedState.epochCtx.isAfterEIP6110()) { const pivotValidatorIndex = finalizedState.validators.length; // Note EIP-6914 will break this logic - const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.filter((index, _pubkey) => index < pivotValidatorIndex); + const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.filter( + (index, _pubkey) => index < pivotValidatorIndex + ); // Populate finalized pubkey cache and remove unfinalized pubkey cache if (!newFinalizedValidators.isEmpty()) { diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 5534da8061b..0cb48f0e2de 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -1,6 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; import {phase0, Epoch, RootHex} from "@lodestar/types"; -import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {MapDef} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {Metrics} from "../../metrics/index.js"; diff --git a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts index cee784e5ac0..b37967d16ca 100644 --- a/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts +++ b/packages/beacon-node/test/memory/unfinalizedPubkey2Index.ts @@ -1,9 +1,8 @@ - import crypto from "node:crypto"; +import {Map} from "immutable"; +import {ValidatorIndex} from "@lodestar/types"; +import {toMemoryEfficientHexStr} from "@lodestar/state-transition/src/cache/pubkeyCache.js"; import {testRunnerMemory} from "./testRunnerMemory.js"; -import { Map } from "immutable"; -import { ValidatorIndex } from "@lodestar/types"; -import { toMemoryEfficientHexStr } from "../../../state-transition/src/cache/pubkeyCache.js"; // Results in MacOS Nov 2023 // @@ -13,26 +12,26 @@ import { toMemoryEfficientHexStr } from "../../../state-transition/src/cache/pub testRunnerMemoryBpi([ { - id: `UnfinalizedPubkey2Index 1000 keys`, + id: "UnfinalizedPubkey2Index 1000 keys", getInstance: () => getRandomMap(1000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), }, { - id: `UnfinalizedPubkey2Index 10000 keys`, + id: "UnfinalizedPubkey2Index 10000 keys", getInstance: () => getRandomMap(10000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), }, { - id: `UnfinalizedPubkey2Index 100000 keys`, + id: "UnfinalizedPubkey2Index 100000 keys", getInstance: () => getRandomMap(100000, () => toMemoryEfficientHexStr(crypto.randomBytes(48))), }, ]); function getRandomMap(n: number, getKey: (i: number) => string): Map { - let map = Map(); + const map = Map(); - return map.withMutations(m => { + return map.withMutations((m) => { for (let i = 0; i < n; i++) { m.set(getKey(i), i); - } + } }); } diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index c6924bc15cd..59074d151af 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -1,12 +1,11 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; -import {CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; +import {Map} from "immutable"; +import {PubkeyIndexMap} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; +import {interopPubkeysCached} from "../../../../../state-transition/test/utils/interop.js"; import {generateCached6110State} from "../../../utils/state.js"; import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; -import {Map} from "immutable"; -import { interopPubkeysCached } from "../../../../../state-transition/test/utils/interop.js"; - // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz // ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1496.612 ops/s 668.1760 us/op - 276 runs 3.39 s // ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 174.9926 ops/s 5.714528 ms/op - 142 runs 2.19 s @@ -14,7 +13,7 @@ import { interopPubkeysCached } from "../../../../../state-transition/test/utils describe("updateUnfinalizedPubkeys perf tests", function () { setBenchOpts({noThreshold: true}); - const numPubkeysToBeFinalizedCases = [10, 100, 1000] + const numPubkeysToBeFinalizedCases = [10, 100, 1000]; const numCheckpointStateCache = 8; const numStateCache = 3 * 32; @@ -27,14 +26,14 @@ describe("updateUnfinalizedPubkeys perf tests", function () { for (const numPubkeysToBeFinalized of numPubkeysToBeFinalizedCases) { itBench({ id: `updateUnfinalizedPubkeys - updating ${numPubkeysToBeFinalized} pubkeys`, - beforeEach: async() => { + beforeEach: async () => { baseState.epochCtx.unfinalizedPubkey2index = Map(unfinalizedPubkey2Index.map); baseState.epochCtx.pubkey2index = new PubkeyIndexMap(); baseState.epochCtx.index2pubkey = []; checkpointStateCache = new CheckpointStateCache({}); stateCache = new StateContextCache({}); - + for (let i = 0; i < numCheckpointStateCache; i++) { const clonedState = baseState.clone(); const checkpoint = ssz.phase0.Checkpoint.defaultValue(); @@ -44,22 +43,25 @@ describe("updateUnfinalizedPubkeys perf tests", function () { checkpointStateCache.add(checkpoint, clonedState); } - + for (let i = 0; i < numStateCache; i++) { const clonedState = baseState.clone(); clonedState.slot = i; stateCache.add(clonedState); } }, - fn: async() => { - const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.filter((index, _pubkey) => index < numPubkeysToBeFinalized); + fn: async () => { + const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.filter( + (index, _pubkey) => index < numPubkeysToBeFinalized + ); stateCache.updateUnfinalizedPubkeys(newFinalizedValidators); stateCache.updateUnfinalizedPubkeys.bind(checkpointStateCache)(newFinalizedValidators); - }}); + }, + }); } function generatePubkey2Index(startIndex: number, endIndex: number): PubkeyIndexMap { - let pubkey2Index = new PubkeyIndexMap(); + const pubkey2Index = new PubkeyIndexMap(); const pubkeys = interopPubkeysCached(endIndex - startIndex); for (let i = startIndex; i < endIndex; i++) { @@ -68,5 +70,4 @@ describe("updateUnfinalizedPubkeys perf tests", function () { return pubkey2Index; } - }); diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 8dd44daaf27..93f063291cd 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -203,8 +203,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); if (!payloadId2) throw Error("InvalidPayloadId"); - // 4. Get the payload. Check depositReceipts field contains deposit - + // 5. Get the payload. Check depositReceipts field contains deposit // Wait a bit first for besu to pick up tx from the tx pool. await sleep(1000); const payloadAndBlockValue = await executionEngine.getPayload(ForkName.eip6110, payloadId2); diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index b44120cd09a..041b9535aa6 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -155,4 +155,4 @@ export function generateCached6110State(opts?: TestBeaconState): CachedBeaconSta pubkey2index: new PubkeyIndexMap(), index2pubkey: [], }); -} \ No newline at end of file +} From 7db9b2ab3d830d8135d415eba872e38097ea88d4 Mon Sep 17 00:00:00 2001 From: naviechan Date: Fri, 8 Dec 2023 15:41:39 +0800 Subject: [PATCH 131/155] Remove try/catch in updateUnfinalizedPubkeys --- .../src/chain/stateCache/stateContextCache.ts | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index d353af2e196..3a6647307d6 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -88,25 +88,21 @@ export class StateContextCache { let totalNumStatesUpdated = 0; const addTimer = this.metrics?.addPubkeyTime.startTimer(); - try { - if (this.cache.size > 0) { - const st = this.cache.values().next().value as CachedBeaconStateAllForks; - // Only need to insert once since finalized cache is shared across all states globally - st.epochCtx.addFinalizedPubkeys(validators); - } - } finally { - addTimer?.(); + // Don't use a try/catch, only count run without exceptions + if (this.cache.size > 0) { + const st = this.cache.values().next().value as CachedBeaconStateAllForks; + // Only need to insert once since finalized cache is shared across all states globally + st.epochCtx.addFinalizedPubkeys(validators); } + addTimer?.(); const deleteTimer = this.metrics?.deletePubkeyTime.startTimer(); - try { - for (const cachedState of this.cache.values()) { - cachedState.epochCtx.deleteUnfinalizedPubkeys(validators.keys()); - totalNumStatesUpdated++; - } - } finally { - deleteTimer?.(); + // Don't use a try/catch, only count run without exceptions + for (const cachedState of this.cache.values()) { + cachedState.epochCtx.deleteUnfinalizedPubkeys(validators.keys()); + totalNumStatesUpdated++; } + deleteTimer?.(); this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); } From f4f8e0da714e496e3b48b8dd3ec56332115b86c3 Mon Sep 17 00:00:00 2001 From: naviechan Date: Fri, 8 Dec 2023 16:15:23 +0800 Subject: [PATCH 132/155] Introduce EpochCache metric --- .../beacon-node/src/chain/stateCache/stateContextCache.ts | 6 +++--- packages/beacon-node/src/metrics/metrics/lodestar.ts | 7 +++++++ .../perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts | 2 +- packages/state-transition/src/cache/epochCache.ts | 7 ++++--- packages/state-transition/src/metrics.ts | 4 ++++ 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 3a6647307d6..81be66228d7 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -21,7 +21,7 @@ export class StateContextCache { private readonly cache: MapTracker; /** Epoch -> Set */ private readonly epochIndex = new Map>(); - private readonly metrics: Metrics["stateCache"] | null | undefined; + private readonly metrics: (Metrics["stateCache"] & Metrics["epochCache"]) | null | undefined; /** * Strong reference to prevent head state from being pruned. * null if head state is being regen and not available at the moment. @@ -32,7 +32,7 @@ export class StateContextCache { this.maxStates = maxStates; this.cache = new MapTracker(metrics?.stateCache); if (metrics) { - this.metrics = metrics.stateCache; + this.metrics = {...metrics.stateCache, ...metrics.epochCache}; metrics.stateCache.size.addCollect(() => metrics.stateCache.size.set(this.cache.size)); } } @@ -92,7 +92,7 @@ export class StateContextCache { if (this.cache.size > 0) { const st = this.cache.values().next().value as CachedBeaconStateAllForks; // Only need to insert once since finalized cache is shared across all states globally - st.epochCtx.addFinalizedPubkeys(validators); + st.epochCtx.addFinalizedPubkeys(validators, this.metrics ?? undefined); } addTimer?.(); diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 671bb6199b2..d5c4a2e1359 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -345,6 +345,13 @@ export function createLodestarMetrics( help: "Total count state.validators nodesPopulated is false on stfn for post state", }), + epochCache: { + finalizedPubkeyDuplicateInsert: register.gauge({ + name: "lodestar_epoch_cache_finalized_pubkey_duplicate_insert", + help: "Total count of duplicate insert of finalized pubkeys", + }), + }, + // BLS verifier thread pool and queue bls: { diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 59074d151af..049917e25c9 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -2,7 +2,7 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {Map} from "immutable"; import {PubkeyIndexMap} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; -import {interopPubkeysCached} from "../../../../../state-transition/test/utils/interop.js"; +import {interopPubkeysCached} from "@lodestar/state-transition/test/utils/interop.js"; import {generateCached6110State} from "../../../utils/state.js"; import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 22001c717b7..5f90808f350 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -47,6 +47,7 @@ import { SyncCommitteeCache, SyncCommitteeCacheEmpty, } from "./syncCommitteeCache.js"; +import { EpochCacheMetrics } from "../metrics.js"; /** `= PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)` */ export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT); @@ -813,7 +814,7 @@ export class EpochCache { } } - addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap): void { + addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap, metrics?: EpochCacheMetrics): void { pubkeyMap.forEach((index, pubkey) => this.addFinalizedPubkey(index, pubkey)); } @@ -821,7 +822,7 @@ export class EpochCache { * Add finalized validator index and pubkey into finalized cache. * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly */ - addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex): void { + addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex, metrics?: EpochCacheMetrics): void { if (!this.isAfterEIP6110()) { throw new Error("addFInalizedPubkey is not available pre EIP-6110"); } @@ -831,7 +832,7 @@ export class EpochCache { if (existingIndex != undefined) { if (existingIndex === index) { // Repeated insert. - // TODO: Add metric + metrics?.finalizedPubkeyDuplicateInsert.inc(); return; } else { // attempt to insert the same pubkey with different index, should never happen. diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index c5179a1df5b..6d1ca02f20f 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -20,6 +20,10 @@ export type BeaconStateTransitionMetrics = { registerValidatorStatuses: (currentEpoch: Epoch, statuses: AttesterStatus[], balances?: number[]) => void; }; +export type EpochCacheMetrics = { + finalizedPubkeyDuplicateInsert: Gauge; +} + type LabelValues = Partial>; interface Histogram { From 006c26b47d71f729154493d322aa5f7cdeb2126d Mon Sep 17 00:00:00 2001 From: navie Date: Tue, 12 Dec 2023 21:30:39 +0800 Subject: [PATCH 133/155] Add historicalValidatorLengths --- packages/beacon-node/src/chain/chain.ts | 20 ++++++++++++------- .../state-transition/src/cache/epochCache.ts | 14 +++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 57f25330f3f..c803ad878dd 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -948,14 +948,16 @@ export class BeaconChain implements IBeaconChain { this.opPool.pruneAll(headState, finalizedState); } - // TODO: finalizedState may not be available after https://github.com/ChainSafe/lodestar/issues/5968. - // In that case implement getCheckpointStateValidatorCount() in regen and use headState instead - if (finalizedState === null) { - this.logger.verbose("Finalized state is null"); - } else if (finalizedState.epochCtx.isAfterEIP6110()) { - const pivotValidatorIndex = finalizedState.validators.length; + const cpEpoch = cp.epoch; + + if (headState === null) { + this.logger.verbose("Head state is null"); + } else if (cpEpoch >= (headState.config.EIP6110_FORK_EPOCH ?? Infinity)) { + const headEpoch = headState.epochCtx.epoch; + const pivotValidatorIndex = headState.epochCtx.historialValidatorLengths.get((headEpoch - cpEpoch) * -1) ?? 0; + // Note EIP-6914 will break this logic - const newFinalizedValidators = finalizedState.epochCtx.unfinalizedPubkey2index.filter( + const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( (index, _pubkey) => index < pivotValidatorIndex ); @@ -964,6 +966,10 @@ export class BeaconChain implements IBeaconChain { this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); } + } + + if (finalizedState && finalizedState.epochCtx.isAfterEIP6110()) { + // finalizedState can be safely casted to 6110 state since cp is already post-6110 if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { // Signal eth1 to stop polling eth1Data this.eth1.stopPollingEth1Data(); diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 5f90808f350..6324f030a40 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -48,6 +48,7 @@ import { SyncCommitteeCacheEmpty, } from "./syncCommitteeCache.js"; import { EpochCacheMetrics } from "../metrics.js"; +import * as immutable from "immutable"; /** `= PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)` */ export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT); @@ -216,6 +217,12 @@ export class EpochCache { // TODO: Helper stats epoch: Epoch; syncPeriod: SyncPeriod; + /** + * state.validators.length of every state at epoch boundary + * They are saved in an increasing order of epoch. + * The last validator length in the list corresponds to the latest checkpoint state. + */ + historialValidatorLengths: immutable.List; constructor(data: { config: BeaconConfig; @@ -244,6 +251,7 @@ export class EpochCache { nextSyncCommitteeIndexed: SyncCommitteeCache; epoch: Epoch; syncPeriod: SyncPeriod; + historialValidatorLengths: immutable.List; }) { this.config = data.config; this.pubkey2index = data.pubkey2index; @@ -271,6 +279,7 @@ export class EpochCache { this.nextSyncCommitteeIndexed = data.nextSyncCommitteeIndexed; this.epoch = data.epoch; this.syncPeriod = data.syncPeriod; + this.historialValidatorLengths = data.historialValidatorLengths; } /** @@ -469,6 +478,7 @@ export class EpochCache { nextSyncCommitteeIndexed, epoch: currentEpoch, syncPeriod: computeSyncPeriodAtEpoch(currentEpoch), + historialValidatorLengths: immutable.List(), }); } @@ -512,6 +522,7 @@ export class EpochCache { nextSyncCommitteeIndexed: this.nextSyncCommitteeIndexed, epoch: this.epoch, syncPeriod: this.syncPeriod, + historialValidatorLengths: this.historialValidatorLengths, }); } @@ -595,6 +606,9 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); + // Add current cpState.validators.length + // Only keep validatorLength for epochs after finalized cpState.epoch + this.historialValidatorLengths = this.historialValidatorLengths.push(state.validators.length).slice((this.epoch - state.finalizedCheckpoint.epoch) * -1); } beforeEpochTransition(): void { From ff702f85c44be9b9e10b4f4ce6fd3448a40c3f62 Mon Sep 17 00:00:00 2001 From: navie Date: Fri, 15 Dec 2023 14:59:50 +0800 Subject: [PATCH 134/155] Polish code --- packages/beacon-node/src/chain/chain.ts | 9 ++++++--- .../state-transition/src/cache/epochCache.ts | 18 ++++++++++-------- packages/state-transition/src/metrics.ts | 2 +- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index c803ad878dd..6d9e388cdec 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -949,12 +949,16 @@ export class BeaconChain implements IBeaconChain { } const cpEpoch = cp.epoch; + const eip6110Epoch = headState?.config.EIP6110_FORK_EPOCH ?? Infinity; if (headState === null) { this.logger.verbose("Head state is null"); - } else if (cpEpoch >= (headState.config.EIP6110_FORK_EPOCH ?? Infinity)) { + } else if (cpEpoch >= eip6110Epoch) { const headEpoch = headState.epochCtx.epoch; - const pivotValidatorIndex = headState.epochCtx.historialValidatorLengths.get((headEpoch - cpEpoch) * -1) ?? 0; + + // Set pivotValidatorIndex to 0 if `historicalValidatorLengths` does not + // contain validator length for cpEpoch to ensure `newFinalizedValidators` to be empty + const pivotValidatorIndex = headState.epochCtx.historicalValidatorLengths.get((headEpoch - cpEpoch) * -1) ?? 0; // Note EIP-6914 will break this logic const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( @@ -965,7 +969,6 @@ export class BeaconChain implements IBeaconChain { if (!newFinalizedValidators.isEmpty()) { this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); } - } if (finalizedState && finalizedState.epochCtx.isAfterEIP6110()) { diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 6324f030a40..3ebf479940b 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,5 +1,6 @@ import {CoordType, PublicKey} from "@chainsafe/bls/types"; import bls from "@chainsafe/bls"; +import * as immutable from "immutable"; import {BLSSignature, CommitteeIndex, Epoch, Slot, ValidatorIndex, phase0, SyncPeriod} from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainConfig} from "@lodestar/config"; import { @@ -30,6 +31,7 @@ import {computeEpochShuffling, EpochShuffling, getShufflingDecisionBlock} from " import {computeBaseRewardPerIncrement, computeSyncParticipantReward} from "../util/syncCommittee.js"; import {sumTargetUnslashedBalanceIncrements} from "../util/targetUnslashedBalance.js"; import {getTotalSlashingsByIncrement} from "../epoch/processSlashings.js"; +import {EpochCacheMetrics} from "../metrics.js"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements.js"; import { Index2PubkeyCache, @@ -47,8 +49,6 @@ import { SyncCommitteeCache, SyncCommitteeCacheEmpty, } from "./syncCommitteeCache.js"; -import { EpochCacheMetrics } from "../metrics.js"; -import * as immutable from "immutable"; /** `= PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT)` */ export const PROPOSER_WEIGHT_FACTOR = PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT); @@ -219,10 +219,10 @@ export class EpochCache { syncPeriod: SyncPeriod; /** * state.validators.length of every state at epoch boundary - * They are saved in an increasing order of epoch. + * They are saved in increasing order of epoch. * The last validator length in the list corresponds to the latest checkpoint state. */ - historialValidatorLengths: immutable.List; + historicalValidatorLengths: immutable.List; constructor(data: { config: BeaconConfig; @@ -279,7 +279,7 @@ export class EpochCache { this.nextSyncCommitteeIndexed = data.nextSyncCommitteeIndexed; this.epoch = data.epoch; this.syncPeriod = data.syncPeriod; - this.historialValidatorLengths = data.historialValidatorLengths; + this.historicalValidatorLengths = data.historialValidatorLengths; } /** @@ -522,7 +522,7 @@ export class EpochCache { nextSyncCommitteeIndexed: this.nextSyncCommitteeIndexed, epoch: this.epoch, syncPeriod: this.syncPeriod, - historialValidatorLengths: this.historialValidatorLengths, + historialValidatorLengths: this.historicalValidatorLengths, }); } @@ -608,7 +608,9 @@ export class EpochCache { this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); // Add current cpState.validators.length // Only keep validatorLength for epochs after finalized cpState.epoch - this.historialValidatorLengths = this.historialValidatorLengths.push(state.validators.length).slice((this.epoch - state.finalizedCheckpoint.epoch) * -1); + this.historicalValidatorLengths = this.historicalValidatorLengths + .push(state.validators.length) + .slice((this.epoch - state.finalizedCheckpoint.epoch) * -1); } beforeEpochTransition(): void { @@ -829,7 +831,7 @@ export class EpochCache { } addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap, metrics?: EpochCacheMetrics): void { - pubkeyMap.forEach((index, pubkey) => this.addFinalizedPubkey(index, pubkey)); + pubkeyMap.forEach((index, pubkey) => this.addFinalizedPubkey(index, pubkey, metrics)); } /** diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index 6d1ca02f20f..7ba3efb0bca 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -22,7 +22,7 @@ export type BeaconStateTransitionMetrics = { export type EpochCacheMetrics = { finalizedPubkeyDuplicateInsert: Gauge; -} +}; type LabelValues = Partial>; From 598024ee6cf803ad7a794234efdccc0a9c1c9449 Mon Sep 17 00:00:00 2001 From: NC Date: Mon, 18 Dec 2023 18:03:44 +0800 Subject: [PATCH 135/155] Migrate state-transition unit tests to vitest --- .../test/unit/cachedBeaconState.test.ts | 40 ++++--------------- .../test/unit/util/deposit.test.ts | 20 +++++----- 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 13ece6d7112..3aba9f12943 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -46,22 +46,10 @@ describe("CachedBeaconState", () => { const state2 = state1.clone(); state2.epochCtx.addPubkey(index2, pubkey2); - expect(state1.epochCtx.getValidatorIndex(pubkey1)).to.equal( - index1, - "addPubkey() is not reflected in getValidatorIndex()" - ); - expect(state2.epochCtx.getValidatorIndex(pubkey1)).to.equal( - index1, - "cloned state does not maintain cache from original state" - ); - expect(state1.epochCtx.getValidatorIndex(pubkey2)).to.equal( - index2, - "original state cache was not updated when inserting pubkeys into cloned state cache" - ); - expect(state2.epochCtx.getValidatorIndex(pubkey2)).to.equal( - index2, - "addPubkey() is not reflected in getValidatorIndex()" - ); + expect(state1.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state2.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state1.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); + expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); }); /* eslint-disable @typescript-eslint/naming-convention */ @@ -93,22 +81,10 @@ describe("CachedBeaconState", () => { const state2 = state1.clone(); state2.epochCtx.addPubkey(index2, pubkey2); - expect(state1.epochCtx.getValidatorIndex(pubkey1)).to.equal( - index1, - "addPubkey() is not reflected in getValidatorIndex()" - ); - expect(state2.epochCtx.getValidatorIndex(pubkey1)).to.equal( - index1, - "cloned state does not maintain cache from original state" - ); - expect(state1.epochCtx.getValidatorIndex(pubkey2)).to.equal( - undefined, - "original state cache was updated when inserting pubkeys into cloned state cache" - ); - expect(state2.epochCtx.getValidatorIndex(pubkey2)).to.equal( - index2, - "addPubkey() is not reflected in getValidatorIndex()" - ); + expect(state1.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state2.epochCtx.getValidatorIndex(pubkey1)).toBe(index1); + expect(state1.epochCtx.getValidatorIndex(pubkey2)).toBe(undefined); + expect(state2.epochCtx.getValidatorIndex(pubkey2)).toBe(index2); }); it("Auto-commit on hashTreeRoot", () => { diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index daea0c369f7..b03a3ee6505 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {ssz} from "@lodestar/types"; import {createChainForkConfig} from "@lodestar/config"; import {MAX_DEPOSITS} from "@lodestar/params"; @@ -18,11 +18,11 @@ describe("getEth1DepositCount", () => { // 1. Should get less than MAX_DEPOSIT pre6110State.eth1DepositIndex = 120; - expect(getEth1DepositCount(pre6110State)).to.equal(3); + expect(getEth1DepositCount(pre6110State)).toBe(3); // 2. Should get MAX_DEPOSIT pre6110State.eth1DepositIndex = 100; - expect(getEth1DepositCount(pre6110State)).to.equal(MAX_DEPOSITS); + expect(getEth1DepositCount(pre6110State)).toBe(MAX_DEPOSITS); }); it("Post 6110 with eth1 deposit", () => { const stateView = ssz.eip6110.BeaconState.defaultViewDU(); @@ -48,15 +48,15 @@ describe("getEth1DepositCount", () => { // 1. Should get less than MAX_DEPOSIT post6110State.eth1DepositIndex = 990; - expect(getEth1DepositCount(post6110State)).to.equal(5); + expect(getEth1DepositCount(post6110State)).toBe(5); // 2. Should get MAX_DEPOSIT post6110State.eth1DepositIndex = 100; - expect(getEth1DepositCount(post6110State)).to.equal(MAX_DEPOSITS); + expect(getEth1DepositCount(post6110State)).toBe(MAX_DEPOSITS); // 3. Should be 0 post6110State.eth1DepositIndex = 1000; - expect(getEth1DepositCount(post6110State)).to.equal(0); + expect(getEth1DepositCount(post6110State)).toBe(0); }); it("Post 6110 without eth1 deposit", () => { const stateView = ssz.eip6110.BeaconState.defaultViewDU(); @@ -83,17 +83,17 @@ describe("getEth1DepositCount", () => { // Before eth1DepositIndex reaching the start index // 1. Should get less than MAX_DEPOSIT post6110State.eth1DepositIndex = 990; - expect(getEth1DepositCount(post6110State)).to.equal(10); + expect(getEth1DepositCount(post6110State)).toBe(10); // 2. Should get MAX_DEPOSIT post6110State.eth1DepositIndex = 983; - expect(getEth1DepositCount(post6110State)).to.equal(MAX_DEPOSITS); + expect(getEth1DepositCount(post6110State)).toBe(MAX_DEPOSITS); // After eth1DepositIndex reaching the start index // 1. Should be 0 post6110State.eth1DepositIndex = 1000; - expect(getEth1DepositCount(post6110State)).to.equal(0); + expect(getEth1DepositCount(post6110State)).toBe(0); post6110State.eth1DepositIndex = 1003; - expect(getEth1DepositCount(post6110State)).to.equal(0); + expect(getEth1DepositCount(post6110State)).toBe(0); }); }); From 75cb384ad0eaf32b9e709f00ab2822c88afd2307 Mon Sep 17 00:00:00 2001 From: NC Date: Fri, 22 Dec 2023 14:14:58 +0800 Subject: [PATCH 136/155] Fix calculation of pivot index --- packages/beacon-node/src/chain/chain.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 76d893b4b01..08eeb17c28c 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -963,7 +963,7 @@ export class BeaconChain implements IBeaconChain { // Set pivotValidatorIndex to 0 if `historicalValidatorLengths` does not // contain validator length for cpEpoch to ensure `newFinalizedValidators` to be empty - const pivotValidatorIndex = headState.epochCtx.historicalValidatorLengths.get((headEpoch - cpEpoch) * -1) ?? 0; + const pivotValidatorIndex = headState.epochCtx.historicalValidatorLengths.get((headEpoch - cpEpoch + 1) * -1) ?? 0; // Note EIP-6914 will break this logic const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( From da84a1990eae30542d824fb10155a441437d5731 Mon Sep 17 00:00:00 2001 From: NC Date: Fri, 22 Dec 2023 14:15:27 +0800 Subject: [PATCH 137/155] `historicalValidatorLengths` only activate post 6110 --- packages/state-transition/src/cache/epochCache.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 3ebf479940b..f6869c39dc4 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -606,11 +606,15 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); - // Add current cpState.validators.length + // 6110 Only: Add current cpState.validators.length // Only keep validatorLength for epochs after finalized cpState.epoch - this.historicalValidatorLengths = this.historicalValidatorLengths - .push(state.validators.length) - .slice((this.epoch - state.finalizedCheckpoint.epoch) * -1); + // eg. [100(epoch 1), 102(epoch 2)].push(104(epoch 3)), this.epoch = 3, finalized cp epoch = 1 + // We keep the last (3 - 1) items = [102, 104] + if (currEpoch >= this.config.EIP6110_FORK_EPOCH) { + this.historicalValidatorLengths = this.historicalValidatorLengths + .push(state.validators.length) + .slice((this.epoch - state.finalizedCheckpoint.epoch) * -1); + } } beforeEpochTransition(): void { From ad50d55285634d7df268efcbd1694d9dacf3ade5 Mon Sep 17 00:00:00 2001 From: NC Date: Fri, 22 Dec 2023 14:15:34 +0800 Subject: [PATCH 138/155] Update sim test --- packages/beacon-node/test/sim/6110-interop.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 93f063291cd..58850ad7e1f 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -377,6 +377,10 @@ describe("executionEngine / ExecutionEngineHttp", function () { `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` ); } + // epochCtx.historicalValidatorsLength should be empty since no epoch transition has happened. + if (!epochCtx.historicalValidatorLengths.isEmpty()) { + throw Error("Historical validator lengths is modified"); + } await new Promise((resolve, _reject) => { bn.chain.clock.on(ClockEvent.epoch, (epoch) => { @@ -407,6 +411,12 @@ describe("executionEngine / ExecutionEngineHttp", function () { if (!epochCtx.unfinalizedPubkey2index.isEmpty()) { throw Error("Unfinalized cache still contains new validator"); } + // After 4 epochs, headState's finalized cp epoch should be 2 + // Its historicalValidatorLengths should store lengths for epoch 3 and 4 hence size should be 2 + console.log(`haha ${epochCtx.historicalValidatorLengths.size}`); + if (epochCtx.historicalValidatorLengths.size !== 2) { + throw Error("Historical validator lengths is not updated correctly") + } if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { throw Error("state.depositReceiptsStartIndex is not set upon processing new deposit receipt"); From 63f20dd43ad1031c10994758121dc96621837078 Mon Sep 17 00:00:00 2001 From: NC Date: Fri, 22 Dec 2023 14:30:45 +0800 Subject: [PATCH 139/155] Lint --- packages/beacon-node/src/chain/chain.ts | 3 ++- packages/beacon-node/test/sim/6110-interop.test.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 08eeb17c28c..6f0dc7307d5 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -963,7 +963,8 @@ export class BeaconChain implements IBeaconChain { // Set pivotValidatorIndex to 0 if `historicalValidatorLengths` does not // contain validator length for cpEpoch to ensure `newFinalizedValidators` to be empty - const pivotValidatorIndex = headState.epochCtx.historicalValidatorLengths.get((headEpoch - cpEpoch + 1) * -1) ?? 0; + const pivotValidatorIndex = + headState.epochCtx.historicalValidatorLengths.get((headEpoch - cpEpoch + 1) * -1) ?? 0; // Note EIP-6914 will break this logic const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 58850ad7e1f..52da74756d3 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -415,7 +415,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { // Its historicalValidatorLengths should store lengths for epoch 3 and 4 hence size should be 2 console.log(`haha ${epochCtx.historicalValidatorLengths.size}`); if (epochCtx.historicalValidatorLengths.size !== 2) { - throw Error("Historical validator lengths is not updated correctly") + throw Error("Historical validator lengths is not updated correctly"); } if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { From 4f2174b00faa729707e9f78c6f1f44e6568925c9 Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 10 Jan 2024 16:19:39 +0800 Subject: [PATCH 140/155] Update packages/state-transition/src/cache/epochCache.ts Co-authored-by: Lion - dapplion <35266934+dapplion@users.noreply.github.com> --- packages/state-transition/src/cache/epochCache.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index f6869c39dc4..b92a4f4a684 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -806,7 +806,6 @@ export class EpochCache { * Return finalized pubkey given the validator index. * Only finalized pubkey as we do not store unfinalized pubkey because no where in the spec has a * need to make such enquiry - * */ getPubkey(index: ValidatorIndex): PublicKey | undefined { return this.index2pubkey[index]; From cd9d659f1ead9f8bcf5508bcf99498ea3eb230e9 Mon Sep 17 00:00:00 2001 From: navie Date: Wed, 10 Jan 2024 17:44:15 +0800 Subject: [PATCH 141/155] Improve readability on historicalValidatorLengths --- packages/beacon-node/src/chain/chain.ts | 26 ++++++++++--------- .../state-transition/src/cache/epochCache.ts | 21 ++++++++++++--- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 6f0dc7307d5..fccab3571b3 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -961,19 +961,21 @@ export class BeaconChain implements IBeaconChain { } else if (cpEpoch >= eip6110Epoch) { const headEpoch = headState.epochCtx.epoch; - // Set pivotValidatorIndex to 0 if `historicalValidatorLengths` does not - // contain validator length for cpEpoch to ensure `newFinalizedValidators` to be empty - const pivotValidatorIndex = - headState.epochCtx.historicalValidatorLengths.get((headEpoch - cpEpoch + 1) * -1) ?? 0; - - // Note EIP-6914 will break this logic - const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( - (index, _pubkey) => index < pivotValidatorIndex - ); + // Get the validator.length from the state at cpEpoch + // We are confident the last element in the list is from headEpoch + // Thus we query from the end of the list. (cpEpoch - headEpoch - 1) is negative number + const pivotValidatorIndex = headState.epochCtx.historicalValidatorLengths.get(cpEpoch - headEpoch - 1); + + if (pivotValidatorIndex !== undefined) { + // Note EIP-6914 will break this logic + const newFinalizedValidators = headState.epochCtx.unfinalizedPubkey2index.filter( + (index, _pubkey) => index < pivotValidatorIndex + ); - // Populate finalized pubkey cache and remove unfinalized pubkey cache - if (!newFinalizedValidators.isEmpty()) { - this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); + // Populate finalized pubkey cache and remove unfinalized pubkey cache + if (!newFinalizedValidators.isEmpty()) { + this.regen.updateUnfinalizedPubkeys(newFinalizedValidators); + } } } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index b92a4f4a684..80c06f7b51a 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -220,7 +220,10 @@ export class EpochCache { /** * state.validators.length of every state at epoch boundary * They are saved in increasing order of epoch. - * The last validator length in the list corresponds to the latest checkpoint state. + * The first validator length in the list corresponds to the state AFTER the latest finalized checkpoint state. ie. state.finalizedCheckpoint.epoch - 1 + * The last validator length corresponds to the latest epoch state ie. this.epoch + * eg. latest epoch = 105, latest finalized cp state epoch = 102 + * then the list will be (in terms of epoch) [103, 104, 105] */ historicalValidatorLengths: immutable.List; @@ -611,9 +614,19 @@ export class EpochCache { // eg. [100(epoch 1), 102(epoch 2)].push(104(epoch 3)), this.epoch = 3, finalized cp epoch = 1 // We keep the last (3 - 1) items = [102, 104] if (currEpoch >= this.config.EIP6110_FORK_EPOCH) { - this.historicalValidatorLengths = this.historicalValidatorLengths - .push(state.validators.length) - .slice((this.epoch - state.finalizedCheckpoint.epoch) * -1); + this.historicalValidatorLengths = this.historicalValidatorLengths.push(state.validators.length); + + // If number of validatorLengths we want to keep exceeds the current list size, it implies + // finalized checkpoint hasn't advanced, and no need to slice + const hasFinalizedCpAdvanced = + this.epoch - state.finalizedCheckpoint.epoch >= this.historicalValidatorLengths.size; + + if (hasFinalizedCpAdvanced) { + // We use finalized cp epoch - this.epoch which is a negative number to keep the last n entries and discard the rest + this.historicalValidatorLengths = this.historicalValidatorLengths.slice( + state.finalizedCheckpoint.epoch - this.epoch + ); + } } } From 6162ee6aa1c44d2d3b8e067e2b6958d046b746ec Mon Sep 17 00:00:00 2001 From: navie Date: Wed, 10 Jan 2024 18:47:29 +0800 Subject: [PATCH 142/155] Update types --- packages/types/src/allForks/sszTypes.ts | 1 - packages/types/src/allForks/types.ts | 2 +- packages/types/src/eip6110/sszTypes.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 0d7c54eb075..b633edff997 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -193,7 +193,6 @@ export const allForksBlobs = { }, eip6110: { BlobSidecar: deneb.BlobSidecar, - BlindedBlobSidecar: deneb.BlindedBlobSidecar, ExecutionPayloadAndBlobsBundle: eip6110.ExecutionPayloadAndBlobsBundle, }, }; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 46e4ff34362..d3a8dd6e1cd 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -392,5 +392,5 @@ export type AllForksLightClientSSZTypes = { export type AllForksBlobsSSZTypes = { BlobSidecar: AllForksTypeOf; - ExecutionPayloadAndBlobsBundle: AllForksTypeOf; + ExecutionPayloadAndBlobsBundle: AllForksTypeOf; }; diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts index f4380bd6002..d787dc5acce 100644 --- a/packages/types/src/eip6110/sszTypes.ts +++ b/packages/types/src/eip6110/sszTypes.ts @@ -100,7 +100,7 @@ export const SignedBlindedBeaconBlock = new ContainerType( export const BuilderBid = new ContainerType( { header: ExecutionPayloadHeader, // Modified in EIP6110 - blindedBlobsBundle: denebSsz.BlindedBlobsBundle, + blindedBlobsBundle: denebSsz.BlobKzgCommitments, value: UintBn256, pubkey: BLSPubkey, }, From a1b7e0c4557ccd29208641089b5fdf45132e3549 Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 10 Jan 2024 20:02:45 +0800 Subject: [PATCH 143/155] Fix calculation --- packages/state-transition/src/cache/epochCache.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index a023c7a5b88..7813b72cc73 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -621,7 +621,7 @@ export class EpochCache { // If number of validatorLengths we want to keep exceeds the current list size, it implies // finalized checkpoint hasn't advanced, and no need to slice const hasFinalizedCpAdvanced = - this.epoch - state.finalizedCheckpoint.epoch >= this.historicalValidatorLengths.size; + this.epoch - state.finalizedCheckpoint.epoch < this.historicalValidatorLengths.size; if (hasFinalizedCpAdvanced) { // We use finalized cp epoch - this.epoch which is a negative number to keep the last n entries and discard the rest From feb87322331cd6137f396d684f6dc197c6df9679 Mon Sep 17 00:00:00 2001 From: NC Date: Wed, 10 Jan 2024 20:03:43 +0800 Subject: [PATCH 144/155] Add eth1data poll todo --- packages/beacon-node/src/chain/chain.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index c39934682a6..d348c212d1b 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -11,7 +11,6 @@ import { isCachedBeaconState, Index2PubkeyCache, PubkeyIndexMap, - CachedBeaconStateEIP6110, EpochShuffling, } from "@lodestar/state-transition"; import {BeaconConfig} from "@lodestar/config"; @@ -965,13 +964,15 @@ export class BeaconChain implements IBeaconChain { } } - if (finalizedState && finalizedState.epochCtx.isAfterEIP6110()) { - // finalizedState can be safely casted to 6110 state since cp is already post-6110 - if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { - // Signal eth1 to stop polling eth1Data - this.eth1.stopPollingEth1Data(); - } - } + // TODO-6110: Deprecating eth1Data poll requires a check on a finalized checkpoint state. + // Will resolve this later + // if (cpEpoch >= (this.config.EIP6110_FORK_EPOCH ?? Infinity)) { + // // finalizedState can be safely casted to 6110 state since cp is already post-6110 + // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { + // // Signal eth1 to stop polling eth1Data + // this.eth1.stopPollingEth1Data(); + // } + // } } async updateBeaconProposerData(epoch: Epoch, proposers: ProposerPreparationData[]): Promise { From 86899b8513dffa27c1ce1b6bc37ba3c835888f41 Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 18 Jan 2024 19:04:52 +0800 Subject: [PATCH 145/155] Add epochCache.getValidatorCountAtEpoch --- packages/beacon-node/src/chain/chain.ts | 4 +--- .../state-transition/src/cache/epochCache.ts | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index d348c212d1b..126c3f5e2c9 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -944,12 +944,10 @@ export class BeaconChain implements IBeaconChain { if (headState === null) { this.logger.verbose("Head state is null"); } else if (cpEpoch >= eip6110Epoch) { - const headEpoch = headState.epochCtx.epoch; - // Get the validator.length from the state at cpEpoch // We are confident the last element in the list is from headEpoch // Thus we query from the end of the list. (cpEpoch - headEpoch - 1) is negative number - const pivotValidatorIndex = headState.epochCtx.historicalValidatorLengths.get(cpEpoch - headEpoch - 1); + const pivotValidatorIndex = headState.epochCtx.getValidatorCountAtEpoch(cpEpoch); if (pivotValidatorIndex !== undefined) { // Note EIP-6914 will break this logic diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 7813b72cc73..9b6a2ec6e67 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -225,7 +225,7 @@ export class EpochCache { * eg. latest epoch = 105, latest finalized cp state epoch = 102 * then the list will be (in terms of epoch) [103, 104, 105] */ - historicalValidatorLengths: immutable.List; + private historicalValidatorLengths: immutable.List; constructor(data: { config: BeaconConfig; @@ -972,6 +972,25 @@ export class EpochCache { isAfterEIP6110(): boolean { return this.epoch >= (this.config.EIP6110_FORK_EPOCH ?? Infinity); } + + getValidatorCountAtEpoch(targetEpoch: Epoch): number | undefined { + const currentEpoch = this.epoch; + + if (targetEpoch === currentEpoch) { + return this.historicalValidatorLengths.get(-1); + } + + // Attempt to get validator count from future epoch + if (targetEpoch > currentEpoch) { + return undefined; + } + + // targetEpoch is so far back that historicalValidatorLengths doesnt contain such info + if (targetEpoch < currentEpoch - this.historicalValidatorLengths.size + 1) { + return undefined; + } + return this.historicalValidatorLengths.get(targetEpoch - currentEpoch - 1); + } } function getEffectiveBalanceIncrementsByteLen(validatorCount: number): number { From 091181b8eb1815deb9a1691499205cf523913670 Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 18 Jan 2024 19:06:17 +0800 Subject: [PATCH 146/155] Add todo --- packages/beacon-node/src/eth1/eth1DepositDataTracker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index d30c80f4d81..4dbececefa2 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -116,6 +116,7 @@ export class Eth1DepositDataTracker { } } + // TODO 6110: Figure out how an elegant way to stop eth1data polling stopPollingEth1Data(): void { this.stopPolling = true; } From 6673f7e3595a5c79f963c80550a4b3a00f800b0a Mon Sep 17 00:00:00 2001 From: NC Date: Thu, 18 Jan 2024 19:30:44 +0800 Subject: [PATCH 147/155] Add getStateIterator for state cache --- .../beacon-node/src/chain/stateCache/fifoBlockStateCache.ts | 4 ++++ .../src/chain/stateCache/persistentCheckpointsCache.ts | 4 ++++ .../beacon-node/src/chain/stateCache/stateContextCache.ts | 4 ++++ .../src/chain/stateCache/stateContextCheckpointsCache.ts | 4 ++++ packages/beacon-node/src/chain/stateCache/types.ts | 2 ++ 5 files changed, 18 insertions(+) diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index 854983101c0..4f35ddacfb9 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -172,6 +172,10 @@ export class FIFOBlockStateCache implements BlockStateCache { })); } + getStateIterator(): Iterator { + throw new Error("Method not implemented."); + } + /** * For unit test only. */ diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 8ad5c509811..54e3a762501 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -570,6 +570,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { }); } + getStateIterator(): Iterator { + throw new Error("Method not implemented."); + } + /** ONLY FOR DEBUGGING PURPOSES. For spec tests on error */ dumpCheckpointKeys(): string[] { return Array.from(this.cache.keys()); diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 8e6132d4433..cedd7006143 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -150,6 +150,10 @@ export class StateContextCache implements BlockStateCache { })); } + getStateIterator(): Iterator { + return this.cache.values(); + } + private deleteAllEpochItems(epoch: Epoch): void { for (const rootHex of this.epochIndex.get(epoch) || []) { this.cache.delete(rootHex); diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index a177db9b7c8..3a1cf3b0709 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -167,6 +167,10 @@ export class CheckpointStateCache implements CheckpointStateCacheInterface { })); } + getStateIterator(): Iterator { + return this.cache.values(); + } + /** ONLY FOR DEBUGGING PURPOSES. For spec tests on error */ dumpCheckpointKeys(): string[] { return Array.from(this.cache.keys()); diff --git a/packages/beacon-node/src/chain/stateCache/types.ts b/packages/beacon-node/src/chain/stateCache/types.ts index 5867d7d356c..6e00b4a7e1c 100644 --- a/packages/beacon-node/src/chain/stateCache/types.ts +++ b/packages/beacon-node/src/chain/stateCache/types.ts @@ -28,6 +28,7 @@ export interface BlockStateCache { prune(headStateRootHex: RootHex): void; deleteAllBeforeEpoch(finalizedEpoch: Epoch): void; dumpSummary(): routes.lodestar.StateCacheItem[]; + getStateIterator(): Iterator; // Expose beacon states stored in cache. Use with caution } /** @@ -65,6 +66,7 @@ export interface CheckpointStateCache { processState(blockRootHex: RootHex, state: CachedBeaconStateAllForks): Promise; clear(): void; dumpSummary(): routes.lodestar.StateCacheItem[]; + getStateIterator(): Iterator; // Expose beacon states stored in cache. Use with caution } export enum CacheItemType { From b07a7f3bfc9ad0c878e3929d69a86ec551e7e313 Mon Sep 17 00:00:00 2001 From: NC Date: Mon, 22 Jan 2024 12:21:20 +0800 Subject: [PATCH 148/155] Partial commit --- .../beacon-node/src/chain/regen/queued.ts | 43 +++++++++++++++++++ .../chain/stateCache/fifoBlockStateCache.ts | 2 +- .../stateCache/persistentCheckpointsCache.ts | 2 +- .../src/chain/stateCache/stateContextCache.ts | 2 +- .../stateContextCheckpointsCache.ts | 2 +- .../beacon-node/src/chain/stateCache/types.ts | 4 +- .../src/metrics/metrics/lodestar.ts | 40 +++++++---------- 7 files changed, 64 insertions(+), 31 deletions(-) diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index c7b6893d278..d4352d4aa9d 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -128,6 +128,49 @@ export class QueuedStateRegenerator implements IStateRegenerator { updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { this.stateCache.updateUnfinalizedPubkeys(validators); this.stateCache.updateUnfinalizedPubkeys.bind(this.checkpointStateCache)(validators); + + let numStatesUpdated = 0; + const states = this.stateCache.getStates(); + const cpStates = this.checkpointStateCache.getStates(); + + + // Add finalized pubkeys to all states. + const addTimer = this.metrics?.regenFnAddPubkeyTime.startTimer(); + + // We only need to add pubkeys to any one of the states since the finalized caches is shared globally across all states + const firstState = (states.next().value ?? cpStates.next().value) as CachedBeaconStateAllForks | undefined; + + if (firstState !== undefined) { + firstState.epochCtx.addFinalizedPubkeys(validators, this.metrics?.epochCache ?? undefined); + } else { + this.logger.warn("Attempt to delete finalized pubkey from unfinalized pubkey cache. But no state is available"); + } + + addTimer?.(); + + // Delete finalized pubkeys from unfinalized pubkey cache for all states + const deleteTimer = this.metrics?.regenFnDeletePubkeyTime.startTimer(); + const pubkeysToDelete = Array.from(validators.keys()); + + for (const s of states) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + numStatesUpdated++; + } + + for (const s of cpStates) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + numStatesUpdated++; + } + + // Since first state is consumed from the iterator. Will need to perform delete explicitly + if (firstState !== undefined) { + firstState?.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + numStatesUpdated++; + } + + deleteTimer?.(); + + this.metrics?.regenFnNumStatesUpdated.observe(numStatesUpdated); } /** diff --git a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts index 4f35ddacfb9..ecf74a01b07 100644 --- a/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts +++ b/packages/beacon-node/src/chain/stateCache/fifoBlockStateCache.ts @@ -172,7 +172,7 @@ export class FIFOBlockStateCache implements BlockStateCache { })); } - getStateIterator(): Iterator { + getStates(): IterableIterator { throw new Error("Method not implemented."); } diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 54e3a762501..18a7f507cf4 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -570,7 +570,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { }); } - getStateIterator(): Iterator { + getStates(): IterableIterator { throw new Error("Method not implemented."); } diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index cedd7006143..7fc4f845dd6 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -150,7 +150,7 @@ export class StateContextCache implements BlockStateCache { })); } - getStateIterator(): Iterator { + getStates(): IterableIterator { return this.cache.values(); } diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts index 3a1cf3b0709..82db0b8efcb 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCheckpointsCache.ts @@ -167,7 +167,7 @@ export class CheckpointStateCache implements CheckpointStateCacheInterface { })); } - getStateIterator(): Iterator { + getStates(): IterableIterator { return this.cache.values(); } diff --git a/packages/beacon-node/src/chain/stateCache/types.ts b/packages/beacon-node/src/chain/stateCache/types.ts index 6e00b4a7e1c..29067d47a79 100644 --- a/packages/beacon-node/src/chain/stateCache/types.ts +++ b/packages/beacon-node/src/chain/stateCache/types.ts @@ -28,7 +28,7 @@ export interface BlockStateCache { prune(headStateRootHex: RootHex): void; deleteAllBeforeEpoch(finalizedEpoch: Epoch): void; dumpSummary(): routes.lodestar.StateCacheItem[]; - getStateIterator(): Iterator; // Expose beacon states stored in cache. Use with caution + getStates(): IterableIterator; // Expose beacon states stored in cache. Use with caution } /** @@ -66,7 +66,7 @@ export interface CheckpointStateCache { processState(blockRootHex: RootHex, state: CachedBeaconStateAllForks): Promise; clear(): void; dumpSummary(): routes.lodestar.StateCacheItem[]; - getStateIterator(): Iterator; // Expose beacon states stored in cache. Use with caution + getStates(): IterableIterator; // Expose beacon states stored in cache. Use with caution } export enum CacheItemType { diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index 38dc0ed29fd..a48b873af4f 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1091,21 +1091,6 @@ export function createLodestarMetrics( help: "Histogram of cloned count per state every time state.clone() is called", buckets: [1, 2, 5, 10, 50, 250], }), - numStatesUpdated: register.histogram({ - name: "lodestar_state_cache_state_updated_count", - help: "Histogram of number of state cache items updated every time removing and adding pubkeys to pubkey cache", - buckets: [1, 2, 5, 10, 50, 250], - }), - addPubkeyTime: register.histogram({ - name: "lodestar_state_cache_state_add_pubkey_time_seconds", - help: "Historgram of time spent on adding pubkeys to all state cache items in seconds", - buckets: [0.01, 0.1, 0.5, 1, 2, 5], - }), - deletePubkeyTime: register.histogram({ - name: "lodestar_state_cache_state_delete_pubkey_time_seconds", - help: "Histrogram of time spent on deleting pubkeys from all state cache items in seconds", - buckets: [0.01, 0.1, 0.5, 1, 2, 5], - }), }, cpStateCache: { @@ -1149,16 +1134,6 @@ export function createLodestarMetrics( help: "Histogram of number of state cache items updated every time removing and adding pubkeys to pubkey cache", buckets: [1, 2, 5, 10, 50, 250], }), - addPubkeyTime: register.histogram({ - name: "lodestar_cp_state_cache_state_add_pubkey_time_seconds", - help: "Avg min max of total time spent on adding pubkeys to all state cache items in seconds", - buckets: [0.01, 0.1, 0.5, 1, 2, 5], - }), - deletePubkeyTime: register.histogram({ - name: "lodestar_cp_state_cache_state_delete_pubkey_time_seconds", - help: "Avg min max of total time spent on deleting pubkeys from all state cache items in seconds", - buckets: [0.01, 0.1, 0.5, 1, 2, 5], - }), statePersistDuration: register.histogram({ name: "lodestar_cp_state_cache_state_persist_seconds", help: "Histogram of time to persist state to db", @@ -1315,6 +1290,21 @@ export function createLodestarMetrics( help: "regen function total errors", labelNames: ["entrypoint", "caller"], }), + regenFnAddPubkeyTime: register.histogram({ + name: "lodestar_regen_fn_add_pubkey_time_seconds", + help: "Historgram of time spent on adding pubkeys to all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), + regenFnDeletePubkeyTime: register.histogram({ + name: "lodestar_regen_fn_delete_pubkey_time_seconds", + help: "Histrogram of time spent on deleting pubkeys from all state cache items in seconds", + buckets: [0.01, 0.1, 0.5, 1, 2, 5], + }), + regenFnNumStatesUpdated: register.histogram({ + name: "lodestar_regen_state_cache_state_updated_count", + help: "Histogram of number of state cache items updated every time removing pubkeys from unfinalized cache", + buckets: [1, 2, 5, 10, 50, 250], + }), unhandledPromiseRejections: register.gauge({ name: "lodestar_unhandled_promise_rejections_total", help: "UnhandledPromiseRejection total count", From ad914fa3a2039b3b68dd42102717b174a63b0d74 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 22 Jan 2024 15:04:33 +0800 Subject: [PATCH 149/155] Update perf test --- .../updateUnfinalizedPubkeys.test.ts | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 049917e25c9..8457dc9bae9 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -2,9 +2,13 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {Map} from "immutable"; import {PubkeyIndexMap} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; -import {interopPubkeysCached} from "@lodestar/state-transition/test/utils/interop.js"; import {generateCached6110State} from "../../../utils/state.js"; import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; +import {toBufferBE} from "bigint-buffer"; +import {digest} from "@chainsafe/as-sha256"; +import type {SecretKey} from "@chainsafe/bls/types"; +import bls from "@chainsafe/bls"; +import {bytesToBigInt, intToBytes} from "@lodestar/utils"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz // ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1496.612 ops/s 668.1760 us/op - 276 runs 3.39 s @@ -62,7 +66,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { function generatePubkey2Index(startIndex: number, endIndex: number): PubkeyIndexMap { const pubkey2Index = new PubkeyIndexMap(); - const pubkeys = interopPubkeysCached(endIndex - startIndex); + const pubkeys = generatePubkeys(endIndex - startIndex); for (let i = startIndex; i < endIndex; i++) { pubkey2Index.set(pubkeys[i], i); @@ -70,4 +74,21 @@ describe("updateUnfinalizedPubkeys perf tests", function () { return pubkey2Index; } + + function generatePubkeys(validatorCount: number): Uint8Array[] { + const keys = []; + + for (let i = 0; i < validatorCount; i++) { + const sk = generatePrivateKey(i); + const pk = sk.toPublicKey().toBytes(); + keys.push(pk); + } + + return keys; + } + + function generatePrivateKey(index: number): SecretKey { + const secretKeyBytes = toBufferBE(bytesToBigInt(digest(intToBytes(index, 32))) % BigInt("38581184513"), 32); + return bls.SecretKey.fromBytes(secretKeyBytes); + } }); From 5841771d4a0e6bec837f9e4a45964b5c64da1ed1 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 22 Jan 2024 15:09:43 +0800 Subject: [PATCH 150/155] updateUnfinalizedPubkeys directly modify states from regen --- .../beacon-node/src/chain/regen/queued.ts | 3 -- .../src/chain/stateCache/stateContextCache.ts | 25 +--------------- .../updateUnfinalizedPubkeys.test.ts | 29 +++++++++++++++---- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index d4352d4aa9d..3bb67ceca34 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -126,9 +126,6 @@ export class QueuedStateRegenerator implements IStateRegenerator { * and add them to epochCtx.pubkey2index and epochCtx.index2pubkey */ updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - this.stateCache.updateUnfinalizedPubkeys(validators); - this.stateCache.updateUnfinalizedPubkeys.bind(this.checkpointStateCache)(validators); - let numStatesUpdated = 0; const states = this.stateCache.getStates(); const cpStates = this.checkpointStateCache.getStates(); diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index 7fc4f845dd6..d57c9972f7c 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -22,7 +22,7 @@ export class StateContextCache implements BlockStateCache { private readonly cache: MapTracker; /** Epoch -> Set */ private readonly epochIndex = new Map>(); - private readonly metrics: (Metrics["stateCache"] & Metrics["epochCache"]) | null | undefined; + private readonly metrics: (Metrics["stateCache"]) | null | undefined; /** * Strong reference to prevent head state from being pruned. * null if head state is being regen and not available at the moment. @@ -85,29 +85,6 @@ export class StateContextCache implements BlockStateCache { return this.cache.size; } - updateUnfinalizedPubkeys(validators: UnfinalizedPubkeyIndexMap): void { - let totalNumStatesUpdated = 0; - - const addTimer = this.metrics?.addPubkeyTime.startTimer(); - // Don't use a try/catch, only count run without exceptions - if (this.cache.size > 0) { - const st = this.cache.values().next().value as CachedBeaconStateAllForks; - // Only need to insert once since finalized cache is shared across all states globally - st.epochCtx.addFinalizedPubkeys(validators, this.metrics ?? undefined); - } - addTimer?.(); - - const deleteTimer = this.metrics?.deletePubkeyTime.startTimer(); - // Don't use a try/catch, only count run without exceptions - for (const cachedState of this.cache.values()) { - cachedState.epochCtx.deleteUnfinalizedPubkeys(validators.keys()); - totalNumStatesUpdated++; - } - deleteTimer?.(); - - this.metrics?.numStatesUpdated.observe(totalNumStatesUpdated); - } - /** * TODO make this more robust. * Without more thought, this currently breaks our assumptions about recent state availablity diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 8457dc9bae9..ff2cb5881f8 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -1,6 +1,6 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {Map} from "immutable"; -import {PubkeyIndexMap} from "@lodestar/state-transition"; +import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; import {generateCached6110State} from "../../../utils/state.js"; import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; @@ -11,9 +11,9 @@ import bls from "@chainsafe/bls"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz -// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1496.612 ops/s 668.1760 us/op - 276 runs 3.39 s -// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 174.9926 ops/s 5.714528 ms/op - 142 runs 2.19 s -// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 10.17848 ops/s 98.24650 ms/op - 28 runs 3.75 s +// ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1444.173 ops/s 692.4380 us/op - 1057 runs 6.03 s +// ✔ updateUnfinalizedPubkeys - updating 100 pubkeys 189.5965 ops/s 5.274358 ms/op - 57 runs 1.15 s +// ✔ updateUnfinalizedPubkeys - updating 1000 pubkeys 12.90495 ops/s 77.48967 ms/op - 13 runs 1.62 s describe("updateUnfinalizedPubkeys perf tests", function () { setBenchOpts({noThreshold: true}); @@ -58,8 +58,25 @@ describe("updateUnfinalizedPubkeys perf tests", function () { const newFinalizedValidators = baseState.epochCtx.unfinalizedPubkey2index.filter( (index, _pubkey) => index < numPubkeysToBeFinalized ); - stateCache.updateUnfinalizedPubkeys(newFinalizedValidators); - stateCache.updateUnfinalizedPubkeys.bind(checkpointStateCache)(newFinalizedValidators); + + const states = stateCache.getStates(); + const cpStates = checkpointStateCache.getStates(); + + const firstState = states.next().value as CachedBeaconStateAllForks; + firstState.epochCtx.addFinalizedPubkeys(newFinalizedValidators); + + const pubkeysToDelete = Array.from(newFinalizedValidators.keys()); + + firstState.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + + for (const s of states) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + } + + for (const s of cpStates) { + s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); + } + }, }); } From 35c97dad74456c5c2797b69871176d86106f5045 Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 22 Jan 2024 15:49:16 +0800 Subject: [PATCH 151/155] Update sim test. Lint --- .../beacon-node/src/chain/regen/queued.ts | 1 - .../src/chain/stateCache/stateContextCache.ts | 4 ++-- .../updateUnfinalizedPubkeys.test.ts | 11 +++++------ .../beacon-node/test/sim/6110-interop.test.ts | 19 +++++++++++++------ packages/types/src/allForks/types.ts | 4 +++- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 3bb67ceca34..e69e9705a59 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -130,7 +130,6 @@ export class QueuedStateRegenerator implements IStateRegenerator { const states = this.stateCache.getStates(); const cpStates = this.checkpointStateCache.getStates(); - // Add finalized pubkeys to all states. const addTimer = this.metrics?.regenFnAddPubkeyTime.startTimer(); diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts index d57c9972f7c..02fae18a328 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/stateContextCache.ts @@ -1,6 +1,6 @@ import {toHexString} from "@chainsafe/ssz"; import {Epoch, RootHex} from "@lodestar/types"; -import {CachedBeaconStateAllForks, UnfinalizedPubkeyIndexMap} from "@lodestar/state-transition"; +import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {routes} from "@lodestar/api"; import {Metrics} from "../../metrics/index.js"; import {MapTracker} from "./mapMetrics.js"; @@ -22,7 +22,7 @@ export class StateContextCache implements BlockStateCache { private readonly cache: MapTracker; /** Epoch -> Set */ private readonly epochIndex = new Map>(); - private readonly metrics: (Metrics["stateCache"]) | null | undefined; + private readonly metrics: Metrics["stateCache"] | null | undefined; /** * Strong reference to prevent head state from being pruned. * null if head state is being regen and not available at the moment. diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index ff2cb5881f8..59eee6ab83b 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -1,14 +1,14 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {Map} from "immutable"; -import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; -import {ssz} from "@lodestar/types"; -import {generateCached6110State} from "../../../utils/state.js"; -import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; import {toBufferBE} from "bigint-buffer"; import {digest} from "@chainsafe/as-sha256"; import type {SecretKey} from "@chainsafe/bls/types"; import bls from "@chainsafe/bls"; +import {ssz} from "@lodestar/types"; +import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; +import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; +import {generateCached6110State} from "../../../utils/state.js"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz // ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1444.173 ops/s 692.4380 us/op - 1057 runs 6.03 s @@ -72,11 +72,10 @@ describe("updateUnfinalizedPubkeys perf tests", function () { for (const s of states) { s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); } - + for (const s of cpStates) { s.epochCtx.deleteUnfinalizedPubkeys(pubkeysToDelete); } - }, }); } diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/6110-interop.test.ts index 52da74756d3..32f6750975a 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/6110-interop.test.ts @@ -377,8 +377,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { `Unfinalized cache is missing the expected validator. Size: ${epochCtx.unfinalizedPubkey2index.size}` ); } - // epochCtx.historicalValidatorsLength should be empty since no epoch transition has happened. - if (!epochCtx.historicalValidatorLengths.isEmpty()) { + // validator count at epoch 1 should be empty at this point since no epoch transition has happened. + if (epochCtx.getValidatorCountAtEpoch(1) !== undefined) { throw Error("Historical validator lengths is modified"); } @@ -412,10 +412,17 @@ describe("executionEngine / ExecutionEngineHttp", function () { throw Error("Unfinalized cache still contains new validator"); } // After 4 epochs, headState's finalized cp epoch should be 2 - // Its historicalValidatorLengths should store lengths for epoch 3 and 4 hence size should be 2 - console.log(`haha ${epochCtx.historicalValidatorLengths.size}`); - if (epochCtx.historicalValidatorLengths.size !== 2) { - throw Error("Historical validator lengths is not updated correctly"); + // epochCtx should only have validator count for epoch 3 and 4. + if (epochCtx.getValidatorCountAtEpoch(4) === undefined || epochCtx.getValidatorCountAtEpoch(3) === undefined) { + throw Error("Missing historical validator length for epoch 3 or 4"); + } + + if (epochCtx.getValidatorCountAtEpoch(4) !== 33 || epochCtx.getValidatorCountAtEpoch(3) !== 33) { + throw Error("Incorrect historical validator length for epoch 3 or 4"); + } + + if (epochCtx.getValidatorCountAtEpoch(2) !== undefined || epochCtx.getValidatorCountAtEpoch(1) !== undefined) { + throw Error("Historical validator length for epoch 1 or 2 is not dropped properly"); } if (headState.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index d3a8dd6e1cd..7454f4b5a2a 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -392,5 +392,7 @@ export type AllForksLightClientSSZTypes = { export type AllForksBlobsSSZTypes = { BlobSidecar: AllForksTypeOf; - ExecutionPayloadAndBlobsBundle: AllForksTypeOf; + ExecutionPayloadAndBlobsBundle: AllForksTypeOf< + typeof denebSsz.ExecutionPayloadAndBlobsBundle | typeof eip6110Ssz.ExecutionPayloadAndBlobsBundle + >; }; From 7da35981f4861078459fffb6abe2f975b6065fbf Mon Sep 17 00:00:00 2001 From: navie Date: Mon, 22 Jan 2024 16:00:33 +0800 Subject: [PATCH 152/155] Add todo --- packages/beacon-node/src/eth1/eth1DepositDataTracker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index 4dbececefa2..4e3940fcde4 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -73,7 +73,7 @@ export class Eth1DepositDataTracker { private eth1GetLogsBatchSizeDynamic = MAX_BLOCKS_PER_LOG_QUERY; private readonly forcedEth1DataVote: phase0.Eth1Data | null; /** To stop `runAutoUpdate()` in addition to AbortSignal */ - private stopPolling: boolean = false; + private stopPolling: boolean; constructor( opts: Eth1Options, @@ -88,6 +88,8 @@ export class Eth1DepositDataTracker { this.depositsCache = new Eth1DepositsCache(opts, config, db); this.eth1DataCache = new Eth1DataCache(config, db); this.eth1FollowDistance = config.ETH1_FOLLOW_DISTANCE; + // TODO 6110: fix scenario where node starts post-6110 and `stopPolling` will always be false + this.stopPolling = false; this.forcedEth1DataVote = opts.forcedEth1DataVote ? ssz.phase0.Eth1Data.deserialize(fromHex(opts.forcedEth1DataVote)) From bcb9919045f803030bc1c26feefbc289e461986c Mon Sep 17 00:00:00 2001 From: gajinder Date: Sat, 10 Feb 2024 17:19:25 +0530 Subject: [PATCH 153/155] some improvements and a fix for effectiveBalanceIncrements fork safeness --- .../src/metrics/metrics/lodestar.ts | 4 ++ .../state-transition/src/cache/epochCache.ts | 45 +++++++++++++------ packages/state-transition/src/metrics.ts | 1 + .../test/unit/upgradeState.test.ts | 2 +- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index d2fed1a9752..e36362122b9 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -373,6 +373,10 @@ export function createLodestarMetrics( name: "lodestar_epoch_cache_finalized_pubkey_duplicate_insert", help: "Total count of duplicate insert of finalized pubkeys", }), + newUnFinalizedPubkey: register.gauge({ + name: "lodestar_epoch_cache_new_unfinalized_pubkey", + help: "Total count of unfinalized pubkeys added", + }), }, // BLS verifier thread pool and queue diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index 9b6a2ec6e67..f16b930eeea 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -1,6 +1,7 @@ import {CoordType, PublicKey} from "@chainsafe/bls/types"; import bls from "@chainsafe/bls"; import * as immutable from "immutable"; +import {fromHexString} from "@chainsafe/ssz"; import {BLSSignature, CommitteeIndex, Epoch, Slot, ValidatorIndex, phase0, SyncPeriod} from "@lodestar/types"; import {createBeaconConfig, BeaconConfig, ChainConfig} from "@lodestar/config"; import { @@ -841,13 +842,19 @@ export class EpochCache { */ addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { if (this.isAfterEIP6110()) { - this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); + this.addUnFinalizedPubkey(index, pubkey); } else { - this.pubkey2index.set(pubkey, index); - this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkey, CoordType.jacobian); + // deposit mechanism pre 6110 follows a safe distance with assumption + // that they are already canonical + this.addFinalizedPubkey(index, pubkey); } } + addUnFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { + this.unfinalizedPubkey2index = this.unfinalizedPubkey2index.set(toMemoryEfficientHexStr(pubkey), index); + metrics?.newUnFinalizedPubkey.inc(); + } + addFinalizedPubkeys(pubkeyMap: UnfinalizedPubkeyIndexMap, metrics?: EpochCacheMetrics): void { pubkeyMap.forEach((index, pubkey) => this.addFinalizedPubkey(index, pubkey, metrics)); } @@ -856,14 +863,10 @@ export class EpochCache { * Add finalized validator index and pubkey into finalized cache. * Since addFinalizedPubkey() primarily takes pubkeys from unfinalized cache, it can take pubkey hex string directly */ - addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex, metrics?: EpochCacheMetrics): void { - if (!this.isAfterEIP6110()) { - throw new Error("addFInalizedPubkey is not available pre EIP-6110"); - } - + addFinalizedPubkey(index: ValidatorIndex, pubkey: PubkeyHex | Uint8Array, metrics?: EpochCacheMetrics): void { const existingIndex = this.pubkey2index.get(pubkey); - if (existingIndex != undefined) { + if (existingIndex !== undefined) { if (existingIndex === index) { // Repeated insert. metrics?.finalizedPubkeyDuplicateInsert.inc(); @@ -875,7 +878,8 @@ export class EpochCache { } this.pubkey2index.set(pubkey, index); - this.index2pubkey[index] = bls.PublicKey.fromHex(pubkey); + const pubkeyBytes = pubkey instanceof Uint8Array ? pubkey : fromHexString(pubkey); + this.index2pubkey[index] = bls.PublicKey.fromBytes(pubkeyBytes, CoordType.jacobian); } /** @@ -959,11 +963,26 @@ export class EpochCache { } effectiveBalanceIncrementsSet(index: number, effectiveBalance: number): void { - if (index >= this.effectiveBalanceIncrements.length) { - // Clone and extend effectiveBalanceIncrements + if (this.isAfterEIP6110()) { + // TODO: electra + // getting length and setting getEffectiveBalanceIncrementsByteLen is not fork safe + // so each time we add an index, we should new the Uint8Array to keep it forksafe + // one simple optimization could be to increment the length once per block rather + // on each add/set + // + // there could still be some unused length remaining from the prev 6110 padding + const newLength = + index >= this.effectiveBalanceIncrements.length ? index + 1 : this.effectiveBalanceIncrements.length; const effectiveBalanceIncrements = this.effectiveBalanceIncrements; - this.effectiveBalanceIncrements = new Uint8Array(getEffectiveBalanceIncrementsByteLen(index + 1)); + this.effectiveBalanceIncrements = new Uint8Array(newLength); this.effectiveBalanceIncrements.set(effectiveBalanceIncrements, 0); + } else { + if (index >= this.effectiveBalanceIncrements.length) { + // Clone and extend effectiveBalanceIncrements + const effectiveBalanceIncrements = this.effectiveBalanceIncrements; + this.effectiveBalanceIncrements = new Uint8Array(getEffectiveBalanceIncrementsByteLen(index + 1)); + this.effectiveBalanceIncrements.set(effectiveBalanceIncrements, 0); + } } this.effectiveBalanceIncrements[index] = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); diff --git a/packages/state-transition/src/metrics.ts b/packages/state-transition/src/metrics.ts index 539d0d5d45d..9478087df83 100644 --- a/packages/state-transition/src/metrics.ts +++ b/packages/state-transition/src/metrics.ts @@ -26,6 +26,7 @@ export type BeaconStateTransitionMetrics = { export type EpochCacheMetrics = { finalizedPubkeyDuplicateInsert: Gauge; + newUnFinalizedPubkey: Gauge; }; export function onStateCloneMetrics( diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 6a30a0fa754..9387168f0ed 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -38,7 +38,7 @@ describe("upgradeState", () => { {skipSyncCommitteeCache: true} ); const newState = upgradeStateToEIP6110(stateView); - expect(() => newState.toValue()).to.not.throw(); + expect(() => newState.toValue()).not.toThrow(); }); }); From 661df6e878b6e2627cd4194bc43ba17400714630 Mon Sep 17 00:00:00 2001 From: gajinder Date: Thu, 15 Feb 2024 16:51:22 +0530 Subject: [PATCH 154/155] rename eip6110 to elctra --- packages/beacon-node/src/chain/chain.ts | 6 +- .../src/eth1/eth1DepositDataTracker.ts | 12 +- packages/beacon-node/src/eth1/interface.ts | 2 +- .../beacon-node/src/execution/engine/http.ts | 10 +- .../beacon-node/src/execution/engine/mock.ts | 8 +- .../beacon-node/src/execution/engine/types.ts | 32 +-- .../opPools/aggregatedAttestationPool.test.ts | 2 +- .../test/perf/chain/opPools/opPool.test.ts | 2 +- .../produceBlock/produceBlockBody.test.ts | 2 +- .../updateUnfinalizedPubkeys.test.ts | 4 +- .../besu/{6110.tmpl => electra.tmpl} | 0 .../besudocker/{6110.tmpl => electra.tmpl} | 0 ...nterop.test.ts => electra-interop.test.ts} | 32 +-- .../test/spec/presets/genesis.test.ts | 4 +- .../test/spec/presets/operations.test.ts | 10 +- .../upgradeLightClientHeader.test.ts | 30 +-- .../opPools/aggregatedAttestationPool.test.ts | 4 +- .../test/unit/chain/shufflingCache.test.ts | 8 +- .../stateCache/fifoBlockStateCache.test.ts | 3 +- .../test/unit/eth1/utils/deposits.test.ts | 32 ++- .../test/unit/executionEngine/http.test.ts | 8 +- .../beaconBlocksMaybeBlobsByRange.test.ts | 2 +- packages/beacon-node/test/utils/state.ts | 20 +- .../test/utils/validationData/attestation.ts | 7 +- .../config/src/chainConfig/configs/mainnet.ts | 6 +- .../config/src/chainConfig/configs/minimal.ts | 6 +- packages/light-client/src/spec/utils.ts | 6 +- packages/params/src/index.ts | 2 +- packages/params/src/presets/mainnet.ts | 2 +- packages/params/src/presets/minimal.ts | 2 +- packages/params/src/types.ts | 4 +- .../src/block/processDeposit.ts | 2 +- .../src/block/processDepositReceipt.ts | 8 +- .../src/block/processOperations.ts | 10 +- .../state-transition/src/cache/epochCache.ts | 18 +- .../state-transition/src/cache/stateCache.ts | 8 +- packages/state-transition/src/cache/types.ts | 6 +- packages/state-transition/src/index.ts | 4 +- .../src/slot/upgradeStateToElectra.ts | 24 +- .../state-transition/src/stateTransition.ts | 2 +- packages/state-transition/src/types.ts | 4 +- packages/state-transition/src/util/deposit.ts | 10 +- .../state-transition/src/util/execution.ts | 8 +- packages/state-transition/src/util/genesis.ts | 18 +- .../test/unit/cachedBeaconState.test.ts | 8 +- .../test/unit/util/deposit.test.ts | 84 +++--- packages/types/package.json | 4 +- packages/types/src/allForks/sszTypes.ts | 2 +- packages/types/src/allForks/types.ts | 100 +++---- packages/types/src/eip6110/index.ts | 3 - packages/types/src/eip6110/sszTypes.ts | 249 ------------------ packages/types/src/eip6110/types.ts | 33 --- packages/types/src/electra/sszTypes.ts | 147 +++++++++-- packages/types/src/electra/types.ts | 8 +- packages/validator/src/util/params.ts | 4 +- yarn.lock | 6 +- 56 files changed, 414 insertions(+), 624 deletions(-) rename packages/beacon-node/test/scripts/el-interop/besu/{6110.tmpl => electra.tmpl} (100%) rename packages/beacon-node/test/scripts/el-interop/besudocker/{6110.tmpl => electra.tmpl} (100%) rename packages/beacon-node/test/sim/{6110-interop.test.ts => electra-interop.test.ts} (96%) delete mode 100644 packages/types/src/eip6110/index.ts delete mode 100644 packages/types/src/eip6110/sszTypes.ts delete mode 100644 packages/types/src/eip6110/types.ts diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 300f83f9bd6..8c9f2e71a2f 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -987,11 +987,11 @@ export class BeaconChain implements IBeaconChain { } } - // TODO-6110: Deprecating eth1Data poll requires a check on a finalized checkpoint state. + // 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 6110 state since cp is already post-6110 - // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateEIP6110).depositReceiptsStartIndex) { + // // finalizedState can be safely casted to Electra state since cp is already post-Electra + // if (finalizedState.eth1DepositIndex >= (finalizedState as CachedBeaconStateElectra).depositReceiptsStartIndex) { // // Signal eth1 to stop polling eth1Data // this.eth1.stopPollingEth1Data(); // } diff --git a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts index 4e3940fcde4..c0b3ab35a73 100644 --- a/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts +++ b/packages/beacon-node/src/eth1/eth1DepositDataTracker.ts @@ -3,7 +3,7 @@ import {ChainForkConfig} from "@lodestar/config"; import { BeaconStateAllForks, CachedBeaconStateAllForks, - CachedBeaconStateEIP6110, + CachedBeaconStateElectra, becomesNewEth1Data, } from "@lodestar/state-transition"; import {ErrorAborted, TimeoutError, fromHex, Logger, isErrorAborted, sleep} from "@lodestar/utils"; @@ -88,7 +88,7 @@ export class Eth1DepositDataTracker { this.depositsCache = new Eth1DepositsCache(opts, config, db); this.eth1DataCache = new Eth1DataCache(config, db); this.eth1FollowDistance = config.ETH1_FOLLOW_DISTANCE; - // TODO 6110: fix scenario where node starts post-6110 and `stopPolling` will always be false + // TODO Electra: fix scenario where node starts post-Electra and `stopPolling` will always be false this.stopPolling = false; this.forcedEth1DataVote = opts.forcedEth1DataVote @@ -118,7 +118,7 @@ export class Eth1DepositDataTracker { } } - // TODO 6110: Figure out how an elegant way to stop eth1data polling + // TODO Electra: Figure out how an elegant way to stop eth1data polling stopPollingEth1Data(): void { this.stopPolling = true; } @@ -128,10 +128,10 @@ export class Eth1DepositDataTracker { */ async getEth1DataAndDeposits(state: CachedBeaconStateAllForks): Promise { if ( - state.epochCtx.isAfterEIP6110() && - state.eth1DepositIndex >= (state as CachedBeaconStateEIP6110).depositReceiptsStartIndex + state.epochCtx.isAfterElectra() && + state.eth1DepositIndex >= (state as CachedBeaconStateElectra).depositReceiptsStartIndex ) { - // No need to poll eth1Data since EIP6110 deprecates the mechanism after depositReceiptsStartIndex is reached + // No need to poll eth1Data since Electra deprecates the mechanism after depositReceiptsStartIndex is reached return {eth1Data: state.eth1Data, deposits: []}; } const eth1Data = this.forcedEth1DataVote ?? (await this.getEth1Data(state)); diff --git a/packages/beacon-node/src/eth1/interface.ts b/packages/beacon-node/src/eth1/interface.ts index 4b5dd922601..898041ac894 100644 --- a/packages/beacon-node/src/eth1/interface.ts +++ b/packages/beacon-node/src/eth1/interface.ts @@ -64,7 +64,7 @@ export interface IEth1ForBlockProduction { startPollingMergeBlock(): void; /** - * Should stop polling eth1Data after a 6110 block is finalized AND deposit_receipts_start_index is reached + * Should stop polling eth1Data after a Electra block is finalized AND deposit_receipts_start_index is reached */ stopPollingEth1Data(): void; } diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index 37cd8b92824..26109827b30 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -176,8 +176,8 @@ export class ExecutionEngineHttp implements IExecutionEngine { parentBlockRoot?: Root ): Promise { const method = - ForkSeq[fork] >= ForkSeq.eip6110 - ? "engine_newPayloadV6110" + ForkSeq[fork] >= ForkSeq.electra + ? "engine_newPayloadV4" : ForkSeq[fork] >= ForkSeq.deneb ? "engine_newPayloadV3" : ForkSeq[fork] >= ForkSeq.capella @@ -198,7 +198,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { const serializedVersionedHashes = serializeVersionedHashes(versionedHashes); const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot); - const method = ForkSeq[fork] >= ForkSeq.eip6110 ? "engine_newPayloadV6110" : "engine_newPayloadV3"; + const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV4" : "engine_newPayloadV3"; engineRequest = { method, params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot], @@ -372,8 +372,8 @@ export class ExecutionEngineHttp implements IExecutionEngine { shouldOverrideBuilder?: boolean; }> { const method = - ForkSeq[fork] >= ForkSeq.eip6110 - ? "engine_getPayloadV6110" + ForkSeq[fork] >= ForkSeq.electra + ? "engine_getPayloadV4" : ForkSeq[fork] >= ForkSeq.deneb ? "engine_getPayloadV3" : ForkSeq[fork] >= ForkSeq.capella diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index 0111f409ca4..aa15a2bc953 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -35,7 +35,7 @@ export type ExecutionEngineMockOpts = { onlyPredefinedResponses?: boolean; capellaForkTimestamp?: number; denebForkTimestamp?: number; - eip6110ForkTimestamp?: number; + electraForkTimestamp?: number; }; type ExecutionBlock = { @@ -89,14 +89,14 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_newPayloadV1: this.notifyNewPayload.bind(this), engine_newPayloadV2: this.notifyNewPayload.bind(this), engine_newPayloadV3: this.notifyNewPayload.bind(this), - engine_newPayloadV6110: this.notifyNewPayload.bind(this), + engine_newPayloadV4: this.notifyNewPayload.bind(this), engine_forkchoiceUpdatedV1: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV2: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV3: this.notifyForkchoiceUpdate.bind(this), engine_getPayloadV1: this.getPayload.bind(this), engine_getPayloadV2: this.getPayload.bind(this), engine_getPayloadV3: this.getPayload.bind(this), - engine_getPayloadV6110: this.getPayload.bind(this), + engine_getPayloadV4: this.getPayload.bind(this), engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), }; @@ -390,7 +390,7 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { } private timestampToFork(timestamp: number): ForkExecution { - if (timestamp > (this.opts.eip6110ForkTimestamp ?? Infinity)) return ForkName.eip6110; + if (timestamp > (this.opts.electraForkTimestamp ?? Infinity)) return ForkName.electra; if (timestamp > (this.opts.denebForkTimestamp ?? Infinity)) return ForkName.deneb; if (timestamp > (this.opts.capellaForkTimestamp ?? Infinity)) return ForkName.capella; return ForkName.bellatrix; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index e2738006dfd..44d3a91eec9 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -1,4 +1,4 @@ -import {allForks, capella, deneb, Wei, bellatrix, Root, eip6110} from "@lodestar/types"; +import {allForks, capella, deneb, Wei, bellatrix, Root, electra} from "@lodestar/types"; import { BYTES_PER_LOGS_BLOOM, FIELD_ELEMENTS_PER_BLOB, @@ -28,7 +28,7 @@ export type EngineApiRpcParamTypes = { engine_newPayloadV1: [ExecutionPayloadRpc]; engine_newPayloadV2: [ExecutionPayloadRpc]; engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; - engine_newPayloadV6110: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; + engine_newPayloadV4: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; /** * 1. Object - Payload validity status with respect to the consensus rules: * - blockHash: DATA, 32 Bytes - block hash value of the payload @@ -52,7 +52,7 @@ export type EngineApiRpcParamTypes = { engine_getPayloadV1: [QUANTITY]; engine_getPayloadV2: [QUANTITY]; engine_getPayloadV3: [QUANTITY]; - engine_getPayloadV6110: [QUANTITY]; + engine_getPayloadV4: [QUANTITY]; /** * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure @@ -80,7 +80,7 @@ export type EngineApiRpcReturnTypes = { engine_newPayloadV1: PayloadStatus; engine_newPayloadV2: PayloadStatus; engine_newPayloadV3: PayloadStatus; - engine_newPayloadV6110: PayloadStatus; + engine_newPayloadV4: PayloadStatus; engine_forkchoiceUpdatedV1: { payloadStatus: PayloadStatus; payloadId: QUANTITY | null; @@ -99,7 +99,7 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadV1: ExecutionPayloadRpc; engine_getPayloadV2: ExecutionPayloadResponse; engine_getPayloadV3: ExecutionPayloadResponse; - engine_getPayloadV6110: ExecutionPayloadResponse; + engine_getPayloadV4: ExecutionPayloadResponse; engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[]; @@ -124,7 +124,7 @@ export type ExecutionPayloadBodyRpc = { export type ExecutionPayloadBody = { transactions: bellatrix.Transaction[]; withdrawals: capella.Withdrawals | null; - depositReceipts: eip6110.DepositReceipts | null; + depositReceipts: electra.DepositReceipts | null; }; export type ExecutionPayloadRpc = { @@ -146,7 +146,7 @@ export type ExecutionPayloadRpc = { blobGasUsed?: QUANTITY; // DENEB excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB - depositReceipts?: DepositReceiptRpc[]; // EIP6110 + depositReceipts?: DepositReceiptRpc[]; // ELECTRA }; export type WithdrawalRpc = { @@ -215,9 +215,9 @@ export function serializeExecutionPayload(fork: ForkName, data: allForks.Executi payload.excessBlobGas = numToQuantity(excessBlobGas); } - // EIP6110 adds depositReceipts to the ExecutionPayload - if (ForkSeq[fork] >= ForkSeq.eip6110) { - const {depositReceipts} = data as eip6110.ExecutionPayload; + // ELECTRA adds depositReceipts to the ExecutionPayload + if (ForkSeq[fork] >= ForkSeq.electra) { + const {depositReceipts} = data as electra.ExecutionPayload; payload.depositReceipts = depositReceipts.map(serializeDepositReceipt); } @@ -306,15 +306,15 @@ export function parseExecutionPayload( (executionPayload as deneb.ExecutionPayload).excessBlobGas = quantityToBigint(excessBlobGas); } - if (ForkSeq[fork] >= ForkSeq.eip6110) { + if (ForkSeq[fork] >= ForkSeq.electra) { const {depositReceipts} = data; // Geth can also reply with null if (depositReceipts == null) { throw Error( - `depositReceipts missing for ${fork} >= eip6110 executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` + `depositReceipts missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}` ); } - (executionPayload as eip6110.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipts); + (executionPayload as electra.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipts); } return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; @@ -383,7 +383,7 @@ export function deserializeWithdrawal(serialized: WithdrawalRpc): capella.Withdr } as capella.Withdrawal; } -export function serializeDepositReceipt(depositReceipt: eip6110.DepositReceipt): DepositReceiptRpc { +export function serializeDepositReceipt(depositReceipt: electra.DepositReceipt): DepositReceiptRpc { return { pubkey: bytesToData(depositReceipt.pubkey), withdrawalCredentials: bytesToData(depositReceipt.withdrawalCredentials), @@ -393,14 +393,14 @@ export function serializeDepositReceipt(depositReceipt: eip6110.DepositReceipt): }; } -export function deserializeDepositReceipts(serialized: DepositReceiptRpc): eip6110.DepositReceipt { +export function deserializeDepositReceipts(serialized: DepositReceiptRpc): electra.DepositReceipt { return { pubkey: dataToBytes(serialized.pubkey, 48), withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32), amount: quantityToNum(serialized.amount), signature: dataToBytes(serialized.signature, 96), index: quantityToNum(serialized.index), - } as eip6110.DepositReceipt; + } as electra.DepositReceipt; } export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null { 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 4ed8215ac85..87a9c392d8d 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -32,7 +32,7 @@ describe(`getAttestationsForBlock vc=${vc}`, () => { before(function () { this.timeout(5 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}); + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true, vc}) as unknown as CachedBeaconStateAltair; const {blockHeader, checkpoint} = computeAnchorCheckpoint(originalState.config, originalState); // TODO figure out why getBlockRootAtSlot(originalState, justifiedSlot) is not the same to justifiedCheckpoint.root diff --git a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts index 6e420f0e101..7998a204f09 100644 --- a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts @@ -24,7 +24,7 @@ describe("opPool", () => { before(function () { this.timeout(2 * 60 * 1000); // Generating the states for the first time is very slow - originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}); + originalState = generatePerfTestCachedStateAltair({goBackOneSlot: true}) as unknown as CachedBeaconStateAltair; }); itBench({ diff --git a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts index dbe86c2c586..772c8d7bbb7 100644 --- a/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts +++ b/packages/beacon-node/test/perf/chain/produceBlock/produceBlockBody.test.ts @@ -25,7 +25,7 @@ describe("produceBlockBody", () => { before(async () => { db = new BeaconDb(config, await LevelDbController.create({name: ".tmpdb"}, {logger})); - state = stateOg.clone(); + state = stateOg.clone() as unknown as CachedBeaconStateAltair; chain = new BeaconChain( { proposerBoostEnabled: true, diff --git a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts index 59eee6ab83b..900f6a6fb87 100644 --- a/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts +++ b/packages/beacon-node/test/perf/chain/stateCache/updateUnfinalizedPubkeys.test.ts @@ -8,7 +8,7 @@ import {ssz} from "@lodestar/types"; import {type CachedBeaconStateAllForks, PubkeyIndexMap} from "@lodestar/state-transition"; import {bytesToBigInt, intToBytes} from "@lodestar/utils"; import {CheckpointStateCache, StateContextCache} from "../../../../src/chain/stateCache/index.js"; -import {generateCached6110State} from "../../../utils/state.js"; +import {generateCachedElectraState} from "../../../utils/state.js"; // Benchmark date from Mon Nov 21 2023 - Intel Core i7-9750H @ 2.60Ghz // ✔ updateUnfinalizedPubkeys - updating 10 pubkeys 1444.173 ops/s 692.4380 us/op - 1057 runs 6.03 s @@ -25,7 +25,7 @@ describe("updateUnfinalizedPubkeys perf tests", function () { let stateCache: StateContextCache; const unfinalizedPubkey2Index = generatePubkey2Index(0, Math.max.apply(null, numPubkeysToBeFinalizedCases)); - const baseState = generateCached6110State(); + const baseState = generateCachedElectraState(); for (const numPubkeysToBeFinalized of numPubkeysToBeFinalizedCases) { itBench({ diff --git a/packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl b/packages/beacon-node/test/scripts/el-interop/besu/electra.tmpl similarity index 100% rename from packages/beacon-node/test/scripts/el-interop/besu/6110.tmpl rename to packages/beacon-node/test/scripts/el-interop/besu/electra.tmpl diff --git a/packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl b/packages/beacon-node/test/scripts/el-interop/besudocker/electra.tmpl similarity index 100% rename from packages/beacon-node/test/scripts/el-interop/besudocker/6110.tmpl rename to packages/beacon-node/test/scripts/el-interop/besudocker/electra.tmpl diff --git a/packages/beacon-node/test/sim/6110-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts similarity index 96% rename from packages/beacon-node/test/sim/6110-interop.test.ts rename to packages/beacon-node/test/sim/electra-interop.test.ts index 32f6750975a..a7b65244e65 100644 --- a/packages/beacon-node/test/sim/6110-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -3,12 +3,12 @@ import {Context} from "mocha"; import _ from "lodash"; import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; -import {eip6110, Epoch, Slot} from "@lodestar/types"; +import {electra, Epoch, Slot} from "@lodestar/types"; import {ValidatorProposerConfig} from "@lodestar/validator"; import {ChainConfig} from "@lodestar/config"; import {TimestampFormatCode} from "@lodestar/logger"; -import {CachedBeaconStateEIP6110} from "@lodestar/state-transition"; +import {CachedBeaconStateElectra} from "@lodestar/state-transition"; import {initializeExecutionEngine} from "../../src/execution/index.js"; import {ExecutionPayloadStatus, PayloadAttributes} from "../../src/execution/engine/interface.js"; @@ -27,9 +27,9 @@ import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; // NOTE: How to run -// DEV_RUN=true EL_BINARY_DIR=naviechan/besu:v6110 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/6110-interop.test.ts +// DEV_RUN=true EL_BINARY_DIR=naviechan/besu:v6110 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/electra-interop.test.ts // or -// DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn mocha test/sim/6110-interop.test.ts +// DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn mocha test/sim/electra-interop.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention */ @@ -45,7 +45,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { } this.timeout("10min"); - const dataPath = fs.mkdtempSync("lodestar-test-6110"); + const dataPath = fs.mkdtempSync("lodestar-test-electra"); const elSetupConfig = { elScriptDir: process.env.EL_SCRIPT_DIR, elBinaryDir: process.env.EL_BINARY_DIR, @@ -73,7 +73,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { it("Send and get payloads with depositReceipts to/from EL", async () => { const {elClient, tearDownCallBack} = await runEL( - {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "6110.tmpl"}, + {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, {...elRunOptions, ttd: BigInt(0)}, controller.signal ); @@ -98,7 +98,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { parentBeaconBlockRoot: dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32), }; const payloadId = await executionEngine.notifyForkchoiceUpdate( - ForkName.eip6110, + ForkName.electra, genesisBlockHash, //use finalizedBlockHash as safeBlockHash genesisBlockHash, @@ -175,7 +175,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; const parentBeaconBlockRoot = dataToBytes("0x0000000000000000000000000000000000000000000000000000000000000000", 32); const payloadResult = await executionEngine.notifyNewPayload( - ForkName.eip6110, + ForkName.electra, newPayload, [], parentBeaconBlockRoot @@ -194,7 +194,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; const payloadId2 = await executionEngine.notifyForkchoiceUpdate( - ForkName.eip6110, + ForkName.electra, newPayloadBlockHash, //use finalizedBlockHash as safeBlockHash newPayloadBlockHash, @@ -206,8 +206,8 @@ describe("executionEngine / ExecutionEngineHttp", function () { // 5. Get the payload. Check depositReceipts field contains deposit // Wait a bit first for besu to pick up tx from the tx pool. await sleep(1000); - const payloadAndBlockValue = await executionEngine.getPayload(ForkName.eip6110, payloadId2); - const payload = payloadAndBlockValue.executionPayload as eip6110.ExecutionPayload; + const payloadAndBlockValue = await executionEngine.getPayload(ForkName.electra, payloadId2); + const payload = payloadAndBlockValue.executionPayload as electra.ExecutionPayload; if (payload.transactions.length !== 1) { throw Error(`Number of transactions mismatched. Expected: 1, actual: ${payload.transactions.length}`); @@ -236,7 +236,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { it("Post-merge, run for a few blocks", async function () { console.log("\n\nPost-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( - {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "6110.tmpl"}, + {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "electra.tmpl"}, {...elRunOptions, ttd: BigInt(0)}, controller.signal ); @@ -244,7 +244,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { await runNodeWithEL.bind(this)({ elClient, - eip6110Epoch: 0, + electraEpoch: 0, testName: "post-merge", }); }); @@ -256,7 +256,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { */ async function runNodeWithEL( this: Context, - {elClient, eip6110Epoch, testName}: {elClient: ELClient; eip6110Epoch: Epoch; testName: string} + {elClient, electraEpoch, testName}: {elClient: ELClient; electraEpoch: Epoch; testName: string} ): Promise { const {genesisBlockHash, ttd, engineRpcUrl, ethRpcUrl} = elClient; const validatorClientCount = 1; @@ -306,7 +306,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, - EIP6110_FORK_EPOCH: eip6110Epoch, + ELECTRA_FORK_EPOCH: electraEpoch, TERMINAL_TOTAL_DIFFICULTY: ttd, }, options: { @@ -399,7 +399,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { await sleep(500); // Check if new validator is in finalized cache - headState = bn.chain.getHeadState() as CachedBeaconStateEIP6110; + headState = bn.chain.getHeadState() as CachedBeaconStateElectra; epochCtx = headState.epochCtx; if (headState.validators.length !== 33 || headState.balances.length !== 33) { diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index c09e46b95ee..aa052c52a27 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -1,6 +1,6 @@ import path from "node:path"; import {expect} from "vitest"; -import {phase0, Root, ssz, TimeSeconds, allForks, deneb, eip6110} from "@lodestar/types"; +import {phase0, Root, ssz, TimeSeconds, allForks, electra} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; import { BeaconStateAllForks, @@ -60,7 +60,7 @@ const genesisInitialization: TestRunnerFn> = blockFns.processDeposit(fork, state, testCase.deposit); }, - deposit_receipt: (state, testCase: {deposit_receipt: eip6110.DepositReceipt}) => { + deposit_receipt: (state, testCase: {deposit_receipt: electra.DepositReceipt}) => { const fork = state.config.getForkSeq(state.slot); - blockFns.processDepositReceipt(fork, state as CachedBeaconStateEIP6110, testCase.deposit_receipt); + blockFns.processDepositReceipt(fork, state as CachedBeaconStateElectra, testCase.deposit_receipt); }, proposer_slashing: (state, testCase: {proposer_slashing: phase0.ProposerSlashing}) => { @@ -127,7 +127,7 @@ const operations: TestRunnerFn = (fork, block: ssz[fork].BeaconBlock, body: ssz[fork].BeaconBlockBody, deposit: ssz.phase0.Deposit, - deposit_receipt: ssz.eip6110.DepositReceipt, + deposit_receipt: ssz.electra.DepositReceipt, proposer_slashing: ssz.phase0.ProposerSlashing, voluntary_exit: ssz.phase0.SignedVoluntaryExit, // Altair diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index f6cd79422c9..8a33beffe21 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -41,14 +41,8 @@ describe("UpgradeLightClientHeader", function () { }; }); - // Since electra is not implemented for loop is till deneb (Object.values(ForkName).length-1) - // Once electra is implemnted run for loop till Object.values(ForkName).length - - // for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { - // for (let j = i + 1; j < Object.values(ForkName).length; j++) { - - for (let i = ForkSeq.altair; i < Object.values(ForkName).length - 1; i++) { - for (let j = i + 1; j < Object.values(ForkName).length - 1; j++) { + for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { + for (let j = i + 1; j < Object.values(ForkName).length; j++) { const fromFork = ForkName[ForkSeq[i] as ForkName]; const toFork = ForkName[ForkSeq[j] as ForkName]; @@ -62,27 +56,7 @@ describe("UpgradeLightClientHeader", function () { } } - // for electra not implemented for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { - const fromFork = ForkName[ForkSeq[i] as ForkName]; - const toFork = ForkName["electra"]; - - it(`Throw error ${fromFork}=>${toFork}`, function () { - lcHeaderByFork[fromFork].beacon.slot = testSlots[fromFork]; - lcHeaderByFork[toFork].beacon.slot = testSlots[fromFork]; - - expect(() => { - upgradeLightClientHeader(config, toFork, lcHeaderByFork[fromFork]); - }).toThrow("Not Implemented"); - }); - } - - // Since electra is not implemented for loop is till deneb (Object.values(ForkName).length-1) - // Once electra is implemnted run for loop till Object.values(ForkName).length - - // for (let i = ForkSeq.altair; i < Object.values(ForkName).length; i++) { - - for (let i = ForkSeq.altair; i < Object.values(ForkName).length - 1; i++) { for (let j = i; j > 0; j--) { const fromFork = ForkName[ForkSeq[i] as ForkName]; const toFork = ForkName[ForkSeq[j] as ForkName]; diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index 00aa8a40168..a4179579a89 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -61,9 +61,9 @@ describe("AggregatedAttestationPool", function () { epochParticipation[committee[i]] = 0b000; } } - (originalState as CachedBeaconStateAltair).previousEpochParticipation = + (originalState as unknown as CachedBeaconStateAltair).previousEpochParticipation = ssz.altair.EpochParticipation.toViewDU(epochParticipation); - (originalState as CachedBeaconStateAltair).currentEpochParticipation = + (originalState as unknown as CachedBeaconStateAltair).currentEpochParticipation = ssz.altair.EpochParticipation.toViewDU(epochParticipation); originalState.commit(); let altairState: CachedBeaconStateAllForks; diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index 6295a993c07..e6a7e8706bb 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -1,6 +1,6 @@ import {describe, it, expect, beforeEach} from "vitest"; -import {getShufflingDecisionBlock} from "@lodestar/state-transition"; +import {getShufflingDecisionBlock, CachedBeaconStateAllForks} from "@lodestar/state-transition"; // eslint-disable-next-line import/no-relative-packages import {generateTestCachedBeaconStateOnlyValidators} from "../../../../state-transition/test/perf/util.js"; import {ShufflingCache} from "../../../src/chain/shufflingCache.js"; @@ -14,7 +14,7 @@ describe("ShufflingCache", function () { beforeEach(() => { shufflingCache = new ShufflingCache(null, {maxShufflingCacheEpochs: 1}); - shufflingCache.processState(state, currentEpoch); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch); }); it("should get shuffling from cache", async function () { @@ -29,7 +29,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch, "0x00"); expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert shufflings at other epochs does prune the cache - shufflingCache.processState(state, currentEpoch + 1); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch + 1); // the current shuffling is not available anymore expect(await shufflingCache.get(currentEpoch, decisionRoot)).toBeNull(); }); @@ -39,7 +39,7 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch + 1, nextDecisionRoot); const shufflingRequest0 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); const shufflingRequest1 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); - shufflingCache.processState(state, currentEpoch + 1); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, currentEpoch + 1); expect(await shufflingRequest0).toEqual(state.epochCtx.nextShuffling); expect(await shufflingRequest1).toEqual(state.epochCtx.nextShuffling); }); diff --git a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts index 4628b1b0722..6ced4a18fc1 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts @@ -1,8 +1,7 @@ import {describe, it, expect, beforeEach} from "vitest"; import {toHexString} from "@chainsafe/ssz"; -import {EpochShuffling} from "@lodestar/state-transition"; +import {EpochShuffling, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {CachedBeaconStateAllForks} from "@lodestar/state-transition/src/types.js"; import {FIFOBlockStateCache} from "../../../../src/chain/stateCache/index.js"; import {generateCachedState} from "../../../utils/state.js"; diff --git a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts index 581a13ffb8c..6cc3ae8f1ce 100644 --- a/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts +++ b/packages/beacon-node/test/unit/eth1/utils/deposits.test.ts @@ -20,7 +20,7 @@ describe("eth1 / util / deposits", function () { depositIndexes: number[]; expectedReturnedIndexes?: number[]; error?: Eth1ErrorCode; - post6110?: boolean; + postElectra?: boolean; }; const testCases: TestCase[] = [ @@ -74,48 +74,52 @@ describe("eth1 / util / deposits", function () { expectedReturnedIndexes: [], }, { - id: "No deposits to be included post 6110 after deposit_receipts_start_index", + id: "No deposits to be included post Electra after deposit_receipts_start_index", depositCount: 2030, eth1DepositIndex: 2025, depositIndexes: Array.from({length: 2030}, (_, i) => i), expectedReturnedIndexes: [], - post6110: true, + postElectra: true, }, { - id: "Should return deposits post 6110 before deposit_receipts_start_index", + id: "Should return deposits post Electra before deposit_receipts_start_index", depositCount: 2022, eth1DepositIndex: 2018, depositIndexes: Array.from({length: 2022}, (_, i) => i), expectedReturnedIndexes: [2018, 2019, 2020, 2021], - post6110: true, + postElectra: true, }, { - id: "Should return deposits less than MAX_DEPOSITS post 6110 before deposit_receipts_start_index", + id: "Should return deposits less than MAX_DEPOSITS post Electra before deposit_receipts_start_index", depositCount: 10 * MAX_DEPOSITS, eth1DepositIndex: 0, depositIndexes: Array.from({length: 10 * MAX_DEPOSITS}, (_, i) => i), expectedReturnedIndexes: Array.from({length: MAX_DEPOSITS}, (_, i) => i), - post6110: true, + postElectra: true, }, ]; /* eslint-disable @typescript-eslint/naming-convention */ - const post6110Config = createChainForkConfig({ + const postElectraConfig = createChainForkConfig({ ALTAIR_FORK_EPOCH: 1, BELLATRIX_FORK_EPOCH: 2, CAPELLA_FORK_EPOCH: 3, DENEB_FORK_EPOCH: 4, - EIP6110_FORK_EPOCH: 5, + ELECTRA_FORK_EPOCH: 5, }); - const post6110Slot = post6110Config.EIP6110_FORK_EPOCH * SLOTS_PER_EPOCH + 1; + const postElectraSlot = postElectraConfig.ELECTRA_FORK_EPOCH * SLOTS_PER_EPOCH + 1; for (const testCase of testCases) { - const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error, post6110} = testCase; + const {id, depositIndexes, eth1DepositIndex, depositCount, expectedReturnedIndexes, error, postElectra} = + testCase; it(id, async function () { - const state = post6110 - ? generateState({slot: post6110Slot, eth1DepositIndex}, post6110Config) + const state = postElectra + ? generateState({slot: postElectraSlot, eth1DepositIndex}, postElectraConfig) : generateState({eth1DepositIndex}); - const cachedState = createCachedBeaconStateTest(state, post6110 ? post6110Config : createChainForkConfig({})); + const cachedState = createCachedBeaconStateTest( + state, + postElectra ? postElectraConfig : createChainForkConfig({}) + ); const eth1Data = generateEth1Data(depositCount); const deposits = depositIndexes.map((index) => generateDepositEvent(index)); const depositsGetter: DepositGetter = async (indexRange) => diff --git a/packages/beacon-node/test/unit/executionEngine/http.test.ts b/packages/beacon-node/test/unit/executionEngine/http.test.ts index fc668d00e91..373801ac240 100644 --- a/packages/beacon-node/test/unit/executionEngine/http.test.ts +++ b/packages/beacon-node/test/unit/executionEngine/http.test.ts @@ -188,7 +188,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], - depositReceipts: null, // depositReceipts is null pre-6110 + depositReceipts: null, // depositReceipts is null pre-electra }, null, // null returned for missing blocks { @@ -197,7 +197,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella - depositReceipts: null, // depositReceipts is null pre-6110 + depositReceipts: null, // depositReceipts is null pre-electra }, ], }; @@ -245,7 +245,7 @@ describe("ExecutionEngine / http", () => { amount: "0x7b", }, ], - depositReceipts: null, // depositReceipts is null pre-6110 + depositReceipts: null, // depositReceipts is null pre-electra }, null, // null returned for missing blocks { @@ -254,7 +254,7 @@ describe("ExecutionEngine / http", () => { "0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", ], withdrawals: null, // withdrawals is null pre-capella - depositReceipts: null, // depositReceipts is null pre-6110 + depositReceipts: null, // depositReceipts is null pre-electra }, ], }; diff --git a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts index eea806f85d4..444f9063a8e 100644 --- a/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts +++ b/packages/beacon-node/test/unit/network/beaconBlocksMaybeBlobsByRange.test.ts @@ -23,7 +23,7 @@ describe("beaconBlocksMaybeBlobsByRange", () => { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, - EIP6110_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 4af97682125..255f1a397b7 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -7,10 +7,10 @@ import { PubkeyIndexMap, CachedBeaconStateBellatrix, BeaconStateBellatrix, - CachedBeaconStateEIP6110, - BeaconStateEIP6110, + CachedBeaconStateElectra, + BeaconStateElectra, } from "@lodestar/state-transition"; -import {allForks, altair, bellatrix, eip6110, ssz} from "@lodestar/types"; +import {allForks, altair, bellatrix, electra, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; import {FAR_FUTURE_EPOCH, ForkName, ForkSeq, MAX_EFFECTIVE_BALANCE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; @@ -95,10 +95,10 @@ export function generateState( }; } - if (forkSeq >= ForkSeq.eip6110) { - const stateEIP6110 = state as eip6110.BeaconState; - stateEIP6110.depositReceiptsStartIndex = 2023n; - stateEIP6110.latestExecutionPayloadHeader = ssz.eip6110.ExecutionPayloadHeader.defaultValue(); + if (forkSeq >= ForkSeq.electra) { + const stateElectra = state as electra.BeaconState; + stateElectra.depositReceiptsStartIndex = 2023n; + stateElectra.latestExecutionPayloadHeader = ssz.electra.ExecutionPayloadHeader.defaultValue(); } return config.getForkTypes(stateSlot).BeaconState.toViewDU(state); @@ -149,10 +149,10 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac /** * This generates state with default pubkey */ -export function generateCached6110State(opts?: TestBeaconState): CachedBeaconStateEIP6110 { - const config = getConfig(ForkName.eip6110); +export function generateCachedElectraState(opts?: TestBeaconState): CachedBeaconStateElectra { + const config = getConfig(ForkName.electra); const state = generateState(opts, config); - return createCachedBeaconState(state as BeaconStateEIP6110, { + return createCachedBeaconState(state as BeaconStateElectra, { config: createBeaconConfig(config, state.genesisValidatorsRoot), pubkey2index: new PubkeyIndexMap(), index2pubkey: [], diff --git a/packages/beacon-node/test/utils/validationData/attestation.ts b/packages/beacon-node/test/utils/validationData/attestation.ts index fa3c4d479ad..31431a12c1c 100644 --- a/packages/beacon-node/test/utils/validationData/attestation.ts +++ b/packages/beacon-node/test/utils/validationData/attestation.ts @@ -4,6 +4,7 @@ import { computeSigningRoot, computeStartSlotAtEpoch, getShufflingDecisionBlock, + CachedBeaconStateAllForks, } from "@lodestar/state-transition"; import {ProtoBlock, IForkChoice, ExecutionStatus} from "@lodestar/fork-choice"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; @@ -79,8 +80,8 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { }; const shufflingCache = new ShufflingCache(); - shufflingCache.processState(state, state.epochCtx.currentShuffling.epoch); - shufflingCache.processState(state, state.epochCtx.nextShuffling.epoch); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, state.epochCtx.currentShuffling.epoch); + shufflingCache.processState(state as unknown as CachedBeaconStateAllForks, state.epochCtx.nextShuffling.epoch); const dependentRoot = getShufflingDecisionBlock(state, state.epochCtx.currentShuffling.epoch); const forkChoice = { @@ -130,7 +131,7 @@ export function getAttestationValidData(opts: AttestationValidDataOpts): { getState: async () => state, // TODO: remove this once we have a better way to get state getStateSync: () => state, - } as Partial as IStateRegenerator; + } as unknown as Partial as IStateRegenerator; const chain = { clock, diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 09c4043d8f6..1bf51c4f3b4 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -49,14 +49,10 @@ export const chainConfig: ChainConfig = { DENEB_FORK_VERSION: b("0x04000000"), DENEB_FORK_EPOCH: 269568, // March 13, 2024, 01:55:35pm UTC - // Electra + // ELECTRA ELECTRA_FORK_VERSION: b("0x05000000"), ELECTRA_FORK_EPOCH: Infinity, - // EIP-6110 - EIP6110_FORK_VERSION: b("0x05000000"), - EIP6110_FORK_EPOCH: Infinity, - // Time parameters // --------------------------------------------------------------- // 12 seconds diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index bb68f151a5c..5507feef942 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -45,11 +45,7 @@ export const chainConfig: ChainConfig = { // Deneb DENEB_FORK_VERSION: b("0x04000001"), DENEB_FORK_EPOCH: Infinity, - // EIP-6110 - EIP6110_FORK_VERSION: b("0x05000001"), - EIP6110_FORK_EPOCH: Infinity, - - // Electra + // ELECTRA ELECTRA_FORK_VERSION: b("0x05000001"), ELECTRA_FORK_EPOCH: Infinity, diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index d3ca59ab6bc..f453e6c384c 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -8,7 +8,7 @@ import { BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, BLOCK_BODY_EXECUTION_PAYLOAD_INDEX as EXECUTION_PAYLOAD_INDEX, } from "@lodestar/params"; -import {altair, phase0, ssz, allForks, capella, deneb, Slot, eip6110} from "@lodestar/types"; +import {altair, phase0, ssz, allForks, capella, deneb, Slot, electra} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {computeEpochAtSlot} from "@lodestar/state-transition"; @@ -146,8 +146,8 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: allFor } } - if (epoch < config.EIP6110_FORK_EPOCH) { - if ((header as eip6110.LightClientHeader).execution.depositReceiptsRoot !== undefined) { + if (epoch < config.ELECTRA_FORK_EPOCH) { + if ((header as electra.LightClientHeader).execution.depositReceiptsRoot !== undefined) { return false; } } diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index c8957f150eb..482e591123b 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -247,5 +247,5 @@ export const KZG_COMMITMENT_SUBTREE_INDEX0 = KZG_COMMITMENT_GINDEX0 - 2 ** KZG_C // ssz.deneb.BlobSidecars.elementType.fixedSize export const BLOBSIDECAR_FIXED_SIZE = ACTIVE_PRESET === PresetName.minimal ? 131672 : 131928; -// EIP-6110 Misc +// Electra Misc export const UNSET_DEPOSIT_RECEIPTS_START_INDEX = 2n ** 64n - 1n; diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 8ae65d2738f..86f5c39c539 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -119,6 +119,6 @@ export const mainnetPreset: BeaconPreset = { MAX_BLOBS_PER_BLOCK: 6, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 17, - // EIP6110 + // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index aed585054e9..6239a8c1a3e 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -120,6 +120,6 @@ export const minimalPreset: BeaconPreset = { MAX_BLOBS_PER_BLOCK: 6, KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 9, - // EIP6110 + // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index bf082c9714e..57ee8230a77 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -83,7 +83,7 @@ export type BeaconPreset = { MAX_BLOBS_PER_BLOCK: number; KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: number; - // EIP6110 + // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number; }; @@ -171,7 +171,7 @@ export const beaconPresetTypes: BeaconPresetTypes = { MAX_BLOBS_PER_BLOCK: "number", KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: "number", - // EIP6110 + // ELECTRA MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number", }; diff --git a/packages/state-transition/src/block/processDeposit.ts b/packages/state-transition/src/block/processDeposit.ts index 1305826da96..fbefafdc7fb 100644 --- a/packages/state-transition/src/block/processDeposit.ts +++ b/packages/state-transition/src/block/processDeposit.ts @@ -13,7 +13,7 @@ import { } from "@lodestar/params"; import {DepositData} from "@lodestar/types/lib/phase0/types.js"; -import {DepositReceipt} from "@lodestar/types/lib/eip6110/types.js"; +import {DepositReceipt} from "@lodestar/types/lib/electra/types.js"; import {ZERO_HASH} from "../constants/index.js"; import {computeDomain, computeSigningRoot, increaseBalance} from "../util/index.js"; import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; diff --git a/packages/state-transition/src/block/processDepositReceipt.ts b/packages/state-transition/src/block/processDepositReceipt.ts index c9e13b7de8e..140e38d634f 100644 --- a/packages/state-transition/src/block/processDepositReceipt.ts +++ b/packages/state-transition/src/block/processDepositReceipt.ts @@ -1,13 +1,13 @@ -import {eip6110} from "@lodestar/types"; +import {electra} from "@lodestar/types"; import {ForkSeq, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; -import {CachedBeaconStateEIP6110} from "../types.js"; +import {CachedBeaconStateElectra} from "../types.js"; import {applyDeposit} from "./processDeposit.js"; export function processDepositReceipt( fork: ForkSeq, - state: CachedBeaconStateEIP6110, - depositReceipt: eip6110.DepositReceipt + state: CachedBeaconStateElectra, + depositReceipt: electra.DepositReceipt ): void { if (state.depositReceiptsStartIndex === UNSET_DEPOSIT_RECEIPTS_START_INDEX) { state.depositReceiptsStartIndex = BigInt(depositReceipt.index); diff --git a/packages/state-transition/src/block/processOperations.ts b/packages/state-transition/src/block/processOperations.ts index b2217b433a7..968182fdf8c 100644 --- a/packages/state-transition/src/block/processOperations.ts +++ b/packages/state-transition/src/block/processOperations.ts @@ -1,7 +1,7 @@ -import {allForks, capella, eip6110} from "@lodestar/types"; +import {allForks, capella, electra} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; -import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateEIP6110} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; import {getEth1DepositCount} from "../util/deposit.js"; import {processAttestations} from "./processAttestations.js"; import {processProposerSlashing} from "./processProposerSlashing.js"; @@ -58,9 +58,9 @@ export function processOperations( } } - if (fork >= ForkSeq.eip6110) { - for (const depositReceipt of (body as eip6110.BeaconBlockBody).executionPayload.depositReceipts) { - processDepositReceipt(fork, state as CachedBeaconStateEIP6110, depositReceipt); + if (fork >= ForkSeq.electra) { + for (const depositReceipt of (body as electra.BeaconBlockBody).executionPayload.depositReceipts) { + processDepositReceipt(fork, state as CachedBeaconStateElectra, depositReceipt); } } } diff --git a/packages/state-transition/src/cache/epochCache.ts b/packages/state-transition/src/cache/epochCache.ts index f16b930eeea..f83b849f8b8 100644 --- a/packages/state-transition/src/cache/epochCache.ts +++ b/packages/state-transition/src/cache/epochCache.ts @@ -612,11 +612,11 @@ export class EpochCache { // ``` this.epoch = computeEpochAtSlot(state.slot); this.syncPeriod = computeSyncPeriodAtEpoch(this.epoch); - // 6110 Only: Add current cpState.validators.length + // ELECTRA Only: Add current cpState.validators.length // Only keep validatorLength for epochs after finalized cpState.epoch // eg. [100(epoch 1), 102(epoch 2)].push(104(epoch 3)), this.epoch = 3, finalized cp epoch = 1 // We keep the last (3 - 1) items = [102, 104] - if (currEpoch >= this.config.EIP6110_FORK_EPOCH) { + if (currEpoch >= this.config.ELECTRA_FORK_EPOCH) { this.historicalValidatorLengths = this.historicalValidatorLengths.push(state.validators.length); // If number of validatorLengths we want to keep exceeds the current list size, it implies @@ -828,7 +828,7 @@ export class EpochCache { } getValidatorIndex(pubkey: Uint8Array | PubkeyHex): ValidatorIndex | undefined { - if (this.isAfterEIP6110()) { + if (this.isAfterElectra()) { return this.pubkey2index.get(pubkey) ?? this.unfinalizedPubkey2index.get(toMemoryEfficientHexStr(pubkey)); } else { return this.pubkey2index.get(pubkey); @@ -841,10 +841,10 @@ export class EpochCache { * */ addPubkey(index: ValidatorIndex, pubkey: Uint8Array): void { - if (this.isAfterEIP6110()) { + if (this.isAfterElectra()) { this.addUnFinalizedPubkey(index, pubkey); } else { - // deposit mechanism pre 6110 follows a safe distance with assumption + // deposit mechanism pre ELECTRA follows a safe distance with assumption // that they are already canonical this.addFinalizedPubkey(index, pubkey); } @@ -963,14 +963,14 @@ export class EpochCache { } effectiveBalanceIncrementsSet(index: number, effectiveBalance: number): void { - if (this.isAfterEIP6110()) { + if (this.isAfterElectra()) { // TODO: electra // getting length and setting getEffectiveBalanceIncrementsByteLen is not fork safe // so each time we add an index, we should new the Uint8Array to keep it forksafe // one simple optimization could be to increment the length once per block rather // on each add/set // - // there could still be some unused length remaining from the prev 6110 padding + // there could still be some unused length remaining from the prev ELECTRA padding const newLength = index >= this.effectiveBalanceIncrements.length ? index + 1 : this.effectiveBalanceIncrements.length; const effectiveBalanceIncrements = this.effectiveBalanceIncrements; @@ -988,8 +988,8 @@ export class EpochCache { this.effectiveBalanceIncrements[index] = Math.floor(effectiveBalance / EFFECTIVE_BALANCE_INCREMENT); } - isAfterEIP6110(): boolean { - return this.epoch >= (this.config.EIP6110_FORK_EPOCH ?? Infinity); + isAfterElectra(): boolean { + return this.epoch >= (this.config.ELECTRA_FORK_EPOCH ?? Infinity); } getValidatorCountAtEpoch(targetEpoch: Epoch): number | undefined { diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 0323f4bcb72..aaaaf62a48d 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -11,7 +11,7 @@ import { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, - BeaconStateEIP6110, + BeaconStateElectra, } from "./types.js"; import {RewardCache, createEmptyRewardCache} from "./rewardCache.js"; @@ -132,13 +132,13 @@ export type CachedBeaconStateAltair = CachedBeaconState; export type CachedBeaconStateBellatrix = CachedBeaconState; export type CachedBeaconStateCapella = CachedBeaconState; export type CachedBeaconStateDeneb = CachedBeaconState; -export type CachedBeaconStateEIP6110 = CachedBeaconState; +export type CachedBeaconStateElectra = CachedBeaconState; export type CachedBeaconStateAllForks = CachedBeaconState; export type CachedBeaconStateExecutions = CachedBeaconState; /** * Create CachedBeaconState computing a new EpochCache instance - * TODO 6110: rename this to createFinalizedCachedBeaconState() as it's intended for finalized state only + * TODO ELECTRA: rename this to createFinalizedCachedBeaconState() as it's intended for finalized state only */ export function createCachedBeaconState( state: T, @@ -162,7 +162,7 @@ export function createCachedBeaconState( * Create a CachedBeaconState given a cached seed state and state bytes * This guarantees that the returned state shares the same tree with the seed state * Check loadState() api for more details - * // TODO: rename to loadUnfinalizedCachedBeaconState() due to EIP-6110 + * // TODO: rename to loadUnfinalizedCachedBeaconState() due to ELECTRA */ export function loadCachedBeaconState( cachedSeedState: T, diff --git a/packages/state-transition/src/cache/types.ts b/packages/state-transition/src/cache/types.ts index e27ae53d256..a865aa4f418 100644 --- a/packages/state-transition/src/cache/types.ts +++ b/packages/state-transition/src/cache/types.ts @@ -7,7 +7,7 @@ export type BeaconStateAltair = CompositeViewDU; export type BeaconStateBellatrix = CompositeViewDU; export type BeaconStateCapella = CompositeViewDU; export type BeaconStateDeneb = CompositeViewDU; -export type BeaconStateEIP6110 = CompositeViewDU; +export type BeaconStateElectra = CompositeViewDU; // Union at the TreeViewDU level // - Works well as function argument and as generic type for allForks functions @@ -20,8 +20,8 @@ export type BeaconStateAllForks = | BeaconStateBellatrix | BeaconStateCapella | BeaconStateDeneb - | BeaconStateEIP6110; + | BeaconStateElectra; -export type BeaconStateExecutions = BeaconStateBellatrix | BeaconStateCapella | BeaconStateDeneb | BeaconStateEIP6110; +export type BeaconStateExecutions = BeaconStateBellatrix | BeaconStateCapella | BeaconStateDeneb | BeaconStateElectra; export type ShufflingGetter = (shufflingEpoch: Epoch, dependentRoot: RootHex) => EpochShuffling | null; diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 1c2282f08b2..35964bc4800 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -11,7 +11,7 @@ export type { CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, - CachedBeaconStateEIP6110, + CachedBeaconStateElectra, CachedBeaconStateAllForks, CachedBeaconStateExecutions, // Non-cached states @@ -20,7 +20,7 @@ export type { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, - BeaconStateEIP6110, + BeaconStateElectra, BeaconStateAllForks, BeaconStateExecutions, } from "./types.js"; diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index 428c6c5e7fc..19cac8811f7 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -1,33 +1,33 @@ import {ssz} from "@lodestar/types"; import {UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateDeneb} from "../types.js"; -import {CachedBeaconStateEIP6110, getCachedBeaconState} from "../cache/stateCache.js"; +import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; /** * Upgrade a state from Capella to Deneb. */ -export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateEIP6110 { +export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateElectra { const {config} = stateDeneb; - const stateEIP6110Node = ssz.deneb.BeaconState.commitViewDU(stateDeneb); - const stateEIP6110View = ssz.eip6110.BeaconState.getViewDU(stateEIP6110Node); + const stateElectraNode = ssz.deneb.BeaconState.commitViewDU(stateDeneb); + const stateElectraView = ssz.electra.BeaconState.getViewDU(stateElectraNode); - const stateEIP6110 = getCachedBeaconState(stateEIP6110View, stateDeneb); + const stateElectra = getCachedBeaconState(stateElectraView, stateDeneb); - stateEIP6110.fork = ssz.phase0.Fork.toViewDU({ + stateElectra.fork = ssz.phase0.Fork.toViewDU({ previousVersion: stateDeneb.fork.currentVersion, - currentVersion: config.EIP6110_FORK_VERSION, + currentVersion: config.ELECTRA_FORK_VERSION, epoch: stateDeneb.epochCtx.epoch, }); // latestExecutionPayloadHeader's depositReceiptsRoot set to zeros by default // default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX - stateEIP6110.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; // Commit new added fields ViewDU to the root node - stateEIP6110.commit(); - // Clear cache to ensure the cache of deneb fields is not used by new EIP6110 fields - stateEIP6110["clearCache"](); + stateElectra.commit(); + // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields + stateElectra["clearCache"](); - return stateEIP6110; + return stateElectra; } diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index 3aaacd2ee64..049f04dce28 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -232,7 +232,7 @@ function processSlotsWithTransientCache( if (stateSlot === config.DENEB_FORK_EPOCH) { postState = upgradeStateToDeneb(postState as CachedBeaconStateCapella) as CachedBeaconStateAllForks; } - if (stateSlot === config.EIP6110_FORK_EPOCH) { + if (stateSlot === config.ELECTRA_FORK_EPOCH) { postState = upgradeStateToElectra(postState as CachedBeaconStateDeneb) as CachedBeaconStateAllForks; } } else { diff --git a/packages/state-transition/src/types.ts b/packages/state-transition/src/types.ts index b01d6e1867a..d3a1ed69a7a 100644 --- a/packages/state-transition/src/types.ts +++ b/packages/state-transition/src/types.ts @@ -9,7 +9,7 @@ export type { CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, - CachedBeaconStateEIP6110, + CachedBeaconStateElectra, } from "./cache/stateCache.js"; export type { @@ -20,5 +20,5 @@ export type { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, - BeaconStateEIP6110, + BeaconStateElectra, } from "./cache/types.js"; diff --git a/packages/state-transition/src/util/deposit.ts b/packages/state-transition/src/util/deposit.ts index 56b9aef9bd9..493099fdd98 100644 --- a/packages/state-transition/src/util/deposit.ts +++ b/packages/state-transition/src/util/deposit.ts @@ -1,17 +1,17 @@ import {ForkSeq, MAX_DEPOSITS} from "@lodestar/params"; import {UintNum64, phase0} from "@lodestar/types"; -import {CachedBeaconStateAllForks, CachedBeaconStateEIP6110} from "../types.js"; +import {CachedBeaconStateAllForks, CachedBeaconStateElectra} from "../types.js"; export function getEth1DepositCount(state: CachedBeaconStateAllForks, eth1Data?: phase0.Eth1Data): UintNum64 { const eth1DataToUse = eth1Data ?? state.eth1Data; - if (state.config.getForkSeq(state.slot) >= ForkSeq.eip6110) { - const eip6110State = state as CachedBeaconStateEIP6110; + if (state.config.getForkSeq(state.slot) >= ForkSeq.electra) { + const electraState = state as CachedBeaconStateElectra; // eth1DataIndexLimit = min(UintNum64, UintBn64) can be safely casted as UintNum64 // since the result lies within upper and lower bound of UintNum64 const eth1DataIndexLimit: UintNum64 = - eth1DataToUse.depositCount < eip6110State.depositReceiptsStartIndex + eth1DataToUse.depositCount < electraState.depositReceiptsStartIndex ? eth1DataToUse.depositCount - : Number(eip6110State.depositReceiptsStartIndex); + : Number(electraState.depositReceiptsStartIndex); if (state.eth1DepositIndex < eth1DataIndexLimit) { return Math.min(MAX_DEPOSITS, eth1DataIndexLimit - state.eth1DepositIndex); diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index eb1f35f6973..b7923fd9f80 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -1,4 +1,4 @@ -import {allForks, bellatrix, capella, deneb, eip6110, isBlindedBeaconBlockBody, ssz} from "@lodestar/types"; +import {allForks, bellatrix, capella, deneb, electra, isBlindedBeaconBlockBody, ssz} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import { @@ -170,9 +170,9 @@ export function executionPayloadToPayloadHeader( ).excessBlobGas; } - if (fork >= ForkSeq.eip6110) { - (bellatrixPayloadFields as eip6110.ExecutionPayloadHeader).depositReceiptsRoot = - ssz.eip6110.DepositReceipts.hashTreeRoot((payload as eip6110.ExecutionPayload).depositReceipts); + if (fork >= ForkSeq.electra) { + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot = + ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts); } return bellatrixPayloadFields; diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index d2036ec7373..6c700436d7f 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -215,7 +215,7 @@ export function initializeBeaconStateFromEth1( | typeof ssz.bellatrix.ExecutionPayloadHeader | typeof ssz.capella.ExecutionPayloadHeader | typeof ssz.deneb.ExecutionPayloadHeader - | typeof ssz.eip6110.ExecutionPayloadHeader + | typeof ssz.electra.ExecutionPayloadHeader > ): CachedBeaconStateAllForks { const stateView = getGenesisBeaconState( @@ -286,14 +286,14 @@ export function initializeBeaconStateFromEth1( ssz.deneb.ExecutionPayloadHeader.defaultViewDU(); } - if (GENESIS_SLOT >= config.EIP6110_FORK_EPOCH) { - const stateEIP6110 = state as CompositeViewDU; - stateEIP6110.fork.previousVersion = config.EIP6110_FORK_VERSION; - stateEIP6110.fork.currentVersion = config.EIP6110_FORK_VERSION; - stateEIP6110.latestExecutionPayloadHeader = - (executionPayloadHeader as CompositeViewDU) ?? - ssz.eip6110.ExecutionPayloadHeader.defaultViewDU(); - stateEIP6110.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; + if (GENESIS_SLOT >= config.ELECTRA_FORK_EPOCH) { + const stateElectra = state as CompositeViewDU; + stateElectra.fork.previousVersion = config.ELECTRA_FORK_VERSION; + stateElectra.fork.currentVersion = config.ELECTRA_FORK_VERSION; + stateElectra.latestExecutionPayloadHeader = + (executionPayloadHeader as CompositeViewDU) ?? + ssz.electra.ExecutionPayloadHeader.defaultViewDU(); + stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX; } state.commit(); diff --git a/packages/state-transition/test/unit/cachedBeaconState.test.ts b/packages/state-transition/test/unit/cachedBeaconState.test.ts index 81162670b73..9b05b8947f7 100644 --- a/packages/state-transition/test/unit/cachedBeaconState.test.ts +++ b/packages/state-transition/test/unit/cachedBeaconState.test.ts @@ -29,7 +29,7 @@ describe("CachedBeaconState", () => { expect(state2.epochCtx.epoch).toBe(0); }); - it("Clone and mutate cache pre-6110", () => { + it("Clone and mutate cache pre-Electra", () => { const stateView = ssz.altair.BeaconState.defaultViewDU(); const state1 = createCachedBeaconStateTest(stateView); @@ -54,8 +54,8 @@ describe("CachedBeaconState", () => { }); /* eslint-disable @typescript-eslint/naming-convention */ - it("Clone and mutate cache post-6110", () => { - const stateView = ssz.eip6110.BeaconState.defaultViewDU(); + it("Clone and mutate cache post-Electra", () => { + const stateView = ssz.electra.BeaconState.defaultViewDU(); const state1 = createCachedBeaconStateTest( stateView, createChainForkConfig({ @@ -63,7 +63,7 @@ describe("CachedBeaconState", () => { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, - EIP6110_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, }), {skipSyncCommitteeCache: true, skipSyncPubkeys: true} ); diff --git a/packages/state-transition/test/unit/util/deposit.test.ts b/packages/state-transition/test/unit/util/deposit.test.ts index b03a3ee6505..e8f7f7a86af 100644 --- a/packages/state-transition/test/unit/util/deposit.test.ts +++ b/packages/state-transition/test/unit/util/deposit.test.ts @@ -2,31 +2,31 @@ import {describe, it, expect} from "vitest"; import {ssz} from "@lodestar/types"; import {createChainForkConfig} from "@lodestar/config"; import {MAX_DEPOSITS} from "@lodestar/params"; -import {CachedBeaconStateEIP6110, getEth1DepositCount} from "../../../src/index.js"; +import {CachedBeaconStateElectra, getEth1DepositCount} from "../../../src/index.js"; import {createCachedBeaconStateTest} from "../../utils/state.js"; describe("getEth1DepositCount", () => { - it("Pre 6110", () => { + it("Pre Electra", () => { const stateView = ssz.altair.BeaconState.defaultViewDU(); - const pre6110State = createCachedBeaconStateTest(stateView); + const preElectraState = createCachedBeaconStateTest(stateView); - if (pre6110State.epochCtx.isAfterEIP6110()) { - throw Error("Not a pre-6110 state"); + if (preElectraState.epochCtx.isAfterElectra()) { + throw Error("Not a pre-Electra state"); } - pre6110State.eth1Data.depositCount = 123; + preElectraState.eth1Data.depositCount = 123; // 1. Should get less than MAX_DEPOSIT - pre6110State.eth1DepositIndex = 120; - expect(getEth1DepositCount(pre6110State)).toBe(3); + preElectraState.eth1DepositIndex = 120; + expect(getEth1DepositCount(preElectraState)).toBe(3); // 2. Should get MAX_DEPOSIT - pre6110State.eth1DepositIndex = 100; - expect(getEth1DepositCount(pre6110State)).toBe(MAX_DEPOSITS); + preElectraState.eth1DepositIndex = 100; + expect(getEth1DepositCount(preElectraState)).toBe(MAX_DEPOSITS); }); - it("Post 6110 with eth1 deposit", () => { - const stateView = ssz.eip6110.BeaconState.defaultViewDU(); - const post6110State = createCachedBeaconStateTest( + it("Post Electra with eth1 deposit", () => { + const stateView = ssz.electra.BeaconState.defaultViewDU(); + const postElectraState = createCachedBeaconStateTest( stateView, createChainForkConfig({ /* eslint-disable @typescript-eslint/naming-convention */ @@ -34,33 +34,33 @@ describe("getEth1DepositCount", () => { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, - EIP6110_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, }), {skipSyncCommitteeCache: true, skipSyncPubkeys: true} - ) as CachedBeaconStateEIP6110; + ) as CachedBeaconStateElectra; - if (!post6110State.epochCtx.isAfterEIP6110()) { - throw Error("Not a post-6110 state"); + if (!postElectraState.epochCtx.isAfterElectra()) { + throw Error("Not a post-Electra state"); } - post6110State.depositReceiptsStartIndex = 1000n; - post6110State.eth1Data.depositCount = 995; + postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.eth1Data.depositCount = 995; // 1. Should get less than MAX_DEPOSIT - post6110State.eth1DepositIndex = 990; - expect(getEth1DepositCount(post6110State)).toBe(5); + postElectraState.eth1DepositIndex = 990; + expect(getEth1DepositCount(postElectraState)).toBe(5); // 2. Should get MAX_DEPOSIT - post6110State.eth1DepositIndex = 100; - expect(getEth1DepositCount(post6110State)).toBe(MAX_DEPOSITS); + postElectraState.eth1DepositIndex = 100; + expect(getEth1DepositCount(postElectraState)).toBe(MAX_DEPOSITS); // 3. Should be 0 - post6110State.eth1DepositIndex = 1000; - expect(getEth1DepositCount(post6110State)).toBe(0); + postElectraState.eth1DepositIndex = 1000; + expect(getEth1DepositCount(postElectraState)).toBe(0); }); - it("Post 6110 without eth1 deposit", () => { - const stateView = ssz.eip6110.BeaconState.defaultViewDU(); - const post6110State = createCachedBeaconStateTest( + it("Post Electra without eth1 deposit", () => { + const stateView = ssz.electra.BeaconState.defaultViewDU(); + const postElectraState = createCachedBeaconStateTest( stateView, createChainForkConfig({ /* eslint-disable @typescript-eslint/naming-convention */ @@ -68,32 +68,32 @@ describe("getEth1DepositCount", () => { BELLATRIX_FORK_EPOCH: 0, CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: 0, - EIP6110_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, }), {skipSyncCommitteeCache: true, skipSyncPubkeys: true} - ) as CachedBeaconStateEIP6110; + ) as CachedBeaconStateElectra; - if (!post6110State.epochCtx.isAfterEIP6110()) { - throw Error("Not a post-6110 state"); + if (!postElectraState.epochCtx.isAfterElectra()) { + throw Error("Not a post-Electra state"); } - post6110State.depositReceiptsStartIndex = 1000n; - post6110State.eth1Data.depositCount = 1005; + postElectraState.depositReceiptsStartIndex = 1000n; + postElectraState.eth1Data.depositCount = 1005; // Before eth1DepositIndex reaching the start index // 1. Should get less than MAX_DEPOSIT - post6110State.eth1DepositIndex = 990; - expect(getEth1DepositCount(post6110State)).toBe(10); + postElectraState.eth1DepositIndex = 990; + expect(getEth1DepositCount(postElectraState)).toBe(10); // 2. Should get MAX_DEPOSIT - post6110State.eth1DepositIndex = 983; - expect(getEth1DepositCount(post6110State)).toBe(MAX_DEPOSITS); + postElectraState.eth1DepositIndex = 983; + expect(getEth1DepositCount(postElectraState)).toBe(MAX_DEPOSITS); // After eth1DepositIndex reaching the start index // 1. Should be 0 - post6110State.eth1DepositIndex = 1000; - expect(getEth1DepositCount(post6110State)).toBe(0); - post6110State.eth1DepositIndex = 1003; - expect(getEth1DepositCount(post6110State)).toBe(0); + postElectraState.eth1DepositIndex = 1000; + expect(getEth1DepositCount(postElectraState)).toBe(0); + postElectraState.eth1DepositIndex = 1003; + expect(getEth1DepositCount(postElectraState)).toBe(0); }); }); diff --git a/packages/types/package.json b/packages/types/package.json index 45399089a60..cde08a6ce8d 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -32,8 +32,8 @@ "./deneb": { "import": "./lib/deneb/index.js" }, - "./eip6110": { - "import": "./lib/eip6110/index.js" + "./electra": { + "import": "./lib/electra/index.js" }, "./phase0": { "import": "./lib/phase0/index.js" diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 6030215ac8c..84c6bb86ce5 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -192,7 +192,7 @@ export const allForksBlobs = { ExecutionPayloadAndBlobsBundle: deneb.ExecutionPayloadAndBlobsBundle, }, electra: { - BlobSidecar: electra.BlobSidecar, + BlobSidecar: deneb.BlobSidecar, ExecutionPayloadAndBlobsBundle: electra.ExecutionPayloadAndBlobsBundle, }, }; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 7454f4b5a2a..416bb051065 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -4,14 +4,14 @@ import {ts as altair} from "../altair/index.js"; import {ts as bellatrix} from "../bellatrix/index.js"; import {ts as capella} from "../capella/index.js"; import {ts as deneb} from "../deneb/index.js"; -import {ts as eip6110} from "../eip6110/index.js"; +import {ts as electra} from "../electra/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -import {ssz as eip6110Ssz} from "../eip6110/index.js"; +import {ssz as electraSsz} from "../electra/index.js"; // Re-export union types for types that are _known_ to differ @@ -21,28 +21,28 @@ export type BeaconBlockBody = | bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody - | eip6110.BeaconBlockBody; + | electra.BeaconBlockBody; export type BeaconBlock = | phase0.BeaconBlock | altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock - | eip6110.BeaconBlock; + | electra.BeaconBlock; export type SignedBeaconBlock = | phase0.SignedBeaconBlock | altair.SignedBeaconBlock | bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock | deneb.SignedBeaconBlock - | eip6110.SignedBeaconBlock; + | electra.SignedBeaconBlock; export type BeaconState = | phase0.BeaconState | altair.BeaconState | bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState - | eip6110.BeaconState; + | electra.BeaconState; export type Metadata = phase0.Metadata | altair.Metadata; // For easy reference in the assemble block for building payloads @@ -50,36 +50,36 @@ export type ExecutionBlockBody = | bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody - | eip6110.BeaconBlockBody; + | electra.BeaconBlockBody; // These two additional types will also change bellatrix forward export type ExecutionPayload = | bellatrix.ExecutionPayload | capella.ExecutionPayload | deneb.ExecutionPayload - | eip6110.ExecutionPayload; + | electra.ExecutionPayload; export type ExecutionPayloadHeader = | bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader | deneb.ExecutionPayloadHeader - | eip6110.ExecutionPayloadHeader; + | electra.ExecutionPayloadHeader; // Blinded types that will change across forks export type BlindedBeaconBlockBody = | bellatrix.BlindedBeaconBlockBody | capella.BlindedBeaconBlockBody | deneb.BlindedBeaconBlockBody - | eip6110.BlindedBeaconBlockBody; + | electra.BlindedBeaconBlockBody; export type BlindedBeaconBlock = | bellatrix.BlindedBeaconBlock | capella.BlindedBeaconBlock | deneb.BlindedBeaconBlock - | eip6110.BlindedBeaconBlock; + | electra.BlindedBeaconBlock; export type SignedBlindedBeaconBlock = | bellatrix.SignedBlindedBeaconBlock | capella.SignedBlindedBeaconBlock | deneb.SignedBlindedBeaconBlock - | eip6110.SignedBlindedBeaconBlock; + | electra.SignedBlindedBeaconBlock; // Full or blinded types export type FullOrBlindedExecutionPayload = @@ -101,52 +101,52 @@ export type SignedBeaconBlockOrContents = SignedBeaconBlock | SignedBlockContent export type FullOrBlindedBeaconBlockOrContents = BeaconBlockOrContents | BlindedBeaconBlock; -export type BuilderBid = bellatrix.BuilderBid | capella.BuilderBid | deneb.BuilderBid | eip6110.BuilderBid; +export type BuilderBid = bellatrix.BuilderBid | capella.BuilderBid | deneb.BuilderBid | electra.BuilderBid; export type SignedBuilderBid = | bellatrix.SignedBuilderBid | capella.SignedBuilderBid | deneb.SignedBuilderBid - | eip6110.SignedBuilderBid; + | electra.SignedBuilderBid; export type ExecutionPayloadAndBlobsBundle = | deneb.ExecutionPayloadAndBlobsBundle - | eip6110.ExecutionPayloadAndBlobsBundle; + | electra.ExecutionPayloadAndBlobsBundle; export type LightClientHeader = | altair.LightClientHeader | capella.LightClientHeader | deneb.LightClientHeader - | eip6110.LightClientHeader; + | electra.LightClientHeader; export type LightClientBootstrap = | altair.LightClientBootstrap | capella.LightClientBootstrap | deneb.LightClientBootstrap - | eip6110.LightClientBootstrap; + | electra.LightClientBootstrap; export type LightClientUpdate = | altair.LightClientUpdate | capella.LightClientUpdate | deneb.LightClientUpdate - | eip6110.LightClientUpdate; + | electra.LightClientUpdate; export type LightClientFinalityUpdate = | altair.LightClientFinalityUpdate | capella.LightClientFinalityUpdate | deneb.LightClientFinalityUpdate - | eip6110.LightClientFinalityUpdate; + | electra.LightClientFinalityUpdate; export type LightClientOptimisticUpdate = | altair.LightClientOptimisticUpdate | capella.LightClientOptimisticUpdate | deneb.LightClientOptimisticUpdate - | eip6110.LightClientOptimisticUpdate; + | electra.LightClientOptimisticUpdate; export type LightClientStore = | altair.LightClientStore | capella.LightClientStore | deneb.LightClientStore - | eip6110.LightClientStore; + | electra.LightClientStore; export type SSEPayloadAttributes = | bellatrix.SSEPayloadAttributes | capella.SSEPayloadAttributes | deneb.SSEPayloadAttributes - | eip6110.SSEPayloadAttributes; + | electra.SSEPayloadAttributes; /** * Types known to change between forks @@ -176,7 +176,7 @@ export type AllForksLightClient = { | bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock - | eip6110.BeaconBlock; + | electra.BeaconBlock; LightClientHeader: LightClientHeader; LightClientBootstrap: LightClientBootstrap; LightClientUpdate: LightClientUpdate; @@ -186,12 +186,12 @@ export type AllForksLightClient = { }; export type AllForksExecution = { - BeaconBlock: bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock | eip6110.BeaconBlock; + BeaconBlock: bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock | electra.BeaconBlock; BeaconBlockBody: | bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody - | eip6110.BeaconBlockBody; + | electra.BeaconBlockBody; }; /** @@ -230,7 +230,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody - | typeof eip6110Ssz.BeaconBlockBody + | typeof electraSsz.BeaconBlockBody >; BeaconBlock: AllForksTypeOf< | typeof phase0Ssz.BeaconBlock @@ -238,7 +238,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock - | typeof eip6110Ssz.BeaconBlock + | typeof electraSsz.BeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof phase0Ssz.SignedBeaconBlock @@ -246,7 +246,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock - | typeof eip6110Ssz.SignedBeaconBlock + | typeof electraSsz.SignedBeaconBlock >; BeaconState: AllForksTypeOf< | typeof phase0Ssz.BeaconState @@ -254,7 +254,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState - | typeof eip6110Ssz.BeaconState + | typeof electraSsz.BeaconState >; Metadata: AllForksTypeOf; }; @@ -264,55 +264,55 @@ export type AllForksExecutionSSZTypes = { | typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody - | typeof eip6110Ssz.BeaconBlockBody + | typeof electraSsz.BeaconBlockBody >; BeaconBlock: AllForksTypeOf< | typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock - | typeof eip6110Ssz.BeaconBlock + | typeof electraSsz.BeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock - | typeof eip6110Ssz.SignedBeaconBlock + | typeof electraSsz.SignedBeaconBlock >; BeaconState: AllForksTypeOf< | typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState - | typeof eip6110Ssz.BeaconState + | typeof electraSsz.BeaconState >; ExecutionPayload: AllForksTypeOf< | typeof bellatrixSsz.ExecutionPayload | typeof capellaSsz.ExecutionPayload | typeof denebSsz.ExecutionPayload - | typeof eip6110Ssz.ExecutionPayload + | typeof electraSsz.ExecutionPayload >; ExecutionPayloadHeader: AllForksTypeOf< | typeof bellatrixSsz.ExecutionPayloadHeader | typeof capellaSsz.ExecutionPayloadHeader | typeof denebSsz.ExecutionPayloadHeader - | typeof eip6110Ssz.ExecutionPayloadHeader + | typeof electraSsz.ExecutionPayloadHeader >; BuilderBid: AllForksTypeOf< | typeof bellatrixSsz.BuilderBid | typeof capellaSsz.BuilderBid | typeof denebSsz.BuilderBid - | typeof eip6110Ssz.BuilderBid + | typeof electraSsz.BuilderBid >; SignedBuilderBid: AllForksTypeOf< | typeof bellatrixSsz.SignedBuilderBid | typeof capellaSsz.SignedBuilderBid | typeof denebSsz.SignedBuilderBid - | typeof eip6110Ssz.SignedBuilderBid + | typeof electraSsz.SignedBuilderBid >; SSEPayloadAttributes: AllForksTypeOf< | typeof bellatrixSsz.SSEPayloadAttributes | typeof capellaSsz.SSEPayloadAttributes | typeof denebSsz.SSEPayloadAttributes - | typeof eip6110Ssz.SSEPayloadAttributes + | typeof electraSsz.SSEPayloadAttributes >; }; @@ -321,19 +321,19 @@ export type AllForksBlindedSSZTypes = { | typeof bellatrixSsz.BlindedBeaconBlockBody | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock - | typeof eip6110Ssz.BlindedBeaconBlock + | typeof electraSsz.BlindedBeaconBlock >; BeaconBlock: AllForksTypeOf< | typeof bellatrixSsz.BlindedBeaconBlock | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock - | typeof eip6110Ssz.BlindedBeaconBlock + | typeof electraSsz.BlindedBeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof bellatrixSsz.SignedBlindedBeaconBlock | typeof capellaSsz.SignedBlindedBeaconBlock | typeof denebSsz.SignedBlindedBeaconBlock - | typeof eip6110Ssz.SignedBlindedBeaconBlock + | typeof electraSsz.SignedBlindedBeaconBlock >; }; @@ -343,56 +343,56 @@ export type AllForksLightClientSSZTypes = { | typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock - | typeof eip6110Ssz.BeaconBlock + | typeof electraSsz.BeaconBlock >; BeaconBlockBody: AllForksTypeOf< | typeof altairSsz.BeaconBlockBody | typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody - | typeof eip6110Ssz.BeaconBlockBody + | typeof electraSsz.BeaconBlockBody >; LightClientHeader: AllForksTypeOf< | typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader - | typeof eip6110Ssz.LightClientHeader + | typeof electraSsz.LightClientHeader >; LightClientBootstrap: AllForksTypeOf< | typeof altairSsz.LightClientBootstrap | typeof capellaSsz.LightClientBootstrap | typeof denebSsz.LightClientBootstrap - | typeof eip6110Ssz.LightClientBootstrap + | typeof electraSsz.LightClientBootstrap >; LightClientUpdate: AllForksTypeOf< | typeof altairSsz.LightClientUpdate | typeof capellaSsz.LightClientUpdate | typeof denebSsz.LightClientUpdate - | typeof eip6110Ssz.LightClientUpdate + | typeof electraSsz.LightClientUpdate >; LightClientFinalityUpdate: AllForksTypeOf< | typeof altairSsz.LightClientFinalityUpdate | typeof capellaSsz.LightClientFinalityUpdate | typeof denebSsz.LightClientFinalityUpdate - | typeof eip6110Ssz.LightClientFinalityUpdate + | typeof electraSsz.LightClientFinalityUpdate >; LightClientOptimisticUpdate: AllForksTypeOf< | typeof altairSsz.LightClientOptimisticUpdate | typeof capellaSsz.LightClientOptimisticUpdate | typeof denebSsz.LightClientOptimisticUpdate - | typeof eip6110Ssz.LightClientOptimisticUpdate + | typeof electraSsz.LightClientOptimisticUpdate >; LightClientStore: AllForksTypeOf< | typeof altairSsz.LightClientStore | typeof capellaSsz.LightClientStore | typeof denebSsz.LightClientStore - | typeof eip6110Ssz.LightClientStore + | typeof electraSsz.LightClientStore >; }; export type AllForksBlobsSSZTypes = { BlobSidecar: AllForksTypeOf; ExecutionPayloadAndBlobsBundle: AllForksTypeOf< - typeof denebSsz.ExecutionPayloadAndBlobsBundle | typeof eip6110Ssz.ExecutionPayloadAndBlobsBundle + typeof denebSsz.ExecutionPayloadAndBlobsBundle | typeof electraSsz.ExecutionPayloadAndBlobsBundle >; }; diff --git a/packages/types/src/eip6110/index.ts b/packages/types/src/eip6110/index.ts deleted file mode 100644 index 7856cd72962..00000000000 --- a/packages/types/src/eip6110/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./types.js"; -export * as ts from "./types.js"; -export * as ssz from "./sszTypes.js"; diff --git a/packages/types/src/eip6110/sszTypes.ts b/packages/types/src/eip6110/sszTypes.ts deleted file mode 100644 index d787dc5acce..00000000000 --- a/packages/types/src/eip6110/sszTypes.ts +++ /dev/null @@ -1,249 +0,0 @@ -import {ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; -import { - HISTORICAL_ROOTS_LIMIT, - BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, - EPOCHS_PER_SYNC_COMMITTEE_PERIOD, - SLOTS_PER_EPOCH, - MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, -} from "@lodestar/params"; -import {ssz as primitiveSsz} from "../primitive/index.js"; -import {ssz as phase0Ssz} from "../phase0/index.js"; -import {ssz as altairSsz} from "../altair/index.js"; -import {ssz as bellatrixSsz} from "../bellatrix/index.js"; -import {ssz as capellaSsz} from "../capella/index.js"; -import {ssz as denebSsz} from "../deneb/index.js"; - -const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, DepositIndex, UintBn64} = primitiveSsz; - -export const DepositReceipt = new ContainerType( - { - pubkey: BLSPubkey, - withdrawalCredentials: Bytes32, - amount: UintNum64, - signature: BLSSignature, - index: DepositIndex, - }, - {typeName: "DepositReceipt", jsonCase: "eth2"} -); - -export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); - -export const ExecutionPayload = new ContainerType( - { - ...denebSsz.ExecutionPayload.fields, - depositReceipts: DepositReceipts, // New in EIP6110 - }, - {typeName: "ExecutionPayload", jsonCase: "eth2"} -); - -export const ExecutionPayloadHeader = new ContainerType( - { - ...denebSsz.ExecutionPayloadHeader.fields, - depositReceiptsRoot: Root, // New in EIP6110 - }, - {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} -); - -// We have to preserve Fields ordering while changing the type of ExecutionPayload -export const BeaconBlockBody = new ContainerType( - { - ...altairSsz.BeaconBlockBody.fields, - executionPayload: ExecutionPayload, // Modified in EIP6110 - blsToExecutionChanges: denebSsz.BeaconBlockBody.fields.blsToExecutionChanges, - blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, - }, - {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} -); - -export const BeaconBlock = new ContainerType( - { - ...denebSsz.BeaconBlock.fields, - body: BeaconBlockBody, // Modified in EIP6110 - }, - {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} -); - -export const SignedBeaconBlock = new ContainerType( - { - message: BeaconBlock, // Modified in EIP6110 - signature: BLSSignature, - }, - {typeName: "SignedBeaconBlock", jsonCase: "eth2"} -); - -export const BlindedBeaconBlockBody = new ContainerType( - { - ...altairSsz.BeaconBlockBody.fields, - executionPayloadHeader: ExecutionPayloadHeader, // Modified in EIP6110 - blsToExecutionChanges: denebSsz.BeaconBlockBody.fields.blsToExecutionChanges, - blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, - }, - {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} -); - -export const BlindedBeaconBlock = new ContainerType( - { - ...denebSsz.BlindedBeaconBlock.fields, - body: BlindedBeaconBlockBody, // Modified in EIP6110 - }, - {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} -); - -export const SignedBlindedBeaconBlock = new ContainerType( - { - message: BlindedBeaconBlock, // Modified in EIP6110 - signature: BLSSignature, - }, - {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} -); - -export const BuilderBid = new ContainerType( - { - header: ExecutionPayloadHeader, // Modified in EIP6110 - blindedBlobsBundle: denebSsz.BlobKzgCommitments, - value: UintBn256, - pubkey: BLSPubkey, - }, - {typeName: "BuilderBid", jsonCase: "eth2"} -); - -export const SignedBuilderBid = new ContainerType( - { - message: BuilderBid, - signature: BLSSignature, - }, - {typeName: "SignedBuilderBid", jsonCase: "eth2"} -); - -export const ExecutionPayloadAndBlobsBundle = new ContainerType( - { - executionPayload: ExecutionPayload, // Modified in EIP6110 - blobsBundle: denebSsz.BlobsBundle, - }, - {typeName: "ExecutionPayloadAndBlobsBundle", jsonCase: "eth2"} -); - -// We don't spread deneb.BeaconState fields since we need to replace -// latestExecutionPayloadHeader and we cannot keep order doing that -export const BeaconState = new ContainerType( - { - genesisTime: UintNum64, - genesisValidatorsRoot: Root, - slot: primitiveSsz.Slot, - fork: phase0Ssz.Fork, - // History - latestBlockHeader: phase0Ssz.BeaconBlockHeader, - blockRoots: phase0Ssz.HistoricalBlockRoots, - stateRoots: phase0Ssz.HistoricalStateRoots, - // historical_roots Frozen in Capella, replaced by historical_summaries - historicalRoots: new ListCompositeType(Root, HISTORICAL_ROOTS_LIMIT), - // Eth1 - eth1Data: phase0Ssz.Eth1Data, - eth1DataVotes: phase0Ssz.Eth1DataVotes, - eth1DepositIndex: UintNum64, - // Registry - validators: phase0Ssz.Validators, - balances: phase0Ssz.Balances, - randaoMixes: phase0Ssz.RandaoMixes, - // Slashings - slashings: phase0Ssz.Slashings, - // Participation - previousEpochParticipation: altairSsz.EpochParticipation, - currentEpochParticipation: altairSsz.EpochParticipation, - // Finality - justificationBits: phase0Ssz.JustificationBits, - previousJustifiedCheckpoint: phase0Ssz.Checkpoint, - currentJustifiedCheckpoint: phase0Ssz.Checkpoint, - finalizedCheckpoint: phase0Ssz.Checkpoint, - // Inactivity - inactivityScores: altairSsz.InactivityScores, - // Sync - currentSyncCommittee: altairSsz.SyncCommittee, - nextSyncCommittee: altairSsz.SyncCommittee, - // Execution - latestExecutionPayloadHeader: ExecutionPayloadHeader, // Modified in EIP6110 - // Withdrawals - nextWithdrawalIndex: capellaSsz.BeaconState.fields.nextWithdrawalIndex, - nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, - // Deep history valid from Capella onwards - historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, - depositReceiptsStartIndex: UintBn64, // New in EIP6110 - }, - {typeName: "BeaconState", jsonCase: "eth2"} -); - -export const LightClientHeader = new ContainerType( - { - beacon: phase0Ssz.BeaconBlockHeader, - execution: ExecutionPayloadHeader, // Modified in EIP6110 - executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), - }, - {typeName: "LightClientHeader", jsonCase: "eth2"} -); - -export const LightClientBootstrap = new ContainerType( - { - header: LightClientHeader, - currentSyncCommittee: altairSsz.SyncCommittee, - currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, - }, - {typeName: "LightClientBootstrap", jsonCase: "eth2"} -); - -export const LightClientUpdate = new ContainerType( - { - attestedHeader: LightClientHeader, - nextSyncCommittee: altairSsz.SyncCommittee, - nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, - finalizedHeader: LightClientHeader, - finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, - syncAggregate: altairSsz.SyncAggregate, - signatureSlot: Slot, - }, - {typeName: "LightClientUpdate", jsonCase: "eth2"} -); - -export const LightClientFinalityUpdate = new ContainerType( - { - attestedHeader: LightClientHeader, - finalizedHeader: LightClientHeader, - finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, - syncAggregate: altairSsz.SyncAggregate, - signatureSlot: Slot, - }, - {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} -); - -export const LightClientOptimisticUpdate = new ContainerType( - { - attestedHeader: LightClientHeader, - syncAggregate: altairSsz.SyncAggregate, - signatureSlot: Slot, - }, - {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} -); - -export const LightClientStore = new ContainerType( - { - snapshot: LightClientBootstrap, - validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), - }, - {typeName: "LightClientStore", jsonCase: "eth2"} -); - -// PayloadAttributes primarily for SSE event -export const PayloadAttributes = new ContainerType( - { - ...capellaSsz.PayloadAttributes.fields, - parentBeaconBlockRoot: Root, - }, - {typeName: "PayloadAttributes", jsonCase: "eth2"} -); - -export const SSEPayloadAttributes = new ContainerType( - { - ...bellatrixSsz.SSEPayloadAttributesCommon.fields, - payloadAttributes: PayloadAttributes, - }, - {typeName: "SSEPayloadAttributes", jsonCase: "eth2"} -); diff --git a/packages/types/src/eip6110/types.ts b/packages/types/src/eip6110/types.ts deleted file mode 100644 index 3286c10a033..00000000000 --- a/packages/types/src/eip6110/types.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {ValueOf} from "@chainsafe/ssz"; -import * as ssz from "./sszTypes.js"; - -export type DepositReceipt = ValueOf; -export type DepositReceipts = ValueOf; - -export type ExecutionPayload = ValueOf; -export type ExecutionPayloadHeader = ValueOf; - -export type ExecutionPayloadAndBlobsBundle = ValueOf; - -export type BeaconBlockBody = ValueOf; -export type BeaconBlock = ValueOf; -export type SignedBeaconBlock = ValueOf; - -export type BeaconState = ValueOf; - -export type BlindedBeaconBlockBody = ValueOf; -export type BlindedBeaconBlock = ValueOf; -export type SignedBlindedBeaconBlock = ValueOf; - -export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadHeader; - -export type BuilderBid = ValueOf; -export type SignedBuilderBid = ValueOf; -export type SSEPayloadAttributes = ValueOf; - -export type LightClientHeader = ValueOf; -export type LightClientBootstrap = ValueOf; -export type LightClientUpdate = ValueOf; -export type LightClientFinalityUpdate = ValueOf; -export type LightClientOptimisticUpdate = ValueOf; -export type LightClientStore = ValueOf; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 30690a49984..c247c984fa7 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -1,12 +1,37 @@ -import {ContainerType} from "@chainsafe/ssz"; +import {ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; +import { + HISTORICAL_ROOTS_LIMIT, + BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + SLOTS_PER_EPOCH, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, +} from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as altairSsz} from "../altair/index.js"; +import {ssz as bellatrixSsz} from "../bellatrix/index.js"; +import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; -const {BLSSignature} = primitiveSsz; +const {UintNum64, Slot, Root, BLSSignature, UintBn256, Bytes32, BLSPubkey, DepositIndex, UintBn64} = primitiveSsz; + +export const DepositReceipt = new ContainerType( + { + pubkey: BLSPubkey, + withdrawalCredentials: Bytes32, + amount: UintNum64, + signature: BLSSignature, + index: DepositIndex, + }, + {typeName: "DepositReceipt", jsonCase: "eth2"} +); + +export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD); export const ExecutionPayload = new ContainerType( { ...denebSsz.ExecutionPayload.fields, + depositReceipts: DepositReceipts, // New in ELECTRA }, {typeName: "ExecutionPayload", jsonCase: "eth2"} ); @@ -14,13 +39,18 @@ export const ExecutionPayload = new ContainerType( export const ExecutionPayloadHeader = new ContainerType( { ...denebSsz.ExecutionPayloadHeader.fields, + depositReceiptsRoot: Root, // New in ELECTRA }, {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} ); +// We have to preserve Fields ordering while changing the type of ExecutionPayload export const BeaconBlockBody = new ContainerType( { - ...denebSsz.BeaconBlockBody.fields, + ...altairSsz.BeaconBlockBody.fields, + executionPayload: ExecutionPayload, // Modified in ELECTRA + blsToExecutionChanges: denebSsz.BeaconBlockBody.fields.blsToExecutionChanges, + blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, }, {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -28,28 +58,25 @@ export const BeaconBlockBody = new ContainerType( export const BeaconBlock = new ContainerType( { ...denebSsz.BeaconBlock.fields, + body: BeaconBlockBody, // Modified in ELECTRA }, {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); export const SignedBeaconBlock = new ContainerType( { - message: BeaconBlock, + message: BeaconBlock, // Modified in ELECTRA signature: BLSSignature, }, {typeName: "SignedBeaconBlock", jsonCase: "eth2"} ); -export const BlobSidecar = new ContainerType( - { - ...denebSsz.BlobSidecar.fields, - }, - {typeName: "BlobSidecar", jsonCase: "eth2"} -); - export const BlindedBeaconBlockBody = new ContainerType( { - ...denebSsz.BlindedBeaconBlockBody.fields, + ...altairSsz.BeaconBlockBody.fields, + executionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA + blsToExecutionChanges: denebSsz.BeaconBlockBody.fields.blsToExecutionChanges, + blobKzgCommitments: denebSsz.BeaconBlockBody.fields.blobKzgCommitments, }, {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -57,13 +84,14 @@ export const BlindedBeaconBlockBody = new ContainerType( export const BlindedBeaconBlock = new ContainerType( { ...denebSsz.BlindedBeaconBlock.fields, + body: BlindedBeaconBlockBody, // Modified in ELECTRA }, {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} ); export const SignedBlindedBeaconBlock = new ContainerType( { - message: BlindedBeaconBlock, + message: BlindedBeaconBlock, // Modified in ELECTRA signature: BLSSignature, }, {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} @@ -71,7 +99,10 @@ export const SignedBlindedBeaconBlock = new ContainerType( export const BuilderBid = new ContainerType( { - ...denebSsz.BuilderBid.fields, + header: ExecutionPayloadHeader, // Modified in ELECTRA + blindedBlobsBundle: denebSsz.BlobKzgCommitments, + value: UintBn256, + pubkey: BLSPubkey, }, {typeName: "BuilderBid", jsonCase: "eth2"} ); @@ -86,63 +117,133 @@ export const SignedBuilderBid = new ContainerType( export const ExecutionPayloadAndBlobsBundle = new ContainerType( { - ...denebSsz.ExecutionPayloadAndBlobsBundle.fields, + executionPayload: ExecutionPayload, // Modified in ELECTRA + blobsBundle: denebSsz.BlobsBundle, }, {typeName: "ExecutionPayloadAndBlobsBundle", jsonCase: "eth2"} ); +// We don't spread deneb.BeaconState fields since we need to replace +// latestExecutionPayloadHeader and we cannot keep order doing that export const BeaconState = new ContainerType( { - ...denebSsz.BeaconState.fields, + genesisTime: UintNum64, + genesisValidatorsRoot: Root, + slot: primitiveSsz.Slot, + fork: phase0Ssz.Fork, + // History + latestBlockHeader: phase0Ssz.BeaconBlockHeader, + blockRoots: phase0Ssz.HistoricalBlockRoots, + stateRoots: phase0Ssz.HistoricalStateRoots, + // historical_roots Frozen in Capella, replaced by historical_summaries + historicalRoots: new ListCompositeType(Root, HISTORICAL_ROOTS_LIMIT), + // Eth1 + eth1Data: phase0Ssz.Eth1Data, + eth1DataVotes: phase0Ssz.Eth1DataVotes, + eth1DepositIndex: UintNum64, + // Registry + validators: phase0Ssz.Validators, + balances: phase0Ssz.Balances, + randaoMixes: phase0Ssz.RandaoMixes, + // Slashings + slashings: phase0Ssz.Slashings, + // Participation + previousEpochParticipation: altairSsz.EpochParticipation, + currentEpochParticipation: altairSsz.EpochParticipation, + // Finality + justificationBits: phase0Ssz.JustificationBits, + previousJustifiedCheckpoint: phase0Ssz.Checkpoint, + currentJustifiedCheckpoint: phase0Ssz.Checkpoint, + finalizedCheckpoint: phase0Ssz.Checkpoint, + // Inactivity + inactivityScores: altairSsz.InactivityScores, + // Sync + currentSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommittee: altairSsz.SyncCommittee, + // Execution + latestExecutionPayloadHeader: ExecutionPayloadHeader, // Modified in ELECTRA + // Withdrawals + nextWithdrawalIndex: capellaSsz.BeaconState.fields.nextWithdrawalIndex, + nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, + // Deep history valid from Capella onwards + historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, + depositReceiptsStartIndex: UintBn64, // New in ELECTRA }, {typeName: "BeaconState", jsonCase: "eth2"} ); export const LightClientHeader = new ContainerType( { - ...denebSsz.LightClientHeader.fields, + beacon: phase0Ssz.BeaconBlockHeader, + execution: ExecutionPayloadHeader, // Modified in ELECTRA + executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), }, {typeName: "LightClientHeader", jsonCase: "eth2"} ); export const LightClientBootstrap = new ContainerType( { - ...denebSsz.LightClientBootstrap.fields, + header: LightClientHeader, + currentSyncCommittee: altairSsz.SyncCommittee, + currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, }, {typeName: "LightClientBootstrap", jsonCase: "eth2"} ); export const LightClientUpdate = new ContainerType( { - ...denebSsz.LightClientUpdate.fields, + attestedHeader: LightClientHeader, + nextSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, }, {typeName: "LightClientUpdate", jsonCase: "eth2"} ); export const LightClientFinalityUpdate = new ContainerType( { - ...denebSsz.LightClientFinalityUpdate.fields, + attestedHeader: LightClientHeader, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, }, {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} ); export const LightClientOptimisticUpdate = new ContainerType( { - ...denebSsz.LightClientOptimisticUpdate.fields, + attestedHeader: LightClientHeader, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, }, {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} ); export const LightClientStore = new ContainerType( { - ...denebSsz.LightClientStore.fields, + snapshot: LightClientBootstrap, + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), }, {typeName: "LightClientStore", jsonCase: "eth2"} ); +// PayloadAttributes primarily for SSE event +export const PayloadAttributes = new ContainerType( + { + ...capellaSsz.PayloadAttributes.fields, + parentBeaconBlockRoot: Root, + }, + {typeName: "PayloadAttributes", jsonCase: "eth2"} +); + export const SSEPayloadAttributes = new ContainerType( { - ...denebSsz.SSEPayloadAttributes.fields, + ...bellatrixSsz.SSEPayloadAttributesCommon.fields, + payloadAttributes: PayloadAttributes, }, {typeName: "SSEPayloadAttributes", jsonCase: "eth2"} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index 198259eed1d..3286c10a033 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -1,12 +1,14 @@ import {ValueOf} from "@chainsafe/ssz"; import * as ssz from "./sszTypes.js"; -export type BlobSidecar = ValueOf; -export type ExecutionPayloadAndBlobsBundle = ValueOf; +export type DepositReceipt = ValueOf; +export type DepositReceipts = ValueOf; export type ExecutionPayload = ValueOf; export type ExecutionPayloadHeader = ValueOf; +export type ExecutionPayloadAndBlobsBundle = ValueOf; + export type BeaconBlockBody = ValueOf; export type BeaconBlock = ValueOf; export type SignedBeaconBlock = ValueOf; @@ -17,6 +19,8 @@ export type BlindedBeaconBlockBody = ValueOf; export type BlindedBeaconBlock = ValueOf; export type SignedBlindedBeaconBlock = ValueOf; +export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadHeader; + export type BuilderBid = ValueOf; export type SignedBuilderBid = ValueOf; export type SSEPayloadAttributes = ValueOf; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 55bd46771ae..78e9640e718 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -219,7 +219,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Fri, 16 Feb 2024 17:01:59 +0530 Subject: [PATCH 155/155] fix electra-interop.test.ts --- .../beacon-node/src/execution/engine/http.ts | 6 ++--- .../beacon-node/src/execution/engine/mock.ts | 4 +-- .../beacon-node/src/execution/engine/types.ts | 8 +++--- .../test/sim/electra-interop.test.ts | 27 +++++++++++-------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index 26109827b30..5108806f9d4 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -177,7 +177,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { ): Promise { const method = ForkSeq[fork] >= ForkSeq.electra - ? "engine_newPayloadV4" + ? "engine_newPayloadV6110" : ForkSeq[fork] >= ForkSeq.deneb ? "engine_newPayloadV3" : ForkSeq[fork] >= ForkSeq.capella @@ -198,7 +198,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { const serializedVersionedHashes = serializeVersionedHashes(versionedHashes); const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot); - const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV4" : "engine_newPayloadV3"; + const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV6110" : "engine_newPayloadV3"; engineRequest = { method, params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot], @@ -373,7 +373,7 @@ export class ExecutionEngineHttp implements IExecutionEngine { }> { const method = ForkSeq[fork] >= ForkSeq.electra - ? "engine_getPayloadV4" + ? "engine_getPayloadV6110" : ForkSeq[fork] >= ForkSeq.deneb ? "engine_getPayloadV3" : ForkSeq[fork] >= ForkSeq.capella diff --git a/packages/beacon-node/src/execution/engine/mock.ts b/packages/beacon-node/src/execution/engine/mock.ts index aa15a2bc953..83b63bc01c7 100644 --- a/packages/beacon-node/src/execution/engine/mock.ts +++ b/packages/beacon-node/src/execution/engine/mock.ts @@ -89,14 +89,14 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend { engine_newPayloadV1: this.notifyNewPayload.bind(this), engine_newPayloadV2: this.notifyNewPayload.bind(this), engine_newPayloadV3: this.notifyNewPayload.bind(this), - engine_newPayloadV4: this.notifyNewPayload.bind(this), + engine_newPayloadV6110: this.notifyNewPayload.bind(this), engine_forkchoiceUpdatedV1: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV2: this.notifyForkchoiceUpdate.bind(this), engine_forkchoiceUpdatedV3: this.notifyForkchoiceUpdate.bind(this), engine_getPayloadV1: this.getPayload.bind(this), engine_getPayloadV2: this.getPayload.bind(this), engine_getPayloadV3: this.getPayload.bind(this), - engine_getPayloadV4: this.getPayload.bind(this), + engine_getPayloadV6110: this.getPayload.bind(this), engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this), engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this), }; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 44d3a91eec9..ca64b20afae 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -28,7 +28,7 @@ export type EngineApiRpcParamTypes = { engine_newPayloadV1: [ExecutionPayloadRpc]; engine_newPayloadV2: [ExecutionPayloadRpc]; engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; - engine_newPayloadV4: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; + engine_newPayloadV6110: [ExecutionPayloadRpc, VersionedHashesRpc, DATA]; /** * 1. Object - Payload validity status with respect to the consensus rules: * - blockHash: DATA, 32 Bytes - block hash value of the payload @@ -52,7 +52,7 @@ export type EngineApiRpcParamTypes = { engine_getPayloadV1: [QUANTITY]; engine_getPayloadV2: [QUANTITY]; engine_getPayloadV3: [QUANTITY]; - engine_getPayloadV4: [QUANTITY]; + engine_getPayloadV6110: [QUANTITY]; /** * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure @@ -80,7 +80,7 @@ export type EngineApiRpcReturnTypes = { engine_newPayloadV1: PayloadStatus; engine_newPayloadV2: PayloadStatus; engine_newPayloadV3: PayloadStatus; - engine_newPayloadV4: PayloadStatus; + engine_newPayloadV6110: PayloadStatus; engine_forkchoiceUpdatedV1: { payloadStatus: PayloadStatus; payloadId: QUANTITY | null; @@ -99,7 +99,7 @@ export type EngineApiRpcReturnTypes = { engine_getPayloadV1: ExecutionPayloadRpc; engine_getPayloadV2: ExecutionPayloadResponse; engine_getPayloadV3: ExecutionPayloadResponse; - engine_getPayloadV4: ExecutionPayloadResponse; + engine_getPayloadV6110: ExecutionPayloadResponse; engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[]; diff --git a/packages/beacon-node/test/sim/electra-interop.test.ts b/packages/beacon-node/test/sim/electra-interop.test.ts index a7b65244e65..0005da4fea7 100644 --- a/packages/beacon-node/test/sim/electra-interop.test.ts +++ b/packages/beacon-node/test/sim/electra-interop.test.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {Context} from "mocha"; +import {describe, it, vi, afterAll, afterEach} from "vitest"; import _ from "lodash"; import {LogLevel, sleep} from "@lodestar/utils"; import {ForkName, SLOTS_PER_EPOCH, UNSET_DEPOSIT_RECEIPTS_START_INDEX} from "@lodestar/params"; @@ -27,9 +27,9 @@ import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; // NOTE: How to run -// DEV_RUN=true EL_BINARY_DIR=naviechan/besu:v6110 EL_SCRIPT_DIR=besudocker yarn mocha test/sim/electra-interop.test.ts +// DEV_RUN=true EL_BINARY_DIR=naviechan/besu:v6110 EL_SCRIPT_DIR=besudocker yarn vitest --run test/sim/electra-interop.test.ts // or -// DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn mocha test/sim/electra-interop.test.ts +// DEV_RUN=true EL_BINARY_DIR=/Volumes/fast_boi/navie/Documents/workspace/besu/build/install/besu/bin EL_SCRIPT_DIR=besu yarn vitest --run test/sim/electra-interop.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention */ @@ -43,7 +43,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` ); } - this.timeout("10min"); + vi.setConfig({testTimeout: 1000 * 60 * 10, hookTimeout: 1000 * 60 * 10}); const dataPath = fs.mkdtempSync("lodestar-test-electra"); const elSetupConfig = { @@ -58,7 +58,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; const controller = new AbortController(); - after(async () => { + afterAll(async () => { controller?.abort(); await shell(`sudo rm -rf ${dataPath}`); }); @@ -242,7 +242,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); afterEachCallbacks.push(() => tearDownCallBack()); - await runNodeWithEL.bind(this)({ + await runNodeWithEL({ elClient, electraEpoch: 0, testName: "post-merge", @@ -254,10 +254,15 @@ describe("executionEngine / ExecutionEngineHttp", function () { * 1) Send two raw deposit transactions, and see if two new validators with corrent balances show up in the state.validators and unfinalized cache * 2) Upon state-transition, see if the two new validators move from unfinalized cache to finalized cache */ - async function runNodeWithEL( - this: Context, - {elClient, electraEpoch, testName}: {elClient: ELClient; electraEpoch: Epoch; testName: string} - ): Promise { + async function runNodeWithEL({ + elClient, + electraEpoch, + testName, + }: { + elClient: ELClient; + electraEpoch: Epoch; + testName: string; + }): Promise { const {genesisBlockHash, ttd, engineRpcUrl, ethRpcUrl} = elClient; const validatorClientCount = 1; const validatorsPerClient = 32; @@ -280,7 +285,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { testParams.SECONDS_PER_SLOT * 1000; - this.timeout(timeout + 2 * timeoutSetupMargin); + vi.setConfig({testTimeout: timeout + 2 * timeoutSetupMargin}); const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT;