From 4e2c7d20b7b87aa3c11eecc920e8b17c04c36dc6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 28 Sep 2020 17:55:54 -0600 Subject: [PATCH] add additional genesis initialization tests --- .../pyspec/eth2spec/test/helpers/deposits.py | 45 +++++- .../phase0/genesis/test_initialization.py | 132 ++++++++++++++++-- .../test/phase0/genesis/test_validity.py | 8 +- 3 files changed, 171 insertions(+), 14 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/helpers/deposits.py b/tests/core/pyspec/eth2spec/test/helpers/deposits.py index 6a2e30497..418ab1579 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/deposits.py +++ b/tests/core/pyspec/eth2spec/test/helpers/deposits.py @@ -1,3 +1,5 @@ +import random + from eth2spec.test.helpers.keys import pubkeys, privkeys from eth2spec.utils import bls from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_proof @@ -62,11 +64,16 @@ def deposit_from_context(spec, deposit_data_list, index): return deposit, root, deposit_data_list -def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False, deposit_data_list=None): +def prepare_full_genesis_deposits(spec, + amount, + pubkey_max_range, + pubkey_min_range=0, + signed=False, + deposit_data_list=None): if deposit_data_list is None: deposit_data_list = [] genesis_deposits = [] - for validator_index in range(genesis_validator_count): + for validator_index in range(pubkey_min_range, pubkey_max_range): pubkey = pubkeys[validator_index] privkey = privkeys[validator_index] # insecurely use pubkey as withdrawal key if no credentials provided @@ -85,6 +92,40 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False return genesis_deposits, root, deposit_data_list +def prepare_random_genesis_deposits(spec, + num_deposits, + max_pubkey_index, + min_pubkey_index=0, + max_amount=None, + min_amount=None, + deposit_data_list=None): + if max_amount is None: + max_amount = spec.MAX_EFFECTIVE_BALANCE + if min_amount is None: + min_amount = spec.MIN_DEPOSIT_AMOUNT + if deposit_data_list is None: + deposit_data_list = [] + deposits = [] + for _ in range(num_deposits): + pubkey_index = random.randint(min_pubkey_index, max_pubkey_index) + pubkey = pubkeys[pubkey_index] + privkey = privkeys[pubkey_index] + amount = random.randint(min_amount, max_amount) + random_byte = bytes([random.randint(0, 255)]) + withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(random_byte)[1:] + deposit, root, deposit_data_list = build_deposit( + spec, + deposit_data_list, + pubkey, + privkey, + amount, + withdrawal_credentials, + signed=True, + ) + deposits.append(deposit) + return deposits, root, deposit_data_list + + def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_credentials=None, signed=False): """ Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount. diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py index faade2d17..8cd66ae2d 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_initialization.py @@ -1,6 +1,7 @@ from eth2spec.test.context import PHASE0, spec_test, with_phases, single_phase from eth2spec.test.helpers.deposits import ( - prepare_genesis_deposits, + prepare_full_genesis_deposits, + prepare_random_genesis_deposits, ) @@ -9,7 +10,12 @@ from eth2spec.test.helpers.deposits import ( @single_phase def test_initialize_beacon_state_from_eth1(spec): deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - deposits, deposit_root, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + deposits, deposit_root, _ = prepare_full_genesis_deposits( + spec, + spec.MAX_EFFECTIVE_BALANCE, + deposit_count, + signed=True, + ) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME @@ -37,14 +43,18 @@ def test_initialize_beacon_state_from_eth1(spec): @single_phase def test_initialize_beacon_state_some_small_balances(spec): main_deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - main_deposits, _, deposit_data_list = prepare_genesis_deposits(spec, main_deposit_count, - spec.MAX_EFFECTIVE_BALANCE, signed=True) + main_deposits, _, deposit_data_list = prepare_full_genesis_deposits( + spec, spec.MAX_EFFECTIVE_BALANCE, + pubkey_max_range=main_deposit_count, signed=True, + ) # For deposits above, and for another deposit_count, add a balance of EFFECTIVE_BALANCE_INCREMENT small_deposit_count = main_deposit_count * 2 - small_deposits, deposit_root, _ = prepare_genesis_deposits(spec, small_deposit_count, - spec.MIN_DEPOSIT_AMOUNT, - signed=True, - deposit_data_list=deposit_data_list) + small_deposits, deposit_root, _ = prepare_full_genesis_deposits( + spec, spec.MIN_DEPOSIT_AMOUNT, + pubkey_max_range=small_deposit_count, + signed=True, + deposit_data_list=deposit_data_list, + ) deposits = main_deposits + small_deposits eth1_block_hash = b'\x12' * 32 @@ -67,3 +77,109 @@ def test_initialize_beacon_state_some_small_balances(spec): # yield state yield 'state', state + + +@with_phases([PHASE0]) +@spec_test +@single_phase +def test_initialize_beacon_state_one_topup_activation(spec): + # submit all but one deposit as MAX_EFFECTIVE_BALANCE + main_deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 + main_deposits, _, deposit_data_list = prepare_full_genesis_deposits( + spec, spec.MAX_EFFECTIVE_BALANCE, + pubkey_max_range=main_deposit_count, signed=True, + ) + + # submit last pubkey deposit as MAX_EFFECTIVE_BALANCE - MIN_DEPOSIT_AMOUNT + partial_deposits, _, deposit_data_list = prepare_full_genesis_deposits( + spec, spec.MAX_EFFECTIVE_BALANCE - spec.MIN_DEPOSIT_AMOUNT, + pubkey_max_range=main_deposit_count + 1, + pubkey_min_range=main_deposit_count, + signed=True, + deposit_data_list=deposit_data_list, + ) + + # submit last pubkey deposit as MIN_DEPOSIT_AMOUNT to complete the deposit + completed_deposits, deposit_root, deposit_data_list = prepare_full_genesis_deposits( + spec, spec.MIN_DEPOSIT_AMOUNT, + pubkey_max_range=main_deposit_count + 1, + pubkey_min_range=main_deposit_count, + signed=True, + deposit_data_list=deposit_data_list, + ) + + deposits = main_deposits + partial_deposits + completed_deposits + + eth1_block_hash = b'\x13' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + + yield 'eth1_block_hash', eth1_block_hash + yield 'eth1_timestamp', eth1_timestamp + yield 'deposits', deposits + + # initialize beacon_state + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + assert spec.is_valid_genesis_state(state) + + # yield state + yield 'state', state + + +@with_phases([PHASE0]) +@spec_test +@single_phase +def test_initialize_beacon_state_random_invalid_genesis(spec): + # Make a bunch of random deposits + deposits, _, deposit_data_list = prepare_random_genesis_deposits( + spec, + num_deposits=20, + max_pubkey_index=10, + ) + eth1_block_hash = b'\x14' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + 1 + + yield 'eth1_block_hash', eth1_block_hash + yield 'eth1_timestamp', eth1_timestamp + yield 'deposits', deposits + + # initialize beacon_state + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + assert not spec.is_valid_genesis_state(state) + + yield 'state', state + + +@with_phases([PHASE0]) +@spec_test +@single_phase +def test_initialize_beacon_state_random_valid_genesis(spec): + # Make a bunch of random deposits + random_deposits, _, deposit_data_list = prepare_random_genesis_deposits( + spec, + num_deposits=30, + min_pubkey_index=spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 5, + max_pubkey_index=spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 5, + ) + + # Then make spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT full deposits + full_deposits, _, _ = prepare_full_genesis_deposits( + spec, + spec.MAX_EFFECTIVE_BALANCE, + pubkey_max_range=spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, + signed=True, + deposit_data_list=deposit_data_list + ) + + deposits = random_deposits + full_deposits + eth1_block_hash = b'\x15' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + 2 + + yield 'eth1_block_hash', eth1_block_hash + yield 'eth1_timestamp', eth1_timestamp + yield 'deposits', deposits + + # initialize beacon_state + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + assert spec.is_valid_genesis_state(state) + + yield 'state', state diff --git a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py index dbaf3f951..832ad597f 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py +++ b/tests/core/pyspec/eth2spec/test/phase0/genesis/test_validity.py @@ -1,12 +1,12 @@ from eth2spec.test.context import PHASE0, spec_test, with_phases, single_phase from eth2spec.test.helpers.deposits import ( - prepare_genesis_deposits, + prepare_full_genesis_deposits, ) def create_valid_beacon_state(spec): deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - deposits, _, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + deposits, _, _ = prepare_full_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME @@ -69,7 +69,7 @@ def test_is_valid_genesis_state_true_more_balance(spec): @single_phase def test_is_valid_genesis_state_true_one_more_validator(spec): deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 1 - deposits, _, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + deposits, _, _ = prepare_full_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME @@ -83,7 +83,7 @@ def test_is_valid_genesis_state_true_one_more_validator(spec): @single_phase def test_is_valid_genesis_state_false_not_enough_validator(spec): deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 - deposits, _, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) + deposits, _, _ = prepare_full_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME