@@ -10,7 +10,7 @@ import {
1010} from "@lodestar/params" ;
1111import { ValidatorIndex , capella , ssz } from "@lodestar/types" ;
1212
13- import { toRootHex } from "@lodestar/utils" ;
13+ import { MapDef , toRootHex } from "@lodestar/utils" ;
1414import { CachedBeaconStateCapella , CachedBeaconStateElectra } from "../types.js" ;
1515import {
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