|
| 1 | +import random |
| 2 | + |
| 3 | +from eth2spec.test.context import ( |
| 4 | + spec_state_test, |
| 5 | + with_electra_and_later, |
| 6 | +) |
| 7 | +from eth2spec.test.helpers.execution_payload import ( |
| 8 | + build_empty_execution_payload, |
| 9 | +) |
| 10 | +from eth2spec.test.helpers.state import ( |
| 11 | + next_slot, |
| 12 | +) |
| 13 | +from eth2spec.test.helpers.withdrawals import ( |
| 14 | + prepare_expected_withdrawals_compounding, |
| 15 | + run_withdrawals_processing, |
| 16 | + set_compounding_withdrawal_credential_with_balance, |
| 17 | + prepare_pending_withdrawal, |
| 18 | +) |
| 19 | + |
| 20 | + |
| 21 | +@with_electra_and_later |
| 22 | +@spec_state_test |
| 23 | +def test_success_mixed_fully_and_partial_withdrawable_compounding(spec, state): |
| 24 | + num_full_withdrawals = spec.MAX_WITHDRAWALS_PER_PAYLOAD // 2 |
| 25 | + num_partial_withdrawals = spec.MAX_WITHDRAWALS_PER_PAYLOAD - num_full_withdrawals |
| 26 | + fully_withdrawable_indices, partial_withdrawals_indices = prepare_expected_withdrawals_compounding( |
| 27 | + spec, state, |
| 28 | + rng=random.Random(42), |
| 29 | + num_full_withdrawals=num_full_withdrawals, |
| 30 | + num_partial_withdrawals_sweep=num_partial_withdrawals, |
| 31 | + ) |
| 32 | + |
| 33 | + next_slot(spec, state) |
| 34 | + execution_payload = build_empty_execution_payload(spec, state) |
| 35 | + |
| 36 | + yield from run_withdrawals_processing( |
| 37 | + spec, state, execution_payload, |
| 38 | + fully_withdrawable_indices=fully_withdrawable_indices, |
| 39 | + partial_withdrawals_indices=partial_withdrawals_indices) |
| 40 | + |
| 41 | + |
| 42 | +@with_electra_and_later |
| 43 | +@spec_state_test |
| 44 | +def test_success_no_max_effective_balance_compounding(spec, state): |
| 45 | + validator_index = len(state.validators) // 2 |
| 46 | + # To be partially withdrawable, the validator's effective balance must be maxed out |
| 47 | + effective_balance = spec.MAX_EFFECTIVE_BALANCE_ELECTRA - spec.EFFECTIVE_BALANCE_INCREMENT |
| 48 | + set_compounding_withdrawal_credential_with_balance(spec, state, validator_index, effective_balance) |
| 49 | + |
| 50 | + validator = state.validators[validator_index] |
| 51 | + assert not spec.is_partially_withdrawable_validator(validator, state.balances[validator_index]) |
| 52 | + |
| 53 | + execution_payload = build_empty_execution_payload(spec, state) |
| 54 | + |
| 55 | + yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) |
| 56 | + |
| 57 | + |
| 58 | +@with_electra_and_later |
| 59 | +@spec_state_test |
| 60 | +def test_success_no_excess_balance_compounding(spec, state): |
| 61 | + validator_index = len(state.validators) // 2 |
| 62 | + # To be partially withdrawable, the validator needs an excess balance |
| 63 | + effective_balance = spec.MAX_EFFECTIVE_BALANCE_ELECTRA |
| 64 | + set_compounding_withdrawal_credential_with_balance(spec, state, validator_index, effective_balance) |
| 65 | + |
| 66 | + validator = state.validators[validator_index] |
| 67 | + assert not spec.is_partially_withdrawable_validator(validator, state.balances[validator_index]) |
| 68 | + |
| 69 | + execution_payload = build_empty_execution_payload(spec, state) |
| 70 | + |
| 71 | + yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) |
| 72 | + |
| 73 | + |
| 74 | +@with_electra_and_later |
| 75 | +@spec_state_test |
| 76 | +def test_success_excess_balance_but_no_max_effective_balance_compounding(spec, state): |
| 77 | + validator_index = len(state.validators) // 2 |
| 78 | + # To be partially withdrawable, the validator needs both a maxed out effective balance and an excess balance |
| 79 | + effective_balance = spec.MAX_EFFECTIVE_BALANCE_ELECTRA - spec.EFFECTIVE_BALANCE_INCREMENT |
| 80 | + balance = spec.MAX_EFFECTIVE_BALANCE_ELECTRA + spec.EFFECTIVE_BALANCE_INCREMENT |
| 81 | + set_compounding_withdrawal_credential_with_balance(spec, state, validator_index, effective_balance, balance) |
| 82 | + |
| 83 | + validator = state.validators[validator_index] |
| 84 | + assert not spec.is_partially_withdrawable_validator(validator, state.balances[validator_index]) |
| 85 | + |
| 86 | + execution_payload = build_empty_execution_payload(spec, state) |
| 87 | + |
| 88 | + yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=0) |
| 89 | + |
| 90 | + |
| 91 | +@with_electra_and_later |
| 92 | +@spec_state_test |
| 93 | +def test_pending_withdrawals_one_skipped_one_effective(spec, state): |
| 94 | + index_0 = 3 |
| 95 | + index_1 = 5 |
| 96 | + |
| 97 | + withdrawal_0 = prepare_pending_withdrawal(spec, state, index_0) |
| 98 | + withdrawal_1 = prepare_pending_withdrawal(spec, state, index_1) |
| 99 | + |
| 100 | + # If validator doesn't have an excess balance pending withdrawal is skipped |
| 101 | + state.balances[index_0] = spec.MIN_ACTIVATION_BALANCE |
| 102 | + |
| 103 | + execution_payload = build_empty_execution_payload(spec, state) |
| 104 | + assert state.pending_partial_withdrawals == [withdrawal_0, withdrawal_1] |
| 105 | + yield from run_withdrawals_processing(spec, state, execution_payload, num_expected_withdrawals=1) |
| 106 | + |
| 107 | + assert state.pending_partial_withdrawals == [] |
0 commit comments