diff --git a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts index 26180d0d9f3..1fe5c92eea1 100644 --- a/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts +++ b/packages/state-transition/src/epoch/processEffectiveBalanceUpdates.ts @@ -5,12 +5,10 @@ import { HYSTERESIS_QUOTIENT, HYSTERESIS_UPWARD_MULTIPLIER, MAX_EFFECTIVE_BALANCE, - MAX_EFFECTIVE_BALANCE_ELECTRA, - MIN_ACTIVATION_BALANCE, TIMELY_TARGET_FLAG_INDEX, } from "@lodestar/params"; import {EpochTransitionCache, CachedBeaconStateAllForks, BeaconStateAltair} from "../types.js"; -import {hasCompoundingWithdrawalCredential} from "../util/electra.js"; +import {getMaxEffectiveBalance} from "../util/validator.js"; /** Same to https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.5/specs/altair/beacon-chain.md#has_flag */ const TIMELY_TARGET = 1 << TIMELY_TARGET_FLAG_INDEX; @@ -46,7 +44,6 @@ export function processEffectiveBalanceUpdates( // so it's recycled here for performance. const balances = cache.balances ?? state.balances.getAll(); const currentEpochValidators = cache.validators; - const newCompoundingValidators = cache.newCompoundingValidators ?? new Set(); let numUpdate = 0; for (let i = 0, len = balances.length; i < len; i++) { @@ -61,10 +58,7 @@ export function processEffectiveBalanceUpdates( effectiveBalanceLimit = MAX_EFFECTIVE_BALANCE; } else { // from electra, effectiveBalanceLimit is per validator - const isCompoundingValidator = - hasCompoundingWithdrawalCredential(currentEpochValidators[i].withdrawalCredentials) || - newCompoundingValidators.has(i); - effectiveBalanceLimit = isCompoundingValidator ? MAX_EFFECTIVE_BALANCE_ELECTRA : MIN_ACTIVATION_BALANCE; + effectiveBalanceLimit = getMaxEffectiveBalance(currentEpochValidators[i].withdrawalCredentials); } if ( diff --git a/packages/state-transition/src/epoch/processPendingConsolidations.ts b/packages/state-transition/src/epoch/processPendingConsolidations.ts index 28178a509bb..e0058ca6789 100644 --- a/packages/state-transition/src/epoch/processPendingConsolidations.ts +++ b/packages/state-transition/src/epoch/processPendingConsolidations.ts @@ -1,7 +1,7 @@ import {ValidatorIndex} from "@lodestar/types"; import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js"; import {decreaseBalance, increaseBalance} from "../util/balance.js"; -import {getActiveBalance} from "../util/validator.js"; +import {getMaxEffectiveBalance} from "../util/validator.js"; import {switchToCompoundingValidator} from "../util/electra.js"; /** @@ -40,12 +40,13 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra, ca switchToCompoundingValidator(state, targetIndex); newCompoundingValidators.add(targetIndex); // Move active balance to target. Excess balance is withdrawable. - const activeBalance = getActiveBalance(state, sourceIndex); - decreaseBalance(state, sourceIndex, activeBalance); - increaseBalance(state, targetIndex, activeBalance); + const maxEffectiveBalance = getMaxEffectiveBalance(state.validators.getReadonly(sourceIndex).withdrawalCredentials); + const sourceEffectiveBalance = Math.min(state.balances.get(sourceIndex), maxEffectiveBalance); + decreaseBalance(state, sourceIndex, sourceEffectiveBalance); + increaseBalance(state, targetIndex, sourceEffectiveBalance); if (cachedBalances) { - cachedBalances[sourceIndex] -= activeBalance; - cachedBalances[targetIndex] += activeBalance; + cachedBalances[sourceIndex] -= sourceEffectiveBalance; + cachedBalances[targetIndex] += sourceEffectiveBalance; } nextPendingConsolidation++; diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts index b64ac242f83..98e9fbd52ce 100644 --- a/packages/state-transition/src/slot/upgradeStateToElectra.ts +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -1,14 +1,11 @@ import {Epoch, ValidatorIndex, ssz} from "@lodestar/types"; -import {FAR_FUTURE_EPOCH, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; +import {FAR_FUTURE_EPOCH, GENESIS_SLOT, UNSET_DEPOSIT_REQUESTS_START_INDEX} from "@lodestar/params"; import {CachedBeaconStateDeneb} from "../types.js"; import {CachedBeaconStateElectra, getCachedBeaconState} from "../cache/stateCache.js"; -import { - hasCompoundingWithdrawalCredential, - queueEntireBalanceAndResetValidator, - queueExcessActiveBalance, -} from "../util/electra.js"; +import {hasCompoundingWithdrawalCredential, queueExcessActiveBalance} from "../util/electra.js"; import {computeActivationExitEpoch} from "../util/epoch.js"; import {getActivationExitChurnLimit, getConsolidationChurnLimit} from "../util/validator.js"; +import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; /** * Upgrade a state from Deneb to Electra. @@ -93,7 +90,23 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache }); for (const validatorIndex of preActivation) { - queueEntireBalanceAndResetValidator(stateElectraView as CachedBeaconStateElectra, validatorIndex); + const stateElectra = stateElectraView as CachedBeaconStateElectra; + const balance = stateElectra.balances.get(validatorIndex); + stateElectra.balances.set(validatorIndex, 0); + + const validator = stateElectra.validators.get(validatorIndex); + validator.effectiveBalance = 0; + stateElectra.epochCtx.effectiveBalanceIncrementsSet(validatorIndex, 0); + validator.activationEligibilityEpoch = FAR_FUTURE_EPOCH; + + const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ + pubkey: validator.pubkey, + withdrawalCredentials: validator.withdrawalCredentials, + amount: balance, + signature: new Uint8Array(G2_POINT_AT_INFINITY), + slot: GENESIS_SLOT, + }); + stateElectra.pendingDeposits.push(pendingDeposit); } for (let i = 0; i < validatorsArr.length; i++) { @@ -114,45 +127,3 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache return stateElectra; } - -export function upgradeStateToElectraOriginal(stateDeneb: CachedBeaconStateDeneb): CachedBeaconStateElectra { - const {config} = stateDeneb; - - const stateElectraNode = ssz.deneb.BeaconState.commitViewDU(stateDeneb); - const stateElectraView = ssz.electra.BeaconState.getViewDU(stateElectraNode); - - const stateElectra = getCachedBeaconState(stateElectraView, stateDeneb); - - stateElectra.fork = ssz.phase0.Fork.toViewDU({ - previousVersion: stateDeneb.fork.currentVersion, - currentVersion: config.ELECTRA_FORK_VERSION, - epoch: stateDeneb.epochCtx.epoch, - }); - - // default value of depositRequestsStartIndex is UNSET_DEPOSIT_REQUESTS_START_INDEX - stateElectra.depositRequestsStartIndex = UNSET_DEPOSIT_REQUESTS_START_INDEX; - - const validatorsArr = stateElectra.validators.getAllReadonly(); - - for (let i = 0; i < validatorsArr.length; i++) { - const validator = validatorsArr[i]; - - // [EIP-7251]: add validators that are not yet active to pending balance deposits - if (validator.activationEligibilityEpoch === FAR_FUTURE_EPOCH) { - queueEntireBalanceAndResetValidator(stateElectra, i); - } - - // [EIP-7251]: Ensure early adopters of compounding credentials go through the activation churn - const withdrawalCredential = validator.withdrawalCredentials; - if (hasCompoundingWithdrawalCredential(withdrawalCredential)) { - queueExcessActiveBalance(stateElectra, i); - } - } - - // Commit new added fields ViewDU to the root node - stateElectra.commit(); - // Clear cache to ensure the cache of deneb fields is not used by new ELECTRA fields - stateElectra["clearCache"](); - - return stateElectra; -} diff --git a/packages/state-transition/src/util/electra.ts b/packages/state-transition/src/util/electra.ts index 90dd9a3881d..cd5f47e2c78 100644 --- a/packages/state-transition/src/util/electra.ts +++ b/packages/state-transition/src/util/electra.ts @@ -1,4 +1,4 @@ -import {COMPOUNDING_WITHDRAWAL_PREFIX, FAR_FUTURE_EPOCH, GENESIS_SLOT, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; +import {COMPOUNDING_WITHDRAWAL_PREFIX, GENESIS_SLOT, MIN_ACTIVATION_BALANCE} from "@lodestar/params"; import {ValidatorIndex, ssz} from "@lodestar/types"; import {CachedBeaconStateElectra} from "../types.js"; import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; @@ -47,22 +47,3 @@ export function queueExcessActiveBalance(state: CachedBeaconStateElectra, index: state.pendingDeposits.push(pendingDeposit); } } - -export function queueEntireBalanceAndResetValidator(state: CachedBeaconStateElectra, index: ValidatorIndex): void { - const balance = state.balances.get(index); - state.balances.set(index, 0); - - const validator = state.validators.get(index); - validator.effectiveBalance = 0; - state.epochCtx.effectiveBalanceIncrementsSet(index, 0); - validator.activationEligibilityEpoch = FAR_FUTURE_EPOCH; - - const pendingDeposit = ssz.electra.PendingDeposit.toViewDU({ - pubkey: validator.pubkey, - withdrawalCredentials: validator.withdrawalCredentials, - amount: balance, - signature: G2_POINT_AT_INFINITY, - slot: GENESIS_SLOT, - }); - state.pendingDeposits.push(pendingDeposit); -} diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index ebad21d9d25..083b1ce1a57 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -84,14 +84,6 @@ export function getMaxEffectiveBalance(withdrawalCredentials: Uint8Array): numbe } } -export function getActiveBalance(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { - const validatorMaxEffectiveBalance = getMaxEffectiveBalance( - state.validators.getReadonly(validatorIndex).withdrawalCredentials - ); - - return Math.min(state.balances.get(validatorIndex), validatorMaxEffectiveBalance); -} - export function getPendingBalanceToWithdraw(state: CachedBeaconStateElectra, validatorIndex: ValidatorIndex): number { return state.pendingPartialWithdrawals .getAllReadonly()