Skip to content

Commit b429528

Browse files
authored
chore: refactor withdrawal logic (#7714)
1 parent dce8b39 commit b429528

File tree

1 file changed

+15
-18
lines changed

1 file changed

+15
-18
lines changed

packages/state-transition/src/block/processWithdrawals.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from "@lodestar/params";
1111
import {ValidatorIndex, capella, ssz} from "@lodestar/types";
1212

13-
import {toRootHex} from "@lodestar/utils";
13+
import {MapDef, toRootHex} from "@lodestar/utils";
1414
import {CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js";
1515
import {
1616
decreaseBalance,
@@ -98,6 +98,7 @@ export function getExpectedWithdrawals(
9898
const {validators, balances, nextWithdrawalValidatorIndex} = state;
9999

100100
const withdrawals: capella.Withdrawal[] = [];
101+
const withdrawnBalances = new MapDef<ValidatorIndex, number>(() => 0);
101102
const isPostElectra = fork >= ForkSeq.electra;
102103
// partialWithdrawalsCount is withdrawals coming from EL since electra (EIP-7002)
103104
let processedPartialWithdrawalsCount = 0;
@@ -123,15 +124,15 @@ export function getExpectedWithdrawals(
123124
}
124125

125126
const validator = validators.getReadonly(withdrawal.validatorIndex);
127+
const totalWithdrawn = withdrawnBalances.getOrDefault(withdrawal.validatorIndex);
128+
const balance = state.balances.get(withdrawal.validatorIndex) - totalWithdrawn;
126129

127130
if (
128131
validator.exitEpoch === FAR_FUTURE_EPOCH &&
129132
validator.effectiveBalance >= MIN_ACTIVATION_BALANCE &&
130-
balances.get(withdrawal.validatorIndex) > MIN_ACTIVATION_BALANCE
133+
balance > MIN_ACTIVATION_BALANCE
131134
) {
132-
const balanceOverMinActivationBalance = BigInt(
133-
balances.get(withdrawal.validatorIndex) - MIN_ACTIVATION_BALANCE
134-
);
135+
const balanceOverMinActivationBalance = BigInt(balance - MIN_ACTIVATION_BALANCE);
135136
const withdrawableBalance =
136137
balanceOverMinActivationBalance < withdrawal.amount ? balanceOverMinActivationBalance : withdrawal.amount;
137138
withdrawals.push({
@@ -141,6 +142,7 @@ export function getExpectedWithdrawals(
141142
amount: withdrawableBalance,
142143
});
143144
withdrawalIndex++;
145+
withdrawnBalances.set(withdrawal.validatorIndex, totalWithdrawn + Number(withdrawableBalance));
144146
}
145147
processedPartialWithdrawalsCount++;
146148
}
@@ -155,14 +157,16 @@ export function getExpectedWithdrawals(
155157
const validatorIndex = (nextWithdrawalValidatorIndex + n) % validators.length;
156158

157159
const validator = validators.getReadonly(validatorIndex);
160+
const withdrawnBalance = withdrawnBalances.getOrDefault(validatorIndex);
158161
const balance = isPostElectra
159-
? balances.get(validatorIndex) - getPartiallyWithdrawnBalance(withdrawals, validatorIndex)
162+
? // Deduct partially withdrawn balance already queued above
163+
balances.get(validatorIndex) - withdrawnBalance
160164
: balances.get(validatorIndex);
161165
const {withdrawableEpoch, withdrawalCredentials, effectiveBalance} = validator;
162166
const hasWithdrawableCredentials = isPostElectra
163167
? hasExecutionWithdrawalCredential(withdrawalCredentials)
164168
: hasEth1WithdrawalCredential(withdrawalCredentials);
165-
// early skip for balance = 0 as its now more likely that validator has exited/slahed with
169+
// early skip for balance = 0 as its now more likely that validator has exited/slashed with
166170
// balance zero than not have withdrawal credentials set
167171
if (balance === 0 || !hasWithdrawableCredentials) {
168172
continue;
@@ -177,18 +181,21 @@ export function getExpectedWithdrawals(
177181
amount: BigInt(balance),
178182
});
179183
withdrawalIndex++;
184+
withdrawnBalances.set(validatorIndex, withdrawnBalance + balance);
180185
} else if (
181186
effectiveBalance === (isPostElectra ? getMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE) &&
182187
balance > effectiveBalance
183188
) {
184189
// capella partial withdrawal
190+
const partialAmount = balance - effectiveBalance;
185191
withdrawals.push({
186192
index: withdrawalIndex,
187193
validatorIndex,
188194
address: validator.withdrawalCredentials.subarray(12),
189-
amount: BigInt(balance - effectiveBalance),
195+
amount: BigInt(partialAmount),
190196
});
191197
withdrawalIndex++;
198+
withdrawnBalances.set(validatorIndex, withdrawnBalance + partialAmount);
192199
}
193200

194201
// Break if we have enough to pack the block
@@ -199,13 +206,3 @@ export function getExpectedWithdrawals(
199206

200207
return {withdrawals, sampledValidators: n, processedPartialWithdrawalsCount};
201208
}
202-
203-
function getPartiallyWithdrawnBalance(withdrawals: capella.Withdrawal[], validatorIndex: ValidatorIndex): number {
204-
let total = BigInt(0);
205-
for (const withdrawal of withdrawals) {
206-
if (withdrawal.validatorIndex === validatorIndex) {
207-
total += withdrawal.amount;
208-
}
209-
}
210-
return Number(total);
211-
}

0 commit comments

Comments
 (0)