diff --git a/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py b/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py new file mode 100644 index 0000000000..9ea506392b --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/electra/sanity/test_slots.py @@ -0,0 +1,134 @@ +from eth2spec.test.context import ( + spec_state_test, + with_electra_and_later, +) +from eth2spec.test.helpers.deposits import prepare_pending_deposit +from eth2spec.test.helpers.state import transition_to + + +def run_epoch_processing(spec, state, pending_deposits=None, pending_consolidations=None): + if pending_deposits is None: + pending_deposits = [] + if pending_consolidations is None: + pending_consolidations = [] + # Transition to the last slot of the epoch + slot = state.slot + spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH) - 1 + transition_to(spec, state, slot) + state.pending_deposits = pending_deposits + state.pending_consolidations = pending_consolidations + yield 'pre', state + yield 'slots', 1 + spec.process_slots(state, state.slot + 1) + yield 'post', state + + assert state.pending_deposits == [] + assert state.pending_consolidations == [] + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey(spec, state): + # Create multiple deposits with the same pubkey + index = len(state.validators) + deposit = prepare_pending_deposit(spec, validator_index=index, amount=spec.MIN_ACTIVATION_BALANCE, signed=True) + pending_deposits = [deposit, deposit] + + yield from run_epoch_processing(spec, state, pending_deposits=pending_deposits) + + # Check deposit balance is applied correctly + assert state.balances[index] == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == spec.MIN_ACTIVATION_BALANCE + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey_compounding(spec, state): + # Create multiple deposits with the same pubkey and compounding creds + index = len(state.validators) + deposit = prepare_pending_deposit( + spec, validator_index=index, amount=spec.MIN_ACTIVATION_BALANCE, signed=True, + withdrawal_credentials=(spec.COMPOUNDING_WITHDRAWAL_PREFIX + b'\x00' * 11 + b'\x11' * 20) + ) + pending_deposits = [deposit, deposit] + + yield from run_epoch_processing(spec, state, pending_deposits=pending_deposits) + + # Check deposit balance is applied correctly + assert state.balances[index] == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == state.balances[index] + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey_below_upward_threshold(spec, state): + # Create multiple deposits with top up lower than the upward threshold + index = len(state.validators) + deposit_0 = prepare_pending_deposit( + spec, validator_index=index, + amount=(spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT), signed=True + ) + deposit_1 = prepare_pending_deposit( + spec, validator_index=index, + amount=spec.EFFECTIVE_BALANCE_INCREMENT, signed=True + ) + pending_deposits = [deposit_0, deposit_1] + + yield from run_epoch_processing(spec, state, pending_deposits=pending_deposits) + + # Check deposit balance is applied correctly + assert state.balances[index] == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == deposit_0.amount + + +@with_electra_and_later +@spec_state_test +def test_multiple_pending_deposits_same_pubkey_above_upward_threshold(spec, state): + # Create multiple deposits with top up greater than the upward threshold + index = len(state.validators) + deposit_0 = prepare_pending_deposit( + spec, validator_index=index, + amount=(spec.MIN_ACTIVATION_BALANCE - spec.EFFECTIVE_BALANCE_INCREMENT), signed=True + ) + amount = spec.EFFECTIVE_BALANCE_INCREMENT // spec.HYSTERESIS_QUOTIENT * spec.HYSTERESIS_UPWARD_MULTIPLIER + 1 + deposit_1 = prepare_pending_deposit(spec, validator_index=index, amount=amount, signed=True) + pending_deposits = [deposit_0, deposit_1] + + yield from run_epoch_processing(spec, state, pending_deposits) + + # Check deposit balance is applied correctly + balance = state.balances[index] + assert balance == sum(d.amount for d in pending_deposits) + assert state.validators[index].effective_balance == balance - balance % spec.EFFECTIVE_BALANCE_INCREMENT + + +@with_electra_and_later +@spec_state_test +def test_pending_consolidation(spec, state): + # Create pending consolidation + current_epoch = spec.get_current_epoch(state) + source_index = spec.get_active_validator_indices(state, current_epoch)[0] + target_index = spec.get_active_validator_indices(state, current_epoch)[1] + # Set withdrawable epoch to current epoch to allow processing + state.validators[source_index].withdrawable_epoch = current_epoch + # Set the source withdrawal credential to eth1 + state.validators[target_index].withdrawal_credentials = ( + spec.ETH1_ADDRESS_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 + ) + # Set the target withdrawal credential to compounding + state.validators[target_index].withdrawal_credentials = ( + spec.COMPOUNDING_WITHDRAWAL_PREFIX + b"\x00" * 11 + b"\x11" * 20 + ) + pending_consolidations = [spec.PendingConsolidation(source_index=source_index, target_index=target_index)] + + assert state.balances[source_index] == spec.MIN_ACTIVATION_BALANCE + assert state.validators[source_index].effective_balance == spec.MIN_ACTIVATION_BALANCE + assert state.balances[target_index] == spec.MIN_ACTIVATION_BALANCE + assert state.validators[target_index].effective_balance == spec.MIN_ACTIVATION_BALANCE + + yield from run_epoch_processing(spec, state, pending_consolidations=pending_consolidations) + + # Check the consolidation is processed correctly + assert state.balances[source_index] == 0 + assert state.validators[source_index].effective_balance == 0 + assert state.balances[target_index] == spec.MIN_ACTIVATION_BALANCE * 2 + assert state.validators[target_index].effective_balance == spec.MIN_ACTIVATION_BALANCE * 2 diff --git a/tests/generators/sanity/main.py b/tests/generators/sanity/main.py index 8039b82a44..2145146856 100644 --- a/tests/generators/sanity/main.py +++ b/tests/generators/sanity/main.py @@ -33,6 +33,7 @@ # do not forget to update sanity/block/__init__.py accordingly. _new_electra_mods = {key: 'eth2spec.test.electra.sanity.' + key for key in [ 'blocks', + 'slots', ]} electra_mods = combine_mods(_new_electra_mods, deneb_mods)