diff --git a/packages/state-transition/src/block/processConsolidation.ts b/packages/state-transition/src/block/processConsolidation.ts index 3231ee585df..cacc6d0e08d 100644 --- a/packages/state-transition/src/block/processConsolidation.ts +++ b/packages/state-transition/src/block/processConsolidation.ts @@ -4,7 +4,7 @@ import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} import {verifyConsolidationSignature} from "../signatureSets/index.js"; import {CachedBeaconStateElectra} from "../types.js"; -import {getActiveBalance, getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; +import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; import {hasExecutionWithdrawalCredential} from "../util/electra.js"; import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; diff --git a/packages/state-transition/src/block/processExecutionLayerWithdrawRequest.ts b/packages/state-transition/src/block/processExecutionLayerWithdrawRequest.ts index 75faceadac8..5e466a35a97 100644 --- a/packages/state-transition/src/block/processExecutionLayerWithdrawRequest.ts +++ b/packages/state-transition/src/block/processExecutionLayerWithdrawRequest.ts @@ -1,6 +1,11 @@ import {toHexString} from "@chainsafe/ssz"; import {electra, phase0, ssz} from "@lodestar/types"; -import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_PARTIAL_WITHDRAWALS_LIMIT, FULL_EXIT_REQUEST_AMOUNT} from "@lodestar/params"; +import { + FAR_FUTURE_EPOCH, + MIN_ACTIVATION_BALANCE, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + FULL_EXIT_REQUEST_AMOUNT, +} from "@lodestar/params"; import {CachedBeaconStateElectra} from "../types.js"; import {hasCompoundingWithdrawalCredential, hasExecutionWithdrawalCredential} from "../util/electra.js"; @@ -51,14 +56,20 @@ export function processExecutionLayerWithdrawRequest( // TODO Electra: add log here } return; - } + } const hasSufficientEffectiveBalance = validator.effectiveBalance >= MIN_ACTIVATION_BALANCE; const hasExcessBalance = validatorBalance > MIN_ACTIVATION_BALANCE + pendingBalanceToWithdraw; // Only allow partial withdrawals with compounding withdrawal credentials - if (hasCompoundingWithdrawalCredential(validator.withdrawalCredentials) && hasSufficientEffectiveBalance && hasExcessBalance) { - const amountToWithdraw = BigInt(Math.min(validatorBalance - MIN_ACTIVATION_BALANCE - pendingBalanceToWithdraw, amount)); + if ( + hasCompoundingWithdrawalCredential(validator.withdrawalCredentials) && + hasSufficientEffectiveBalance && + hasExcessBalance + ) { + const amountToWithdraw = BigInt( + Math.min(validatorBalance - MIN_ACTIVATION_BALANCE - pendingBalanceToWithdraw, amount) + ); const exitQueueEpoch = computeExitEpochAndUpdateChurn(state, amountToWithdraw); const withdrawableEpoch = exitQueueEpoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY; @@ -68,7 +79,7 @@ export function processExecutionLayerWithdrawRequest( withdrawableEpoch, }); state.pendingPartialWithdrawals.push(pendingPartialWithdrawal); - } + } } function isValidValidator( diff --git a/packages/state-transition/src/block/processVoluntaryExit.ts b/packages/state-transition/src/block/processVoluntaryExit.ts index ceea27cb33e..d1e5947ae40 100644 --- a/packages/state-transition/src/block/processVoluntaryExit.ts +++ b/packages/state-transition/src/block/processVoluntaryExit.ts @@ -16,7 +16,12 @@ export function processVoluntaryExit( signedVoluntaryExit: phase0.SignedVoluntaryExit, verifySignature = true ): void { - if (!isValidVoluntaryExit(fork, state, signedVoluntaryExit, verifySignature)) { + const isAfterElectra = fork >= ForkSeq.electra; + if ( + (!isAfterElectra && !isValidVoluntaryExit(state, signedVoluntaryExit, verifySignature)) || + (isAfterElectra && + !isValidVoluntaryExitElectra(state as CachedBeaconStateElectra, signedVoluntaryExit, verifySignature)) + ) { throw Error("Invalid voluntary exit"); } @@ -25,7 +30,6 @@ export function processVoluntaryExit( } export function isValidVoluntaryExit( - fork: ForkSeq, state: CachedBeaconStateAllForks, signedVoluntaryExit: phase0.SignedVoluntaryExit, verifySignature = true @@ -34,7 +38,6 @@ export function isValidVoluntaryExit( const voluntaryExit = signedVoluntaryExit.message; const validator = state.validators.get(voluntaryExit.validatorIndex); const currentEpoch = epochCtx.epoch; - const isAfterElectra = fork >= ForkSeq.electra; return ( // verify the validator is active @@ -45,9 +48,18 @@ export function isValidVoluntaryExit( currentEpoch >= voluntaryExit.epoch && // verify the validator had been active long enough currentEpoch >= validator.activationEpoch + config.SHARD_COMMITTEE_PERIOD && - // only exit validator if it has no pending withdrawals in the queue (post-Electra only) - isAfterElectra ? getPendingBalanceToWithdraw(state as CachedBeaconStateElectra, voluntaryExit.validatorIndex) === 0 : true && // verify signature (!verifySignature || verifyVoluntaryExitSignature(state, signedVoluntaryExit)) ); } + +function isValidVoluntaryExitElectra( + state: CachedBeaconStateElectra, + signedVoluntaryExit: phase0.SignedVoluntaryExit, + verifySignature = true +): boolean { + const isValidPreElectra = isValidVoluntaryExit(state, signedVoluntaryExit, verifySignature); + + // only exit validator if it has no pending withdrawals in the queue (post-Electra only) + return isValidPreElectra && getPendingBalanceToWithdraw(state, signedVoluntaryExit.message.validatorIndex) === 0; +} diff --git a/packages/state-transition/src/block/processWithdrawals.ts b/packages/state-transition/src/block/processWithdrawals.ts index 77d968b7acb..634b3fc4571 100644 --- a/packages/state-transition/src/block/processWithdrawals.ts +++ b/packages/state-transition/src/block/processWithdrawals.ts @@ -105,7 +105,11 @@ export function getExpectedWithdrawals( const validator = validators.getReadonly(withdrawal.index); - if (validator.exitEpoch === FAR_FUTURE_EPOCH && validator.effectiveBalance >= MIN_ACTIVATION_BALANCE && balances.get(withdrawalIndex) > MIN_ACTIVATION_BALANCE) { + if ( + validator.exitEpoch === FAR_FUTURE_EPOCH && + validator.effectiveBalance >= MIN_ACTIVATION_BALANCE && + balances.get(withdrawalIndex) > MIN_ACTIVATION_BALANCE + ) { const balanceOverMinActivationBalance = BigInt(balances.get(withdrawalIndex) - MIN_ACTIVATION_BALANCE); const withdrawableBalance = balanceOverMinActivationBalance < withdrawal.amount ? balanceOverMinActivationBalance : withdrawal.amount; diff --git a/packages/state-transition/src/util/validator.ts b/packages/state-transition/src/util/validator.ts index ba87f0d04dd..e95a13bf5d4 100644 --- a/packages/state-transition/src/util/validator.ts +++ b/packages/state-transition/src/util/validator.ts @@ -97,4 +97,4 @@ export function getPendingBalanceToWithdraw(state: CachedBeaconStateElectra, val .getAllReadonly() .filter((item) => item.index === validatorIndex) .reduce((total, item) => total + Number(item.amount), 0); -} \ No newline at end of file +}