@@ -49,56 +49,59 @@ func (b *BeaconState) NextWithdrawalValidatorIndex() (primitives.ValidatorIndex,
4949// Spec definition:
5050//
5151// def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64]:
52- // epoch = get_current_epoch(state)
53- // withdrawal_index = state.next_withdrawal_index
54- // validator_index = state.next_withdrawal_validator_index
55- // withdrawals: List[Withdrawal] = []
52+ // epoch = get_current_epoch(state)
53+ // withdrawal_index = state.next_withdrawal_index
54+ // validator_index = state.next_withdrawal_validator_index
55+ // withdrawals: List[Withdrawal] = []
56+ // processed_partial_withdrawals_count = 0
5657//
57- // # [New in Electra:EIP7251] Consume pending partial withdrawals
58- // for withdrawal in state.pending_partial_withdrawals:
59- // if withdrawal.withdrawable_epoch > epoch or len(withdrawals) == MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP:
60- // break
58+ // # [New in Electra:EIP7251] Consume pending partial withdrawals
59+ // for withdrawal in state.pending_partial_withdrawals:
60+ // if withdrawal.withdrawable_epoch > epoch or len(withdrawals) == MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP:
61+ // break
6162//
62- // validator = state.validators[withdrawal.index]
63- // has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
64- // has_excess_balance = state.balances[withdrawal.index] > MIN_ACTIVATION_BALANCE
65- // if validator.exit_epoch == FAR_FUTURE_EPOCH and has_sufficient_effective_balance and has_excess_balance:
66- // withdrawable_balance = min(state.balances[withdrawal.index] - MIN_ACTIVATION_BALANCE, withdrawal.amount)
67- // withdrawals.append(Withdrawal(
68- // index=withdrawal_index,
69- // validator_index=withdrawal.index,
70- // address=ExecutionAddress(validator.withdrawal_credentials[12:]),
71- // amount=withdrawable_balance,
72- // ))
73- // withdrawal_index += WithdrawalIndex(1)
63+ // validator = state.validators[withdrawal.index]
64+ // has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
65+ // has_excess_balance = state.balances[withdrawal.index] > MIN_ACTIVATION_BALANCE
66+ // if validator.exit_epoch == FAR_FUTURE_EPOCH and has_sufficient_effective_balance and has_excess_balance:
67+ // withdrawable_balance = min(state.balances[withdrawal.index] - MIN_ACTIVATION_BALANCE, withdrawal.amount)
68+ // withdrawals.append(Withdrawal(
69+ // index=withdrawal_index,
70+ // validator_index=withdrawal.index,
71+ // address=ExecutionAddress(validator.withdrawal_credentials[12:]),
72+ // amount=withdrawable_balance,
73+ // ))
74+ // withdrawal_index += WithdrawalIndex(1)
7475//
75- // partial_withdrawals_count = len(withdrawals)
76+ // processed_partial_withdrawals_count += 1
7677//
77- // # Sweep for remaining.
78- // bound = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)
79- // for _ in range(bound):
80- // validator = state.validators[validator_index]
81- // balance = state.balances[validator_index]
82- // if is_fully_withdrawable_validator(validator, balance, epoch):
83- // withdrawals.append(Withdrawal(
84- // index=withdrawal_index,
85- // validator_index=validator_index,
86- // address=ExecutionAddress(validator.withdrawal_credentials[12:]),
87- // amount=balance,
88- // ))
89- // withdrawal_index += WithdrawalIndex(1)
90- // elif is_partially_withdrawable_validator(validator, balance):
91- // withdrawals.append(Withdrawal(
92- // index=withdrawal_index,
93- // validator_index=validator_index,
94- // address=ExecutionAddress(validator.withdrawal_credentials[12:]),
95- // amount=balance - get_validator_max_effective_balance(validator), # [Modified in Electra:EIP7251]
96- // ))
97- // withdrawal_index += WithdrawalIndex(1)
98- // if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
99- // break
100- // validator_index = ValidatorIndex((validator_index + 1) % len(state.validators))
101- // return withdrawals, partial_withdrawals_count
78+ // # Sweep for remaining.
79+ // bound = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)
80+ // for _ in range(bound):
81+ // validator = state.validators[validator_index]
82+ // # [Modified in Electra:EIP7251]
83+ // partially_withdrawn_balance = sum(withdrawal.amount for withdrawal in withdrawals if withdrawal.validator_index == validator_index)
84+ // balance = state.balances[validator_index] - partially_withdrawn_balance
85+ // if is_fully_withdrawable_validator(validator, balance, epoch):
86+ // withdrawals.append(Withdrawal(
87+ // index=withdrawal_index,
88+ // validator_index=validator_index,
89+ // address=ExecutionAddress(validator.withdrawal_credentials[12:]),
90+ // amount=balance,
91+ // ))
92+ // withdrawal_index += WithdrawalIndex(1)
93+ // elif is_partially_withdrawable_validator(validator, balance):
94+ // withdrawals.append(Withdrawal(
95+ // index=withdrawal_index,
96+ // validator_index=validator_index,
97+ // address=ExecutionAddress(validator.withdrawal_credentials[12:]),
98+ // amount=balance - get_validator_max_effective_balance(validator), # [Modified in Electra:EIP7251]
99+ // ))
100+ // withdrawal_index += WithdrawalIndex(1)
101+ // if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
102+ // break
103+ // validator_index = ValidatorIndex((validator_index + 1) % len(state.validators))
104+ // return withdrawals, processed_partial_withdrawals_count
102105func (b * BeaconState ) ExpectedWithdrawals () ([]* enginev1.Withdrawal , uint64 , error ) {
103106 if b .version < version .Capella {
104107 return nil , 0 , errNotSupported ("ExpectedWithdrawals" , b .version )
@@ -113,7 +116,7 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
113116 epoch := slots .ToEpoch (b .slot )
114117
115118 // Electra partial withdrawals functionality.
116- var partialWithdrawalsCount uint64
119+ var processedPartialWithdrawalsCount uint64
117120 if b .version >= version .Electra {
118121 for _ , w := range b .pendingPartialWithdrawals {
119122 if w .WithdrawableEpoch > epoch || len (withdrawals ) >= int (params .BeaconConfig ().MaxPendingPartialsPerWithdrawalsSweep ) {
@@ -140,7 +143,7 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
140143 })
141144 withdrawalIndex ++
142145 }
143- partialWithdrawalsCount ++
146+ processedPartialWithdrawalsCount ++
144147 }
145148 }
146149
@@ -155,6 +158,15 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
155158 if err != nil {
156159 return nil , 0 , errors .Wrapf (err , "could not retrieve balance at index %d" , validatorIndex )
157160 }
161+ if b .version >= version .Electra {
162+ var partiallyWithdrawnBalance uint64
163+ for _ , w := range withdrawals {
164+ if w .ValidatorIndex == validatorIndex {
165+ partiallyWithdrawnBalance += w .Amount
166+ }
167+ }
168+ balance = balance - partiallyWithdrawnBalance
169+ }
158170 if helpers .IsFullyWithdrawableValidator (val , balance , epoch , b .version ) {
159171 withdrawals = append (withdrawals , & enginev1.Withdrawal {
160172 Index : withdrawalIndex ,
@@ -181,7 +193,7 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
181193 }
182194 }
183195
184- return withdrawals , partialWithdrawalsCount , nil
196+ return withdrawals , processedPartialWithdrawalsCount , nil
185197}
186198
187199func (b * BeaconState ) PendingPartialWithdrawals () ([]* ethpb.PendingPartialWithdrawal , error ) {
0 commit comments