mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
Compare commits
1 Commits
3e7cd8c2f1
...
v6.0.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96e7ef8767 |
@@ -48,60 +48,62 @@ func (b *BeaconState) NextWithdrawalValidatorIndex() (primitives.ValidatorIndex,
|
||||
//
|
||||
// Spec definition:
|
||||
//
|
||||
// def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64]:
|
||||
// epoch = get_current_epoch(state)
|
||||
// withdrawal_index = state.next_withdrawal_index
|
||||
// validator_index = state.next_withdrawal_validator_index
|
||||
// withdrawals: List[Withdrawal] = []
|
||||
// processed_partial_withdrawals_count = 0
|
||||
// def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64]:
|
||||
// epoch = get_current_epoch(state)
|
||||
// withdrawal_index = state.next_withdrawal_index
|
||||
// validator_index = state.next_withdrawal_validator_index
|
||||
// withdrawals: List[Withdrawal] = []
|
||||
// processed_partial_withdrawals_count = 0
|
||||
//
|
||||
// # [New in Electra:EIP7251] Consume pending partial withdrawals
|
||||
// for withdrawal in state.pending_partial_withdrawals:
|
||||
// if withdrawal.withdrawable_epoch > epoch or len(withdrawals) == MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP:
|
||||
// break
|
||||
// # [New in Electra:EIP7251] Consume pending partial withdrawals
|
||||
// for withdrawal in state.pending_partial_withdrawals:
|
||||
// if withdrawal.withdrawable_epoch > epoch or len(withdrawals) == MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP:
|
||||
// break
|
||||
//
|
||||
// validator = state.validators[withdrawal.index]
|
||||
// has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
|
||||
// has_excess_balance = state.balances[withdrawal.index] > MIN_ACTIVATION_BALANCE
|
||||
// if validator.exit_epoch == FAR_FUTURE_EPOCH and has_sufficient_effective_balance and has_excess_balance:
|
||||
// withdrawable_balance = min(state.balances[withdrawal.index] - MIN_ACTIVATION_BALANCE, withdrawal.amount)
|
||||
// withdrawals.append(Withdrawal(
|
||||
// index=withdrawal_index,
|
||||
// validator_index=withdrawal.index,
|
||||
// address=ExecutionAddress(validator.withdrawal_credentials[12:]),
|
||||
// amount=withdrawable_balance,
|
||||
// ))
|
||||
// withdrawal_index += WithdrawalIndex(1)
|
||||
// validator = state.validators[withdrawal.index]
|
||||
// has_sufficient_effective_balance = validator.effective_balance >= MIN_ACTIVATION_BALANCE
|
||||
// total_withdrawn = sum(w.amount for w in withdrawals if w.validator_index == withdrawal.validator_index)
|
||||
// balance = state.balances[withdrawal.validator_index] - total_withdrawn
|
||||
// has_excess_balance = balance > MIN_ACTIVATION_BALANCE
|
||||
// if validator.exit_epoch == FAR_FUTURE_EPOCH and has_sufficient_effective_balance and has_excess_balance:
|
||||
// withdrawable_balance = min(balance - MIN_ACTIVATION_BALANCE, withdrawal.amount)
|
||||
// withdrawals.append(Withdrawal(
|
||||
// index=withdrawal_index,
|
||||
// validator_index=withdrawal.index,
|
||||
// address=ExecutionAddress(validator.withdrawal_credentials[12:]),
|
||||
// amount=withdrawable_balance,
|
||||
// ))
|
||||
// withdrawal_index += WithdrawalIndex(1)
|
||||
//
|
||||
// processed_partial_withdrawals_count += 1
|
||||
// processed_partial_withdrawals_count += 1
|
||||
//
|
||||
// # Sweep for remaining.
|
||||
// bound = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)
|
||||
// for _ in range(bound):
|
||||
// validator = state.validators[validator_index]
|
||||
// # [Modified in Electra:EIP7251]
|
||||
// partially_withdrawn_balance = sum(withdrawal.amount for withdrawal in withdrawals if withdrawal.validator_index == validator_index)
|
||||
// balance = state.balances[validator_index] - partially_withdrawn_balance
|
||||
// if is_fully_withdrawable_validator(validator, balance, epoch):
|
||||
// withdrawals.append(Withdrawal(
|
||||
// index=withdrawal_index,
|
||||
// validator_index=validator_index,
|
||||
// address=ExecutionAddress(validator.withdrawal_credentials[12:]),
|
||||
// amount=balance,
|
||||
// ))
|
||||
// withdrawal_index += WithdrawalIndex(1)
|
||||
// elif is_partially_withdrawable_validator(validator, balance):
|
||||
// withdrawals.append(Withdrawal(
|
||||
// index=withdrawal_index,
|
||||
// validator_index=validator_index,
|
||||
// address=ExecutionAddress(validator.withdrawal_credentials[12:]),
|
||||
// amount=balance - get_max_effective_balance(validator), # [Modified in Electra:EIP7251]
|
||||
// ))
|
||||
// withdrawal_index += WithdrawalIndex(1)
|
||||
// if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
|
||||
// break
|
||||
// validator_index = ValidatorIndex((validator_index + 1) % len(state.validators))
|
||||
// return withdrawals, processed_partial_withdrawals_count
|
||||
// # Sweep for remaining.
|
||||
// bound = min(len(state.validators), MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP)
|
||||
// for _ in range(bound):
|
||||
// validator = state.validators[validator_index]
|
||||
// # [Modified in Electra:EIP7251]
|
||||
// partially_withdrawn_balance = sum(withdrawal.amount for withdrawal in withdrawals if withdrawal.validator_index == validator_index)
|
||||
// balance = state.balances[validator_index] - partially_withdrawn_balance
|
||||
// if is_fully_withdrawable_validator(validator, balance, epoch):
|
||||
// withdrawals.append(Withdrawal(
|
||||
// index=withdrawal_index,
|
||||
// validator_index=validator_index,
|
||||
// address=ExecutionAddress(validator.withdrawal_credentials[12:]),
|
||||
// amount=balance,
|
||||
// ))
|
||||
// withdrawal_index += WithdrawalIndex(1)
|
||||
// elif is_partially_withdrawable_validator(validator, balance):
|
||||
// withdrawals.append(Withdrawal(
|
||||
// index=withdrawal_index,
|
||||
// validator_index=validator_index,
|
||||
// address=ExecutionAddress(validator.withdrawal_credentials[12:]),
|
||||
// amount=balance - get_max_effective_balance(validator), # [Modified in Electra:EIP7251]
|
||||
// ))
|
||||
// withdrawal_index += WithdrawalIndex(1)
|
||||
// if len(withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
|
||||
// break
|
||||
// validator_index = ValidatorIndex((validator_index + 1) % len(state.validators))
|
||||
// return withdrawals, processed_partial_withdrawals_count
|
||||
func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, error) {
|
||||
if b.version < version.Capella {
|
||||
return nil, 0, errNotSupported("ExpectedWithdrawals", b.version)
|
||||
@@ -132,9 +134,16 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
|
||||
return nil, 0, fmt.Errorf("could not retrieve balance at index %d: %w", w.Index, err)
|
||||
}
|
||||
hasSufficientEffectiveBalance := v.EffectiveBalance() >= params.BeaconConfig().MinActivationBalance
|
||||
hasExcessBalance := vBal > params.BeaconConfig().MinActivationBalance
|
||||
var totalWithdrawn uint64
|
||||
for _, wi := range withdrawals {
|
||||
if wi.ValidatorIndex == w.Index {
|
||||
totalWithdrawn += wi.Amount
|
||||
}
|
||||
}
|
||||
balance := vBal - totalWithdrawn
|
||||
hasExcessBalance := balance > params.BeaconConfig().MinActivationBalance
|
||||
if v.ExitEpoch() == params.BeaconConfig().FarFutureEpoch && hasSufficientEffectiveBalance && hasExcessBalance {
|
||||
amount := min(vBal-params.BeaconConfig().MinActivationBalance, w.Amount)
|
||||
amount := min(balance-params.BeaconConfig().MinActivationBalance, w.Amount)
|
||||
withdrawals = append(withdrawals, &enginev1.Withdrawal{
|
||||
Index: withdrawalIndex,
|
||||
ValidatorIndex: w.Index,
|
||||
|
||||
@@ -416,3 +416,37 @@ func TestExpectedWithdrawals(t *testing.T) {
|
||||
require.DeepEqual(t, withdrawalFull, expected[1])
|
||||
})
|
||||
}
|
||||
|
||||
func TestExpectedWithdrawals_underflow_electra(t *testing.T) {
|
||||
s, err := state_native.InitializeFromProtoUnsafeElectra(ðpb.BeaconStateElectra{})
|
||||
require.NoError(t, err)
|
||||
vals := make([]*ethpb.Validator, 1)
|
||||
balances := make([]uint64, 1)
|
||||
balances[0] = 2015_000_000_000 //Validator A begins leaking ETH due to inactivity, and over time, its balance decreases to 2,015 ETH
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra,
|
||||
WithdrawableEpoch: primitives.Epoch(0),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
|
||||
val.WithdrawalCredentials[31] = byte(0)
|
||||
vals[0] = val
|
||||
|
||||
require.NoError(t, s.SetValidators(vals))
|
||||
require.NoError(t, s.SetBalances(balances))
|
||||
require.NoError(t, s.AppendPendingPartialWithdrawal(ðpb.PendingPartialWithdrawal{
|
||||
Amount: 1008_000_000_000,
|
||||
WithdrawableEpoch: primitives.Epoch(0),
|
||||
}))
|
||||
require.NoError(t, s.AppendPendingPartialWithdrawal(ðpb.PendingPartialWithdrawal{
|
||||
Amount: 1008_000_000_000,
|
||||
WithdrawableEpoch: primitives.Epoch(0),
|
||||
}))
|
||||
expected, _, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 3, len(expected)) // is a fully withdrawable validator
|
||||
require.Equal(t, uint64(1008_000_000_000), expected[0].Amount)
|
||||
require.Equal(t, uint64(975_000_000_000), expected[1].Amount)
|
||||
require.Equal(t, uint64(32_000_000_000), expected[2].Amount)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user