From 47cdae42926fc87084805c2e89b153e4f2f0b58a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 06:38:30 +0800 Subject: [PATCH] Refactor 1. Rename the current `get_genesis_beacon_state(...)` to `initialize_beacon_state_from_eth1(...)` 2. Extract `is_valid_genesis_state(state: BeaconState) -> bool` from `initialize_beacon_state_from_eth1(...)` --- specs/core/0_beacon-chain.md | 20 +++-- .../eth2spec/test/genesis/test_genesis.py | 31 ------- .../test/genesis/test_genesis_trigger.py | 52 ----------- .../test_initialize_beacon_state_from_eth1.py | 39 +++++++++ .../genesis/test_is_valid_genesis_state.py | 86 +++++++++++++++++++ 5 files changed, 140 insertions(+), 88 deletions(-) delete mode 100644 test_libs/pyspec/eth2spec/test/genesis/test_genesis.py delete mode 100644 test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py create mode 100644 test_libs/pyspec/eth2spec/test/genesis/test_initialize_beacon_state_from_eth1.py create mode 100644 test_libs/pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 7e39a5284..1009da909 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1092,24 +1092,25 @@ def slash_validator(state: BeaconState, ### Genesis state -Before the Ethereum 2.0 genesis has been triggered, and for every Ethereum 1.0 block, call `get_genesis_beacon_state(eth1_block_hash, eth1_timestamp, deposits)` where: +Before the Ethereum 2.0 genesis has been triggered, and for every Ethereum 1.0 block, call `initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` where: * `eth1_block_hash` is the hash of the Ethereum 1.0 block * `eth1_timestamp` is the Unix timestamp corresponding to `eth1_block_hash` * `deposits` is the sequence of all deposits, ordered chronologically, up to the block with hash `eth1_block_hash` -The genesis state `genesis_state` is the return value of the first call to `get_genesis_beacon_state` that does not trigger an `assert`. +The genesis state `genesis_state` is the return value of calling `initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)` only if `is_valid_genesis_state(genesis_state) is True`. *Note*: The two constants `MIN_GENESIS_TIME` and `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` have yet to be agreed upon by the community, and can be updated as necessary. ```python -def get_genesis_beacon_state(eth1_block_hash: Hash, eth1_timestamp: uint64, deposits: Sequence[Deposit]) -> BeaconState: +def initialize_beacon_state_from_eth1(eth1_block_hash: Hash, + eth1_timestamp: uint64, + deposits: Sequence[Deposit]) -> BeaconState: state = BeaconState( genesis_time=eth1_timestamp - eth1_timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY, eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=len(deposits)), latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) - assert state.genesis_time >= MIN_GENESIS_TIME # Process deposits leaves = list(map(lambda deposit: deposit.data, deposits)) @@ -1124,7 +1125,6 @@ def get_genesis_beacon_state(eth1_block_hash: Hash, eth1_timestamp: uint64, depo if state.balances[index] >= MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH - assert len(get_active_validator_indices(state, GENESIS_EPOCH)) >= MIN_GENESIS_ACTIVE_VALIDATOR_COUNT # Populate active_index_roots genesis_active_index_root = hash_tree_root( @@ -1136,6 +1136,16 @@ def get_genesis_beacon_state(eth1_block_hash: Hash, eth1_timestamp: uint64, depo return state ``` +```python +def is_valid_genesis_state(state: BeaconState) -> bool: + if state.genesis_time < MIN_GENESIS_TIME: + return False + elif len(get_active_validator_indices(state, GENESIS_EPOCH)) < MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: + return False + else: + return True +``` + ### Genesis block Let `genesis_block = BeaconBlock(state_root=hash_tree_root(genesis_state))`. diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py deleted file mode 100644 index 9c546b172..000000000 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py +++ /dev/null @@ -1,31 +0,0 @@ -from eth2spec.test.context import with_phases, spectest_with_bls_switch -from eth2spec.test.helpers.deposits import ( - prepare_genesis_deposits, -) - - -@with_phases(['phase0']) -@spectest_with_bls_switch -def test_get_genesis_beacon_state_success(spec): - deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - - eth1_block_hash = b'\x12' * 32 - eth1_timestamp = spec.MIN_GENESIS_TIME - - yield "eth1_block_hash", eth1_block_hash - yield "eth1_timestamp", eth1_timestamp - yield "deposits", deposits - genesis_state = spec.get_genesis_beacon_state( - eth1_block_hash, - eth1_timestamp, - deposits, - ) - - assert genesis_state.genesis_time == eth1_timestamp - eth1_timestamp % spec.SECONDS_PER_DAY + 2 * spec.SECONDS_PER_DAY - assert len(genesis_state.validators) == deposit_count - assert genesis_state.eth1_data.deposit_root == deposit_root - assert genesis_state.eth1_data.deposit_count == deposit_count - assert genesis_state.eth1_data.block_hash == eth1_block_hash - - yield "state", genesis_state diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py deleted file mode 100644 index 998189e15..000000000 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py +++ /dev/null @@ -1,52 +0,0 @@ -from eth2spec.test.context import with_phases, spectest_with_bls_switch -from eth2spec.test.helpers.deposits import ( - prepare_genesis_deposits, -) - - -@with_phases(['phase0']) -@spectest_with_bls_switch -def test_is_genesis_trigger_false(spec): - deposit_count = 2 - genesis_deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1546300800 - - yield "deposits", genesis_deposits - yield "time", genesis_time - - is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time) - assert is_triggered is False - - yield "is_triggered", is_triggered - - -@with_phases(['phase0']) -@spectest_with_bls_switch -def test_is_genesis_trigger_true(spec): - deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - SECONDS_PER_DAY = 86400 - genesis_time = 1578009600 - 2 * SECONDS_PER_DAY - - yield "deposits", genesis_deposits - yield "time", genesis_time - - is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time) - assert is_triggered is True - - yield "is_triggered", is_triggered - - -@with_phases(['phase0']) -@spectest_with_bls_switch -def test_is_genesis_trigger_not_enough_balance(spec): - deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) - genesis_time = 1546300800 - yield "deposits", genesis_deposits - yield "time", genesis_time - - is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time) - assert is_triggered is False - - yield "is_triggered", is_triggered diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_initialize_beacon_state_from_eth1.py b/test_libs/pyspec/eth2spec/test/genesis/test_initialize_beacon_state_from_eth1.py new file mode 100644 index 000000000..86f845f74 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/genesis/test_initialize_beacon_state_from_eth1.py @@ -0,0 +1,39 @@ +from eth2spec.test.context import spectest_with_bls_switch, with_phases +from eth2spec.test.helpers.deposits import ( + prepare_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) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + return spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +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) + + eth1_block_hash = b'\x12' * 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 state.genesis_time == eth1_timestamp - eth1_timestamp % spec.SECONDS_PER_DAY + 2 * spec.SECONDS_PER_DAY + assert len(state.validators) == deposit_count + assert state.eth1_data.deposit_root == deposit_root + assert state.eth1_data.deposit_count == deposit_count + assert state.eth1_data.block_hash == eth1_block_hash + + # yield state + yield 'state', state diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py b/test_libs/pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py new file mode 100644 index 000000000..8b41e5ac4 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py @@ -0,0 +1,86 @@ +from eth2spec.test.context import spectest_with_bls_switch, with_phases +from eth2spec.test.helpers.deposits import ( + prepare_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) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + return spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + +def run_is_valid_genesis_state(spec, state, valid=True): + """ + Run ``is_valid_genesis_state``, yielding: + - state ('state') + - is_valid ('is_valid') + If ``valid == False``, run expecting ``AssertionError`` + """ + yield state + is_valid = spec.is_valid_genesis_state(state) + yield 'is_valid', is_valid + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_true(spec): + state = create_valid_beacon_state(spec) + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_false_invalid_timestamp(spec): + state = create_valid_beacon_state(spec) + state.genesis_time = spec.MIN_GENESIS_TIME - 1 + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_true_more_balance(spec): + state = create_valid_beacon_state(spec) + state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE + 1 + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_false_not_enough_balance(spec): + state = create_valid_beacon_state(spec) + state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE - 1 + + yield from run_is_valid_genesis_state(spec, state, valid=False) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +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) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + yield from run_is_valid_genesis_state(spec, state, valid=True) + + +@with_phases(['phase0']) +@spectest_with_bls_switch +def test_is_valid_genesis_state_flase_not_enough_validator(spec): + deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1 + deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) + + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME + state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits) + + yield from run_is_valid_genesis_state(spec, state, valid=False)