From 7a16db144c9658c6dad6da9d29bd849141a7a94a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 15:59:18 -0600 Subject: [PATCH 001/112] Add test_genesis --- scripts/build_spec.py | 1 + specs/core/0_beacon-chain.md | 14 +++-- .../pyspec/eth2spec/test/helpers/deposits.py | 52 ++++++++++++++++--- .../eth2spec/test/sanity/test_genesis.py | 29 +++++++++++ 4 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 test_libs/pyspec/eth2spec/test/sanity/test_genesis.py diff --git a/scripts/build_spec.py b/scripts/build_spec.py index a16fa79ac..d7b6d0f59 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -16,6 +16,7 @@ PHASE0_IMPORTS = '''from typing import ( Callable, Dict, List, + Optional, Set, Tuple, ) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1dcdbdef9..28d0d72cd 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1176,8 +1176,12 @@ def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis ) # Process genesis deposits - for deposit in deposits: - process_deposit(state, deposit) + for deposit_index, deposit in enumerate(deposits): + process_deposit( + state, + deposit, + deposit_index=deposit_index, + ) # Process genesis activations for validator in state.validators: @@ -1726,16 +1730,18 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ##### Deposits ```python -def process_deposit(state: BeaconState, deposit: Deposit) -> None: +def process_deposit(state: BeaconState, deposit: Deposit, deposit_index: Optional[uint64]) -> None: """ Process an Eth1 deposit, registering a validator or increasing its balance. """ + if deposit_index is None: + deposit_index = state.eth1_deposit_index # Verify the Merkle branch assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, depth=DEPOSIT_CONTRACT_TREE_DEPTH, - index=state.eth1_deposit_index, + index=deposit_index, root=state.eth1_data.deposit_root, ) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 20ff7440f..ca8b23361 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -4,25 +4,31 @@ from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merk from eth2spec.utils.ssz.ssz_impl import signing_root -def build_deposit_data(spec, state, pubkey, privkey, amount, withdrawal_credentials, signed=False): +def build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=None, signed=False): deposit_data = spec.DepositData( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, ) if signed: - sign_deposit_data(spec, state, deposit_data, privkey) + sign_deposit_data(spec, deposit_data, privkey, state) return deposit_data -def sign_deposit_data(spec, state, deposit_data, privkey): - signature = bls_sign( - message_hash=signing_root(deposit_data), - privkey=privkey, - domain=spec.get_domain( +def sign_deposit_data(spec, deposit_data, privkey, state=None): + if state is None: + # Genesis + domain = spec.bls_domain(spec.DOMAIN_DEPOSIT) + else: + domain = spec.get_domain( state, spec.DOMAIN_DEPOSIT, ) + + signature = bls_sign( + message_hash=signing_root(deposit_data), + privkey=privkey, + domain=domain, ) deposit_data.signature = signature @@ -35,7 +41,7 @@ def build_deposit(spec, amount, withdrawal_credentials, signed): - deposit_data = build_deposit_data(spec, state, pubkey, privkey, amount, withdrawal_credentials, signed) + deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed) item = deposit_data.hash_tree_root() index = len(deposit_data_leaves) @@ -54,6 +60,36 @@ def build_deposit(spec, return deposit, root, deposit_data_leaves +def prepare_genesis_deposits(spec, genesis_validator_count, signed=False): + genesis_deposit_data_list = [] + deposit_data_leaves = [] + for validator_index in range(genesis_validator_count): + pubkey = pubkeys[validator_index] + privkey = privkeys[validator_index] + # insecurely use pubkey as withdrawal key if no credentials provided + withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:] + deposit_data = spec.DepositData( + pubkey=pubkey, + withdrawal_credentials=withdrawal_credentials, + amount=spec.MAX_EFFECTIVE_BALANCE, + ) + if signed: + sign_deposit_data(spec, deposit_data, privkey) # state=None + item = deposit_data.hash_tree_root() + deposit_data_leaves.append(item) + genesis_deposit_data_list.append(deposit_data) + + tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) + root = get_merkle_root((tuple(deposit_data_leaves))) + + genesis_deposits = ( + spec.Deposit(proof=list(get_merkle_proof(tree, item_index=index)), data=deposit_data) + for index, deposit_data in enumerate(genesis_deposit_data_list) + ) + + return genesis_deposits, root + + 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/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py new file mode 100644 index 000000000..088df84e8 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py @@ -0,0 +1,29 @@ +from eth2spec.test.context import spec_state_test, with_phases +from eth2spec.test.helpers.deposits import ( + prepare_genesis_deposits, +) + + +@with_phases(['phase0']) +@spec_state_test +def test_genesis(spec, state): + deposit_count = 2 + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count) + genesis_time = 1234 + + yield genesis_deposits + yield genesis_time + + genesis_eth1_data = spec.Eth1Data( + deposit_root=deposit_root, + deposit_count=deposit_count, + block_hash=b'\x12' * 32, + ) + + yield genesis_eth1_data + genesis_state = spec.get_genesis_beacon_state( + genesis_deposits, + genesis_time, + genesis_eth1_data, + ) + yield genesis_state From b36ffd5c412c65327ba10f35f1f406a006bf1d20 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 16:10:19 -0600 Subject: [PATCH 002/112] default value of `deposit_index` --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 28d0d72cd..4d35c6516 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1730,7 +1730,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ##### Deposits ```python -def process_deposit(state: BeaconState, deposit: Deposit, deposit_index: Optional[uint64]) -> None: +def process_deposit(state: BeaconState, deposit: Deposit, deposit_index: Optional[uint64]=None) -> None: """ Process an Eth1 deposit, registering a validator or increasing its balance. """ From ac34221f55aabc75934c4e4fa6704e29599a680c Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 16:30:31 -0600 Subject: [PATCH 003/112] Fix `is_genesis_trigger` and add test case --- configs/constant_presets/mainnet.yaml | 2 ++ configs/constant_presets/minimal.yaml | 2 ++ specs/core/0_beacon-chain.md | 19 ++++++++------ .../eth2spec/test/sanity/test_genesis.py | 26 +++++++++++++++++++ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index 09ec7bdb7..572cfb708 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -17,6 +17,8 @@ MIN_PER_EPOCH_CHURN_LIMIT: 4 CHURN_LIMIT_QUOTIENT: 65536 # See issue 563 SHUFFLE_ROUND_COUNT: 90 +# `2**16` (= 65,536) +GENESIS_ACTIVE_VALIDATOR_COUNT: 65536 # Deposit contract diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index c8c2853c7..edc73ab8b 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -16,6 +16,8 @@ MIN_PER_EPOCH_CHURN_LIMIT: 4 CHURN_LIMIT_QUOTIENT: 65536 # [customized] Faster, but unsecure. SHUFFLE_ROUND_COUNT: 10 +# [customized] +GENESIS_ACTIVE_VALIDATOR_COUNT: 100 # Deposit contract diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 4d35c6516..0b856636b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -194,6 +194,7 @@ These configurations are updated for releases, but may be out of sync during `de | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `90` | +| `GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | * For the safety of crosslinks `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) @@ -1134,10 +1135,11 @@ Before genesis has been triggered and whenever the deposit contract emits a `Dep * `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log * `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log -When `is_genesis_trigger(deposits, timestamp) is True` for the first time let: +When `is_genesis_trigger(deposits, timestamp, deposit_root) is True` for the first time let: * `genesis_deposits = deposits` * `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` +* `deposit_root` is the tree root of the given `deposits` * `genesis_eth1_data` be the object of type `Eth1Data` where: * `genesis_eth1_data.block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` * `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits` @@ -1146,20 +1148,19 @@ When `is_genesis_trigger(deposits, timestamp) is True` for the first time let: *Note*: The function `is_genesis_trigger` has yet to be agreed by the community, and can be updated as necessary. We define the following testing placeholder: ```python -def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool: +def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64, deposit_root: Hash) -> bool: # Process deposits state = BeaconState() - for deposit in deposits: - process_deposit(state, deposit) + for index, deposit in enumerate(deposits): + process_deposit(state, deposit, deposit_index=index, deposit_root=deposit_root) # Count active validators at genesis active_validator_count = 0 - for validator in state.validator_registry: + for validator in state.validators: if validator.effective_balance == MAX_EFFECTIVE_BALANCE: active_validator_count += 1 # Check effective balance to trigger genesis - GENESIS_ACTIVE_VALIDATOR_COUNT = 2**16 return active_validator_count == GENESIS_ACTIVE_VALIDATOR_COUNT ``` @@ -1730,19 +1731,21 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ##### Deposits ```python -def process_deposit(state: BeaconState, deposit: Deposit, deposit_index: Optional[uint64]=None) -> None: +def process_deposit(state: BeaconState, deposit: Deposit, deposit_index: Optional[uint64]=None, deposit_root: Optional[Hash]=None) -> None: """ Process an Eth1 deposit, registering a validator or increasing its balance. """ if deposit_index is None: deposit_index = state.eth1_deposit_index + if deposit_root is None: + deposit_root = state.eth1_data.deposit_root # Verify the Merkle branch assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, depth=DEPOSIT_CONTRACT_TREE_DEPTH, index=deposit_index, - root=state.eth1_data.deposit_root, + root=deposit_root, ) # Deposits must be processed in order diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py index 088df84e8..0a9db7bc0 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py @@ -4,6 +4,32 @@ from eth2spec.test.helpers.deposits import ( ) +@with_phases(['phase0']) +@spec_state_test +def test_is_genesis_trigger_false(spec, state): + deposit_count = 2 + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count) + genesis_time = 1234 + + is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) + assert is_triggered is False + + yield is_triggered + + +@with_phases(['phase0']) +@spec_state_test +def test_is_genesis_trigger_true(spec, state): + deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count) + genesis_time = 1234 + + is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) + assert is_triggered is True + + yield is_triggered + + @with_phases(['phase0']) @spec_state_test def test_genesis(spec, state): From e7c595d1d6200299a6d33a7a4ef0d06801297b53 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 16:33:24 -0600 Subject: [PATCH 004/112] Fix test_process_deposit.py --- .../test/phase_0/block_processing/test_process_deposit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py index 63b94c638..1b8c44651 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py @@ -124,7 +124,7 @@ def test_wrong_index(spec, state): # mess up eth1_deposit_index deposit.index = state.eth1_deposit_index + 1 - sign_deposit_data(spec, state, deposit.data, privkeys[validator_index]) + sign_deposit_data(spec, deposit.data, privkeys[validator_index], state=state) yield from run_deposit_processing(spec, state, deposit, validator_index, valid=False) @@ -185,6 +185,6 @@ def test_bad_merkle_proof(spec, state): # mess up merkle branch deposit.proof[-1] = spec.ZERO_HASH - sign_deposit_data(spec, state, deposit.data, privkeys[validator_index]) + sign_deposit_data(spec, deposit.data, privkeys[validator_index], state) yield from run_deposit_processing(spec, state, deposit, validator_index, valid=False) From 8828dad786271fa2b5a6c95f5549d7bf5927c68b Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 17:07:44 -0600 Subject: [PATCH 005/112] minor updates --- specs/core/0_beacon-chain.md | 5 ++++- .../test/phase_0/block_processing/test_process_deposit.py | 2 +- test_libs/pyspec/eth2spec/test/sanity/test_genesis.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 0b856636b..c82f1e34f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1731,7 +1731,10 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ##### Deposits ```python -def process_deposit(state: BeaconState, deposit: Deposit, deposit_index: Optional[uint64]=None, deposit_root: Optional[Hash]=None) -> None: +def process_deposit(state: BeaconState, + deposit: Deposit, + deposit_index: Optional[uint64]=None, + deposit_root: Optional[Hash]=None) -> None: """ Process an Eth1 deposit, registering a validator or increasing its balance. """ diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py index 1b8c44651..6acf86cc7 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py @@ -185,6 +185,6 @@ def test_bad_merkle_proof(spec, state): # mess up merkle branch deposit.proof[-1] = spec.ZERO_HASH - sign_deposit_data(spec, deposit.data, privkeys[validator_index], state) + sign_deposit_data(spec, deposit.data, privkeys[validator_index], state=state) yield from run_deposit_processing(spec, state, deposit, validator_index, valid=False) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py index 0a9db7bc0..d6b3bf940 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py @@ -33,7 +33,7 @@ def test_is_genesis_trigger_true(spec, state): @with_phases(['phase0']) @spec_state_test def test_genesis(spec, state): - deposit_count = 2 + deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count) genesis_time = 1234 From 47b29c84564e442cf9394028080d39c256bf9914 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 21:49:13 -0600 Subject: [PATCH 006/112] Loose condition of effective genesis deposit --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index c82f1e34f..1d2dead41 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1157,7 +1157,7 @@ def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64, deposit_root: # Count active validators at genesis active_validator_count = 0 for validator in state.validators: - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: + if validator.effective_balance >= MAX_EFFECTIVE_BALANCE: active_validator_count += 1 # Check effective balance to trigger genesis From 7468fd034f5cb904513d6b07fc482f5b5478ad1e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 21:50:36 -0600 Subject: [PATCH 007/112] Add more test --- .../pyspec/eth2spec/test/helpers/deposits.py | 6 +++--- .../eth2spec/test/sanity/test_genesis.py | 20 ++++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index ca8b23361..eea019e8b 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -60,7 +60,7 @@ def build_deposit(spec, return deposit, root, deposit_data_leaves -def prepare_genesis_deposits(spec, genesis_validator_count, signed=False): +def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False): genesis_deposit_data_list = [] deposit_data_leaves = [] for validator_index in range(genesis_validator_count): @@ -71,7 +71,7 @@ def prepare_genesis_deposits(spec, genesis_validator_count, signed=False): deposit_data = spec.DepositData( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, - amount=spec.MAX_EFFECTIVE_BALANCE, + amount=amount, ) if signed: sign_deposit_data(spec, deposit_data, privkey) # state=None @@ -84,7 +84,7 @@ def prepare_genesis_deposits(spec, genesis_validator_count, signed=False): genesis_deposits = ( spec.Deposit(proof=list(get_merkle_proof(tree, item_index=index)), data=deposit_data) - for index, deposit_data in enumerate(genesis_deposit_data_list) + for index, deposit_data in enumerate(genesis_deposit_data_list) ) return genesis_deposits, root diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py index d6b3bf940..7e5fd5db4 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py @@ -8,7 +8,7 @@ from eth2spec.test.helpers.deposits import ( @spec_state_test def test_is_genesis_trigger_false(spec, state): deposit_count = 2 - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count) + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1234 is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) @@ -21,7 +21,7 @@ def test_is_genesis_trigger_false(spec, state): @spec_state_test def test_is_genesis_trigger_true(spec, state): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count) + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1234 is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) @@ -29,12 +29,26 @@ def test_is_genesis_trigger_true(spec, state): yield is_triggered +@with_phases(['phase0']) +@spec_state_test +def test_is_genesis_trigger_not_enough_balance(spec, state): + deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) + genesis_time = 1234 + yield genesis_deposits + yield genesis_time + + is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) + assert is_triggered is False + + yield is_triggered + @with_phases(['phase0']) @spec_state_test def test_genesis(spec, state): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count) + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1234 yield genesis_deposits From 24ad42663fd05fd9a09667ae74395feafae8dc37 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 22:02:03 -0600 Subject: [PATCH 008/112] `spectest_with_bls_switch` decorator --- test_libs/pyspec/eth2spec/test/context.py | 6 +++++- .../eth2spec/test/sanity/test_genesis.py | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/context.py b/test_libs/pyspec/eth2spec/test/context.py index 97266acf2..e7560afc6 100644 --- a/test_libs/pyspec/eth2spec/test/context.py +++ b/test_libs/pyspec/eth2spec/test/context.py @@ -27,9 +27,13 @@ def with_state(fn): DEFAULT_BLS_ACTIVE = False +def spectest_with_bls_switch(fn): + return bls_switch(spectest()(fn)) + + # shorthand for decorating @with_state @spectest() def spec_state_test(fn): - return with_state(bls_switch(spectest()(fn))) + return with_state(spectest_with_bls_switch(fn)) def expect_assertion_error(fn): diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py index 7e5fd5db4..3c76654e6 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py @@ -1,12 +1,12 @@ -from eth2spec.test.context import spec_state_test, with_phases +from eth2spec.test.context import with_phases, spectest_with_bls_switch from eth2spec.test.helpers.deposits import ( prepare_genesis_deposits, ) @with_phases(['phase0']) -@spec_state_test -def test_is_genesis_trigger_false(spec, state): +@spectest_with_bls_switch +def test_is_genesis_trigger_false(spec): deposit_count = 2 genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1234 @@ -18,8 +18,8 @@ def test_is_genesis_trigger_false(spec, state): @with_phases(['phase0']) -@spec_state_test -def test_is_genesis_trigger_true(spec, state): +@spectest_with_bls_switch +def test_is_genesis_trigger_true(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1234 @@ -29,9 +29,10 @@ def test_is_genesis_trigger_true(spec, state): yield is_triggered + @with_phases(['phase0']) -@spec_state_test -def test_is_genesis_trigger_not_enough_balance(spec, state): +@spectest_with_bls_switch +def test_is_genesis_trigger_not_enough_balance(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) genesis_time = 1234 @@ -45,8 +46,8 @@ def test_is_genesis_trigger_not_enough_balance(spec, state): @with_phases(['phase0']) -@spec_state_test -def test_genesis(spec, state): +@spectest_with_bls_switch +def test_genesis(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1234 From 5f0921277739d5a137ba86cefa5bf91d0df852dd Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 22:09:09 -0600 Subject: [PATCH 009/112] yield for `is_genesis_trigger` --- specs/core/0_beacon-chain.md | 6 +----- .../pyspec/eth2spec/test/sanity/test_genesis.py | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1d2dead41..c94c4fcc9 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1178,11 +1178,7 @@ def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis # Process genesis deposits for deposit_index, deposit in enumerate(deposits): - process_deposit( - state, - deposit, - deposit_index=deposit_index, - ) + process_deposit(state, deposit, deposit_index=deposit_index) # Process genesis activations for validator in state.validators: diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py index 3c76654e6..37d8a2b17 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py @@ -9,7 +9,11 @@ from eth2spec.test.helpers.deposits import ( def test_is_genesis_trigger_false(spec): deposit_count = 2 genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1234 + genesis_time = 1546300800 + + yield genesis_deposits + yield genesis_time + yield deposit_root is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) assert is_triggered is False @@ -22,7 +26,11 @@ def test_is_genesis_trigger_false(spec): def test_is_genesis_trigger_true(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1234 + genesis_time = 1546300800 + + yield genesis_deposits + yield genesis_time + yield deposit_root is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) assert is_triggered is True @@ -35,9 +43,10 @@ def test_is_genesis_trigger_true(spec): def test_is_genesis_trigger_not_enough_balance(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) - genesis_time = 1234 + genesis_time = 1546300800 yield genesis_deposits yield genesis_time + yield deposit_root is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) assert is_triggered is False @@ -50,7 +59,7 @@ def test_is_genesis_trigger_not_enough_balance(spec): def test_genesis(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1234 + genesis_time = 1546300800 yield genesis_deposits yield genesis_time From 6aef6c5634acc0c378c1f03b2cefd32ba3501954 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 21 Jun 2019 22:26:15 -0600 Subject: [PATCH 010/112] Clean up --- specs/core/0_beacon-chain.md | 4 ++-- test_libs/pyspec/eth2spec/test/sanity/test_genesis.py | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index bb1379b93..8f57967ed 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1139,11 +1139,11 @@ When `is_genesis_trigger(deposits, timestamp, deposit_root) is True` for the fir * `genesis_deposits = deposits` * `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` -* `deposit_root` is the tree root of the given `deposits` +* `deposit_root` is the Merkle tree root of the data of the given `deposits` * `genesis_eth1_data` be the object of type `Eth1Data` where: - * `genesis_eth1_data.block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` * `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits` * `genesis_eth1_data.deposit_count = len(genesis_deposits)` + * `genesis_eth1_data.block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` *Note*: The function `is_genesis_trigger` has yet to be agreed by the community, and can be updated as necessary. We define the following testing placeholder: diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py index 37d8a2b17..780d039eb 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py @@ -60,6 +60,7 @@ def test_genesis(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1546300800 + block_hash = b'\x12' * 32 yield genesis_deposits yield genesis_time @@ -67,7 +68,7 @@ def test_genesis(spec): genesis_eth1_data = spec.Eth1Data( deposit_root=deposit_root, deposit_count=deposit_count, - block_hash=b'\x12' * 32, + block_hash=block_hash, ) yield genesis_eth1_data @@ -76,4 +77,11 @@ def test_genesis(spec): genesis_time, genesis_eth1_data, ) + + assert genesis_state.genesis_time == genesis_time + 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 == block_hash + yield genesis_state From a3f8f50beed9f66801ce266b192b234c2dd11299 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 22 Jun 2019 23:34:09 +0200 Subject: [PATCH 011/112] Initialise deposit root properly --- specs/core/0_beacon-chain.md | 38 ++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8f57967ed..8aa307d66 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1135,11 +1135,10 @@ Before genesis has been triggered and whenever the deposit contract emits a `Dep * `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log * `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log -When `is_genesis_trigger(deposits, timestamp, deposit_root) is True` for the first time let: +When `is_genesis_trigger(deposits, timestamp) is True` for the first time let: * `genesis_deposits = deposits` * `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` -* `deposit_root` is the Merkle tree root of the data of the given `deposits` * `genesis_eth1_data` be the object of type `Eth1Data` where: * `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits` * `genesis_eth1_data.deposit_count = len(genesis_deposits)` @@ -1148,16 +1147,20 @@ When `is_genesis_trigger(deposits, timestamp, deposit_root) is True` for the fir *Note*: The function `is_genesis_trigger` has yet to be agreed by the community, and can be updated as necessary. We define the following testing placeholder: ```python -def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64, deposit_root: Hash) -> bool: - # Process deposits +def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool: + # Initialize deposit root state = BeaconState() - for index, deposit in enumerate(deposits): - process_deposit(state, deposit, deposit_index=index, deposit_root=deposit_root) + for i in range(DEPOSIT_CONTRACT_TREE_DEPTH - 1): + state.eth1_data.deposit_root = hash(state.eth1_data.deposit_root + state.eth1_data.deposit_root) + + # Process deposits + for deposit in deposits: + process_deposit(state, deposit) # Count active validators at genesis active_validator_count = 0 for validator in state.validators: - if validator.effective_balance >= MAX_EFFECTIVE_BALANCE: + if validator.effective_balance == MAX_EFFECTIVE_BALANCE: active_validator_count += 1 # Check effective balance to trigger genesis @@ -1177,12 +1180,12 @@ def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis ) # Process genesis deposits - for deposit_index, deposit in enumerate(deposits): - process_deposit(state, deposit, deposit_index=deposit_index) + for deposit in deposits: + process_deposit(state, deposit) # Process genesis activations for validator in state.validators: - if validator.effective_balance >= MAX_EFFECTIVE_BALANCE: + if validator.effective_balance == MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH @@ -1483,7 +1486,7 @@ def process_registry_updates(state: BeaconState) -> None: for index, validator in enumerate(state.validators): if ( validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH and - validator.effective_balance >= MAX_EFFECTIVE_BALANCE + validator.effective_balance == MAX_EFFECTIVE_BALANCE ): validator.activation_eligibility_epoch = get_current_epoch(state) @@ -1727,24 +1730,17 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None: ##### Deposits ```python -def process_deposit(state: BeaconState, - deposit: Deposit, - deposit_index: Optional[uint64]=None, - deposit_root: Optional[Hash]=None) -> None: +def process_deposit(state: BeaconState, deposit: Deposit) -> None: """ Process an Eth1 deposit, registering a validator or increasing its balance. """ - if deposit_index is None: - deposit_index = state.eth1_deposit_index - if deposit_root is None: - deposit_root = state.eth1_data.deposit_root # Verify the Merkle branch assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, depth=DEPOSIT_CONTRACT_TREE_DEPTH, - index=deposit_index, - root=deposit_root, + index=state.eth1_deposit_index, + root=state.eth1_data.deposit_root, ) # Deposits must be processed in order From 8c34aa8c5f7fd7e1951843feae396ac66021e9db Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Wed, 26 Jun 2019 13:20:04 +0100 Subject: [PATCH 012/112] Initial draft --- specs/core/0_beacon-chain.md | 64 +++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 56a6fd06a..6cf6db0cc 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -30,6 +30,7 @@ - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - [`IndexedAttestation`](#indexedattestation) - [`PendingAttestation`](#pendingattestation) + - [`CompactCommitteees`](#CompactCommitteees) - [`Eth1Data`](#eth1data) - [`HistoricalBatch`](#historicalbatch) - [`DepositData`](#depositdata) @@ -68,7 +69,7 @@ - [`get_block_root_at_slot`](#get_block_root_at_slot) - [`get_block_root`](#get_block_root) - [`get_randao_mix`](#get_randao_mix) - - [`get_active_index_root`](#get_active_index_root) + - [`get_compact_committee_root`](#get_compact_committee_root) - [`generate_seed`](#generate_seed) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - [`verify_merkle_branch`](#verify_merkle_branch) @@ -187,7 +188,7 @@ The following values are (non-configurable) constants used throughout the specif | - | - | | `SHARD_COUNT` | `2**10` (= 1,024) | | `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | -| `MAX_INDICES_PER_ATTESTATION` | `2**12` (= 4,096) | +| `MAX_VALIDATORS_PER_COMMITTEE` | `2**12` (= 4,096) | | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `90` | @@ -344,8 +345,8 @@ class AttestationDataAndCustodyBit(Container): ```python class IndexedAttestation(Container): - custody_bit_0_indices: List[ValidatorIndex, MAX_INDICES_PER_ATTESTATION] # Indices with custody bit equal to 0 - custody_bit_1_indices: List[ValidatorIndex, MAX_INDICES_PER_ATTESTATION] # Indices with custody bit equal to 1 + custody_bit_0_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] # Indices with custody bit equal to 0 + custody_bit_1_indices: List[ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE] # Indices with custody bit equal to 1 data: AttestationData signature: BLSSignature ``` @@ -354,12 +355,22 @@ class IndexedAttestation(Container): ```python class PendingAttestation(Container): - aggregation_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8] + aggregation_bitfield: Bytes[MAX_VALIDATORS_PER_COMMITTEE // 8] data: AttestationData inclusion_delay: Slot proposer_index: ValidatorIndex ``` +#### `CompactCommitteees` + +```python +class CompactCommitteees(Container): + data: Vector[Container( + pubkeys: List[Bytes48, MAX_VALIDATORS_PER_COMMITTEE] + compact_validators: List[uint64, MAX_VALIDATORS_PER_COMMITTEE] + ), SHARD_COUNT] +``` + #### `Eth1Data` ```python @@ -421,9 +432,9 @@ class AttesterSlashing(Container): ```python class Attestation(Container): - aggregation_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8] + aggregation_bitfield: Bytes[MAX_VALIDATORS_PER_COMMITTEE // 8] data: AttestationData - custody_bitfield: Bytes[MAX_INDICES_PER_ATTESTATION // 8] + custody_bitfield: Bytes[MAX_VALIDATORS_PER_COMMITTEE // 8] signature: BLSSignature ``` @@ -511,7 +522,7 @@ class BeaconState(Container): # Shuffling start_shard: Shard randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] - active_index_roots: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Active registry digests for light clients + compact_committee_roots: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Committee digests for light clients # Slashings slashed_balances: Vector[Gwei, EPOCHS_PER_SLASHED_BALANCES_VECTOR] # Sums of slashed effective balances # Attestations @@ -742,17 +753,23 @@ def get_randao_mix(state: BeaconState, return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] ``` -### `get_active_index_root` +### `get_compact_committee_root` ```python -def get_active_index_root(state: BeaconState, - epoch: Epoch) -> Hash: +def get_compact_committee_root(state: BeaconState, epoch: Epoch) -> Hash: """ - Return the index root at a recent ``epoch``. - ``epoch`` expected to be between - (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR + ACTIVATION_EXIT_DELAY, current_epoch + ACTIVATION_EXIT_DELAY]. + Return the compact committee root for the current epoch. """ - return state.active_index_roots[epoch % EPOCHS_PER_HISTORICAL_VECTOR] + committee_data = CompactCommitteees().data + for committee_number in range(get_epoch_committee_count(state, epoch)): + shard = (get_epoch_start_shard(state, epoch) + committee_number) % SHARD_COUNT + for index in get_crosslink_committee(state, epoch, shard): + validator = validators[index] + committee_data[shard].pubkeys.append(validator.pubkey) + # `index` (top 7 bytes) + `slashed` (8th bit) + `effective_balance` (bottom 7 bits) + compact_validator = index << 8 + validator.slashed << 7 + validator.effective_balance // GWEI_PER_ETH + committee_data[shard].compact_validators.append(compact_validator) + return hash_tree_root(committee_data) ``` ### `generate_seed` @@ -765,7 +782,7 @@ def generate_seed(state: BeaconState, """ return hash( get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + - get_active_index_root(state, epoch) + + get_compact_committee_root(state, epoch) + int_to_bytes(epoch, length=32) ) ``` @@ -973,7 +990,7 @@ def validate_indexed_attestation(state: BeaconState, indexed_attestation: Indexe # Verify no index has custody bit equal to 1 [to be removed in phase 1] assert len(bit_1_indices) == 0 # Verify max number of indices - assert len(bit_0_indices) + len(bit_1_indices) <= MAX_INDICES_PER_ATTESTATION + assert len(bit_0_indices) + len(bit_1_indices) <= MAX_VALIDATORS_PER_COMMITTEE # Verify index sets are disjoint assert len(set(bit_0_indices).intersection(bit_1_indices)) == 0 # Verify indices are sorted @@ -1173,12 +1190,9 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH - # Populate active_index_roots - genesis_active_index_root = hash_tree_root( - List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, GENESIS_EPOCH)) - ) + # Populate compact_committee_roots for index in range(EPOCHS_PER_HISTORICAL_VECTOR): - state.active_index_roots[index] = genesis_active_index_root + state.compact_committee_roots[index] = get_compact_committee_root(state, GENESIS_EPOCH) return state ``` @@ -1532,11 +1546,7 @@ def process_final_updates(state: BeaconState) -> None: state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT) # Set active index root index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % EPOCHS_PER_HISTORICAL_VECTOR - state.active_index_roots[index_root_position] = hash_tree_root( - List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT]( - get_active_validator_indices(state, Epoch(next_epoch + ACTIVATION_EXIT_DELAY)) - ) - ) + state.compact_committee_roots[index_root_position] = get_compact_committee_root(state, next_epoch + ACTIVATION_EXIT_DELAY) # Set total slashed balances state.slashed_balances[next_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] = ( state.slashed_balances[current_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] From ccda5082540a4cb7b7ab46de290ce29cb9e60d0f Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Wed, 26 Jun 2019 15:34:54 +0100 Subject: [PATCH 013/112] Fix deposit root, add min_genesis_time, per-block processing --- specs/core/0_beacon-chain.md | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8aa307d66..588c2d133 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -126,7 +126,7 @@ This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain. -At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of [validators](#dfn-validator). In the initial deployment phases of Ethereum 2.0, the only mechanism to become a [validator](#dfn-validator) is to make a one-way ETH transaction to a deposit contract on Ethereum 1.0. Activation as a [validator](#dfn-validator) happens when Ethereum 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior. +At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of [validators](#dfn-validator). In the initial deployment phases of Ethereum 2.0, the only mechanism to become a [validator](#dfn-validator) is to make a one-way ETH transaction to a deposit contract on Eth 1.0. Activation as a [validator](#dfn-validator) happens when Eth 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior. The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block and proof-of-stake votes for a beacon block. A sufficient number of attestations for the same shard block create a "crosslink", confirming the shard segment up to that shard block into the beacon chain. Crosslinks also serve as infrastructure for asynchronous cross-shard communication. @@ -136,7 +136,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. ## Terminology -* **Validator**—a registered participant in the beacon chain. You can become one by sending ether into the Ethereum 1.0 deposit contract. +* **Validator**—a registered participant in the beacon chain. You can become one by sending ether into the Eth 1.0 deposit contract. * **Active validator**—an active participant in the Ethereum 2.0 consensus invited to, among other things, propose and attest to blocks and vote for crosslinks. * **Committee**—a (pseudo-) randomly sampled subset of [active validators](#dfn-active-validator). When a committee is referred to collectively, as in "this committee attests to X", this is assumed to mean "some subset of that committee that contains enough [validators](#dfn-validator) that the protocol recognizes it as representing the committee". * **Proposer**—the [validator](#dfn-validator) that creates a beacon chain block. @@ -195,6 +195,7 @@ These configurations are updated for releases, but may be out of sync during `de | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `90` | | `GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | +| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | * For the safety of crosslinks `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) @@ -1130,31 +1131,34 @@ def slash_validator(state: BeaconState, ### Genesis trigger -Before genesis has been triggered and whenever the deposit contract emits a `Deposit` log, call the function `is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool` where: +Before genesis has been triggered and for every Eth 1.0 block call `is_genesis_trigger(deposits, time)` where: -* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log -* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log +* `deposits` is the list of all deposits up to the Eth 1.0 block, ordered chronologically +* `time` is the Unix time of the Eth 1.0 block -When `is_genesis_trigger(deposits, timestamp) is True` for the first time let: +When `is_genesis_trigger(deposits, time) is True` for the first time let: * `genesis_deposits = deposits` -* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` +* `genesis_time = time - time % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` * `genesis_eth1_data` be the object of type `Eth1Data` where: * `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits` * `genesis_eth1_data.deposit_count = len(genesis_deposits)` - * `genesis_eth1_data.block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` + * `genesis_eth1_data.block_hash` is the Eth 1.0 block hash that emitted the log for the last deposit in `deposits` *Note*: The function `is_genesis_trigger` has yet to be agreed by the community, and can be updated as necessary. We define the following testing placeholder: ```python -def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool: +def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], time: uint64) -> bool: + # Do not deploy too early + if time - time % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: + return False + # Initialize deposit root state = BeaconState() - for i in range(DEPOSIT_CONTRACT_TREE_DEPTH - 1): - state.eth1_data.deposit_root = hash(state.eth1_data.deposit_root + state.eth1_data.deposit_root) + state.eth1_data.deposit_root = hash_tree_root(map(deposits, lambda deposit: deposit.data)) # Process deposits - for deposit in deposits: + for deposit in deposits process_deposit(state, deposit) # Count active validators at genesis From b133dedeaf9d48695d407d9800a49d3b886ba8aa Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 26 Jun 2019 22:11:40 +0200 Subject: [PATCH 014/112] Eth1 data test --- .../eth2spec/test/sanity/test_blocks.py | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 286c0150c..27f0a884f 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -5,7 +5,7 @@ from eth2spec.utils.bls import bls_sign from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block # from eth2spec.test.helpers.transfers import get_valid_transfer -from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block +from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block from eth2spec.test.helpers.keys import privkeys, pubkeys from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing @@ -172,8 +172,6 @@ def test_attester_slashing(spec, state): ) -# TODO update functions below to be like above, i.e. with @spec_state_test and yielding data to put into the test vector - @with_all_phases @spec_state_test def test_deposit_in_block(spec, state): @@ -386,29 +384,43 @@ def test_historical_batch(spec, state): assert len(state.historical_roots) == pre_historical_roots_len + 1 -# @with_all_phases -# @spec_state_test -# def test_eth1_data_votes(spec, state): -# yield 'pre', state +@with_all_phases +@spec_state_test +def test_eth1_data_votes_success(spec, state): + # Don't run when it will take very, very long to simulate. Minimal configuration suffices. + if spec.SLOTS_PER_ETH1_VOTING_PERIOD > 16: + return -# expected_votes = 0 -# assert len(state.eth1_data_votes) == expected_votes + offset_block = build_empty_block(spec, state, slot=spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1) + state_transition_and_sign_block(spec, state, offset_block) + yield 'pre', state -# blocks = [] -# for _ in range(spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1): -# block = build_empty_block_for_next_slot(spec, state) -# state_transition_and_sign_block(spec, state, block) -# expected_votes += 1 -# assert len(state.eth1_data_votes) == expected_votes -# blocks.append(block) + a = b'\xaa' * 32 + b = b'\xbb' * 32 + c = b'\xcc' * 32 -# block = build_empty_block_for_next_slot(spec, state) -# blocks.append(block) + blocks = [] -# state_transition_and_sign_block(spec, state, block) + for i in range(0, spec.SLOTS_PER_ETH1_VOTING_PERIOD): + block = build_empty_block_for_next_slot(spec, state) + # wait for over 50% for A, then start voting B + block.body.eth1_data.block_hash = b if i * 2 > spec.SLOTS_PER_ETH1_VOTING_PERIOD else a + state_transition_and_sign_block(spec, state, block) + blocks.append(block) -# yield 'blocks', [block] -# yield 'post', state + assert len(state.eth1_data_votes) == spec.SLOTS_PER_ETH1_VOTING_PERIOD + assert state.eth1_data.block_hash == a -# assert state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0 -# assert len(state.eth1_data_votes) == 1 + # transition to next eth1 voting period + block = build_empty_block_for_next_slot(spec, state) + block.body.eth1_data.block_hash = c + state_transition_and_sign_block(spec, state, block) + blocks.append(block) + + yield 'blocks', blocks + yield 'post', state + + assert state.eth1_data.block_hash == a + assert state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0 + assert len(state.eth1_data_votes) == 1 + assert state.eth1_data_votes[0].block_hash == c From f54d1a56f7192be254a8d8d87b8f67a84758af7f Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 01:23:37 +0200 Subject: [PATCH 015/112] eth1 voting no consensus test --- .../eth2spec/test/sanity/test_blocks.py | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 27f0a884f..b11e41d66 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -4,7 +4,6 @@ from eth2spec.utils.ssz.ssz_impl import signing_root from eth2spec.utils.bls import bls_sign from eth2spec.test.helpers.state import get_balance, state_transition_and_sign_block -# from eth2spec.test.helpers.transfers import get_valid_transfer from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_empty_block, sign_block from eth2spec.test.helpers.keys import privkeys, pubkeys from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing @@ -386,7 +385,7 @@ def test_historical_batch(spec, state): @with_all_phases @spec_state_test -def test_eth1_data_votes_success(spec, state): +def test_eth1_data_votes_consensus(spec, state): # Don't run when it will take very, very long to simulate. Minimal configuration suffices. if spec.SLOTS_PER_ETH1_VOTING_PERIOD > 16: return @@ -424,3 +423,33 @@ def test_eth1_data_votes_success(spec, state): assert state.slot % spec.SLOTS_PER_ETH1_VOTING_PERIOD == 0 assert len(state.eth1_data_votes) == 1 assert state.eth1_data_votes[0].block_hash == c + + +@with_all_phases +@spec_state_test +def test_eth1_data_votes_no_consensus(spec, state): + # Don't run when it will take very, very long to simulate. Minimal configuration suffices. + if spec.SLOTS_PER_ETH1_VOTING_PERIOD > 16: + return + + offset_block = build_empty_block(spec, state, slot=spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1) + state_transition_and_sign_block(spec, state, offset_block) + yield 'pre', state + + a = b'\xaa' * 32 + b = b'\xbb' * 32 + + blocks = [] + + for i in range(0, spec.SLOTS_PER_ETH1_VOTING_PERIOD): + block = build_empty_block_for_next_slot(spec, state) + # wait for precisely 50% for A, then start voting B for other 50% + block.body.eth1_data.block_hash = b if i * 2 >= spec.SLOTS_PER_ETH1_VOTING_PERIOD else a + state_transition_and_sign_block(spec, state, block) + blocks.append(block) + + assert len(state.eth1_data_votes) == spec.SLOTS_PER_ETH1_VOTING_PERIOD + assert state.eth1_data.block_hash == b'\x00' * 32 + + yield 'blocks', blocks + yield 'post', state From 13b67b4cde6ddb762927ee78645ce38bd8538a76 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 01:46:26 +0200 Subject: [PATCH 016/112] sign blocks in eth1 vote tests --- test_libs/pyspec/eth2spec/test/sanity/test_blocks.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index b11e41d66..34409986e 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -373,6 +373,7 @@ def test_historical_batch(spec, state): yield 'pre', state block = build_empty_block_for_next_slot(spec, state, signed=True) + sign_block(spec, state, block) state_transition_and_sign_block(spec, state, block) yield 'blocks', [block] @@ -391,6 +392,7 @@ def test_eth1_data_votes_consensus(spec, state): return offset_block = build_empty_block(spec, state, slot=spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1) + sign_block(spec, state, offset_block) state_transition_and_sign_block(spec, state, offset_block) yield 'pre', state @@ -404,6 +406,7 @@ def test_eth1_data_votes_consensus(spec, state): block = build_empty_block_for_next_slot(spec, state) # wait for over 50% for A, then start voting B block.body.eth1_data.block_hash = b if i * 2 > spec.SLOTS_PER_ETH1_VOTING_PERIOD else a + sign_block(spec, state, block) state_transition_and_sign_block(spec, state, block) blocks.append(block) @@ -413,6 +416,7 @@ def test_eth1_data_votes_consensus(spec, state): # transition to next eth1 voting period block = build_empty_block_for_next_slot(spec, state) block.body.eth1_data.block_hash = c + sign_block(spec, state, block) state_transition_and_sign_block(spec, state, block) blocks.append(block) @@ -433,6 +437,7 @@ def test_eth1_data_votes_no_consensus(spec, state): return offset_block = build_empty_block(spec, state, slot=spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1) + sign_block(spec, state, offset_block) state_transition_and_sign_block(spec, state, offset_block) yield 'pre', state @@ -445,6 +450,7 @@ def test_eth1_data_votes_no_consensus(spec, state): block = build_empty_block_for_next_slot(spec, state) # wait for precisely 50% for A, then start voting B for other 50% block.body.eth1_data.block_hash = b if i * 2 >= spec.SLOTS_PER_ETH1_VOTING_PERIOD else a + sign_block(spec, state, block) state_transition_and_sign_block(spec, state, block) blocks.append(block) From 327953852d2034ebf6acf7eb7d39af84314b91b2 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 01:47:53 +0200 Subject: [PATCH 017/112] test invalid shard in attestation --- .../block_processing/test_process_attestation.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py index 2b34ab405..79af0b202 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py @@ -148,6 +148,20 @@ def test_wrong_shard(spec, state): yield from run_attestation_processing(spec, state, attestation, False) +@with_all_phases +@spec_state_test +def test_invalid_shard(spec, state): + attestation = get_valid_attestation(spec, state) + state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY + + # off by one (with respect to valid range) on purpose + attestation.data.crosslink.shard = spec.SHARD_COUNT + + sign_attestation(spec, state, attestation) + + yield from run_attestation_processing(spec, state, attestation, False) + + @with_all_phases @spec_state_test def test_new_source_epoch(spec, state): From f75e3dccb2041cec7884266a7a348decd1051074 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 02:03:43 +0200 Subject: [PATCH 018/112] test old and future target epoch in attestation --- .../test_process_attestation.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py index 79af0b202..59e99ac0c 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py @@ -162,6 +162,33 @@ def test_invalid_shard(spec, state): yield from run_attestation_processing(spec, state, attestation, False) +@with_all_phases +@spec_state_test +def test_old_target_epoch(spec, state): + assert spec.MIN_ATTESTATION_INCLUSION_DELAY < spec.SLOTS_PER_EPOCH * 2 + + attestation = get_valid_attestation(spec, state, signed=True) + + state.slot = spec.SLOTS_PER_EPOCH * 2 # target epoch will be too old to handle + + yield from run_attestation_processing(spec, state, attestation, False) + + +@with_all_phases +@spec_state_test +def test_future_target_epoch(spec, state): + assert spec.MIN_ATTESTATION_INCLUSION_DELAY < spec.SLOTS_PER_EPOCH * 2 + + attestation = get_valid_attestation(spec, state) + + state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY + + attestation.data.target_epoch = spec.get_current_epoch(state) + 1 # target epoch will be too new to handle + sign_attestation(spec, state, attestation) + + yield from run_attestation_processing(spec, state, attestation, False) + + @with_all_phases @spec_state_test def test_new_source_epoch(spec, state): From 64e15c524b569ce474406e1c6781d95495bcd53e Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 02:27:28 +0200 Subject: [PATCH 019/112] improve intersection test, just 1 index is enough. And add invalid att1/att2 tests --- .../test_process_attester_slashing.py | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py index c51f5a8a9..2d8f9d31a 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py @@ -142,12 +142,39 @@ def test_participants_already_slashed(spec, state): @with_all_phases @spec_state_test -def test_custody_bit_0_and_1(spec, state): +def test_custody_bit_0_and_1_intersect(spec, state): attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True) - attester_slashing.attestation_1.custody_bit_1_indices = ( - attester_slashing.attestation_1.custody_bit_0_indices + attester_slashing.attestation_1.custody_bit_1_indices.append( + attester_slashing.attestation_1.custody_bit_0_indices[0] ) + sign_indexed_attestation(spec, state, attester_slashing.attestation_1) yield from run_attester_slashing_processing(spec, state, attester_slashing, False) + + +@with_all_phases +@spec_state_test +def test_attester_slashing_invalid_att_1(spec, state): + attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True) + + indices = attester_slashing.attestation_1.custody_bit_0_indices + assert len(indices) >= 3 + indices[1], indices[2] = indices[2], indices[1] # unsort second and third index + sign_indexed_attestation(spec, state, attester_slashing.attestation_1) + + yield from run_attester_slashing_processing(spec, state, attester_slashing, False) + + +@with_all_phases +@spec_state_test +def test_attester_slashing_invalid_att_2(spec, state): + attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False) + + indices = attester_slashing.attestation_2.custody_bit_0_indices + assert len(indices) >= 3 + indices[1], indices[2] = indices[2], indices[1] # unsort second and third index + sign_indexed_attestation(spec, state, attester_slashing.attestation_2) + + yield from run_attester_slashing_processing(spec, state, attester_slashing, False) From 1d6b1cab13dc979f15e1e1bc5b50ae3c3585e795 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 02:37:20 +0200 Subject: [PATCH 020/112] expected deposit count test --- .../eth2spec/test/sanity/test_blocks.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 34409986e..bb6a6dc06 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -171,6 +171,28 @@ def test_attester_slashing(spec, state): ) +@with_all_phases +@spec_state_test +def test_expected_deposit_in_block(spec, state): + # Make the state expect a deposit, then don't provide it. + state.eth1_data.deposit_count += 1 + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + sign_block(spec, state, block) + bad = False + try: + state_transition_and_sign_block(spec, state, block) + bad = True + except AssertionError: + pass + if bad: + raise AssertionError("expected deposit was not enforced") + + yield 'blocks', [block] + yield 'post', None + + @with_all_phases @spec_state_test def test_deposit_in_block(spec, state): From 55d86b4f13afacf5fec4e48cb544cfd003c7cd31 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 02:48:40 +0200 Subject: [PATCH 021/112] effective balance testing in deposits --- .../block_processing/test_process_deposit.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py index 8b3d7b413..1d4b3a107 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py @@ -49,6 +49,11 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef assert len(state.balances) == pre_validator_count + 1 assert get_balance(state, validator_index) == pre_balance + deposit.data.amount + effective = min(spec.MAX_EFFECTIVE_BALANCE, + pre_balance + deposit.data.amount) + effective -= effective % spec.EFFECTIVE_BALANCE_INCREMENT + assert state.validators[validator_index].effective_balance == effective + assert state.eth1_deposit_index == state.eth1_data.deposit_count @@ -57,7 +62,20 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef def test_new_deposit(spec, state): # fresh deposit = next validator index = validator appended to registry validator_index = len(state.validators) - amount = spec.MAX_EFFECTIVE_BALANCE + # effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement. + amount = spec.MAX_EFFECTIVE_BALANCE - 1 + deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) + + yield from run_deposit_processing(spec, state, deposit, validator_index) + + +@with_all_phases +@spec_state_test +def test_new_deposit_maxed_out(spec, state): + # fresh deposit = next validator index = validator appended to registry + validator_index = len(state.validators) + # just 1 over the limit, effective balance should be set MAX_EFFECTIVE_BALANCE during processing + amount = spec.MAX_EFFECTIVE_BALANCE + 1 deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) yield from run_deposit_processing(spec, state, deposit, validator_index) From 063d94b9c7da65d076f563e243584fa0b8b9ab3d Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 25 Jun 2019 04:13:48 +0200 Subject: [PATCH 022/112] Bugfix transfer tests --- .../block_processing/test_process_transfer.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py index 89246cc51..45c161214 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py @@ -107,7 +107,7 @@ def test_active_but_transfer_past_effective_balance(spec, state): def test_incorrect_slot(spec, state): transfer = get_valid_transfer(spec, state, slot=state.slot + 1, signed=True) # un-activate so validator can transfer - state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -120,7 +120,7 @@ def test_insufficient_balance_for_fee_result_dust(spec, state): transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=0, fee=1, signed=True) # un-activate so validator can transfer - state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -146,7 +146,7 @@ def test_insufficient_balance_for_amount_result_dust(spec, state): transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0, signed=True) # un-activate so validator can transfer - state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -287,7 +287,7 @@ def test_no_dust_sender(spec, state): ) # un-activate so validator can transfer - state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -301,7 +301,7 @@ def test_no_dust_recipient(spec, state): state.balances[transfer.recipient] = 0 # un-activate so validator can transfer - state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) @@ -313,6 +313,6 @@ def test_invalid_pubkey(spec, state): state.validators[transfer.sender].withdrawal_credentials = spec.ZERO_HASH # un-activate so validator can transfer - state.validators[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH yield from run_transfer_processing(spec, state, transfer, False) From e79b47e3c3a24d54f341d3defb691707c0acfb73 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 22 Jun 2019 03:54:07 +0200 Subject: [PATCH 023/112] non-existent transfer participants tests --- .../pyspec/eth2spec/test/helpers/transfers.py | 6 ++-- .../block_processing/test_process_transfer.py | 34 +++++++++++++++---- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/helpers/transfers.py b/test_libs/pyspec/eth2spec/test/helpers/transfers.py index acc6a35c5..fa01a3088 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/transfers.py +++ b/test_libs/pyspec/eth2spec/test/helpers/transfers.py @@ -4,13 +4,15 @@ from eth2spec.utils.bls import bls_sign from eth2spec.utils.ssz.ssz_impl import signing_root -def get_valid_transfer(spec, state, slot=None, sender_index=None, amount=None, fee=None, signed=False): +def get_valid_transfer(spec, state, slot=None, sender_index=None, + recipient_index=None, amount=None, fee=None, signed=False): if slot is None: slot = state.slot current_epoch = spec.get_current_epoch(state) if sender_index is None: sender_index = spec.get_active_validator_indices(state, current_epoch)[-1] - recipient_index = spec.get_active_validator_indices(state, current_epoch)[0] + if recipient_index is None: + recipient_index = spec.get_active_validator_indices(state, current_epoch)[0] transfer_pubkey = pubkeys[-1] transfer_privkey = privkeys[-1] diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py index 45c161214..ad7e6ff60 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py @@ -1,7 +1,7 @@ from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases from eth2spec.test.helpers.state import next_epoch from eth2spec.test.helpers.block import apply_empty_block -from eth2spec.test.helpers.transfers import get_valid_transfer +from eth2spec.test.helpers.transfers import get_valid_transfer, sign_transfer def run_transfer_processing(spec, state, transfer, valid=True): @@ -13,11 +13,6 @@ def run_transfer_processing(spec, state, transfer, valid=True): If ``valid == False``, run expecting ``AssertionError`` """ - proposer_index = spec.get_beacon_proposer_index(state) - pre_transfer_sender_balance = state.balances[transfer.sender] - pre_transfer_recipient_balance = state.balances[transfer.recipient] - pre_transfer_proposer_balance = state.balances[proposer_index] - yield 'pre', state yield 'transfer', transfer @@ -26,6 +21,11 @@ def run_transfer_processing(spec, state, transfer, valid=True): yield 'post', None return + proposer_index = spec.get_beacon_proposer_index(state) + pre_transfer_sender_balance = state.balances[transfer.sender] + pre_transfer_recipient_balance = state.balances[transfer.recipient] + pre_transfer_proposer_balance = state.balances[proposer_index] + spec.process_transfer(state, transfer) yield 'post', state @@ -306,6 +306,28 @@ def test_no_dust_recipient(spec, state): yield from run_transfer_processing(spec, state, transfer, False) +@with_all_phases +@spec_state_test +def test_non_existent_sender(spec, state): + sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] + transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0) + transfer.sender = len(state.validators) + sign_transfer(spec, state, transfer, 42) # mostly valid signature, but sender won't exist, use bogus key. + + yield from run_transfer_processing(spec, state, transfer, False) + + +@with_all_phases +@spec_state_test +def test_non_existent_recipient(spec, state): + sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] + state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE + 1 + transfer = get_valid_transfer(spec, state, sender_index=sender_index, + recipient_index=len(state.validators), amount=1, fee=0, signed=True) + + yield from run_transfer_processing(spec, state, transfer, False) + + @with_all_phases @spec_state_test def test_invalid_pubkey(spec, state): From 6266133572494b606e12db1326fa2ac597c215af Mon Sep 17 00:00:00 2001 From: Diederik Loerakker Date: Tue, 25 Jun 2019 03:53:40 +0200 Subject: [PATCH 024/112] rename test methods based on suggestion Co-Authored-By: Danny Ryan --- .../block_processing/test_process_attester_slashing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py index 2d8f9d31a..86b6811a2 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py @@ -156,7 +156,7 @@ def test_custody_bit_0_and_1_intersect(spec, state): @with_all_phases @spec_state_test -def test_attester_slashing_invalid_att_1(spec, state): +def test_unsorted_att_1(spec, state): attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True) indices = attester_slashing.attestation_1.custody_bit_0_indices @@ -169,7 +169,7 @@ def test_attester_slashing_invalid_att_1(spec, state): @with_all_phases @spec_state_test -def test_attester_slashing_invalid_att_2(spec, state): +def test_unsorted_att_2(spec, state): attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False) indices = attester_slashing.attestation_2.custody_bit_0_indices From c4b88e68e1772bd2a88987f030113309dd4a9c4d Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 25 Jun 2019 04:19:02 +0200 Subject: [PATCH 025/112] different new-deposit tests --- .../block_processing/test_process_deposit.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py index 1d4b3a107..0f94bd26c 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py @@ -59,10 +59,10 @@ def run_deposit_processing(spec, state, deposit, validator_index, valid=True, ef @with_all_phases @spec_state_test -def test_new_deposit(spec, state): +def test_new_deposit_under_max(spec, state): # fresh deposit = next validator index = validator appended to registry validator_index = len(state.validators) - # effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement. + # effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement. amount = spec.MAX_EFFECTIVE_BALANCE - 1 deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) @@ -71,7 +71,19 @@ def test_new_deposit(spec, state): @with_all_phases @spec_state_test -def test_new_deposit_maxed_out(spec, state): +def test_new_deposit_max(spec, state): + # fresh deposit = next validator index = validator appended to registry + validator_index = len(state.validators) + # effective balance will be exactly the same as balance. + amount = spec.MAX_EFFECTIVE_BALANCE + deposit = prepare_state_and_deposit(spec, state, validator_index, amount, signed=True) + + yield from run_deposit_processing(spec, state, deposit, validator_index) + + +@with_all_phases +@spec_state_test +def test_new_deposit_over_max(spec, state): # fresh deposit = next validator index = validator appended to registry validator_index = len(state.validators) # just 1 over the limit, effective balance should be set MAX_EFFECTIVE_BALANCE during processing From b4b4e9571da32e6ff13cd550cb1308cfdf703919 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 25 Jun 2019 04:45:53 +0200 Subject: [PATCH 026/112] test activation queue --- .../test_process_registry_updates.py | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index d92220910..6c1319a5b 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -30,18 +30,20 @@ def run_process_registry_updates(spec, state, valid=True): yield 'post', state -@with_all_phases -@spec_state_test -def test_activation(spec, state): - index = 0 +def mock_deposit(spec, state, index): assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) - - # Mock a new deposit state.validators[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH state.validators[index].activation_epoch = spec.FAR_FUTURE_EPOCH state.validators[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE assert not spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) + +@with_all_phases +@spec_state_test +def test_activation(spec, state): + index = 0 + mock_deposit(spec, state, index) + for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): next_epoch(spec, state) @@ -49,10 +51,39 @@ def test_activation(spec, state): assert state.validators[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH assert state.validators[index].activation_epoch != spec.FAR_FUTURE_EPOCH - assert spec.is_active_validator( - state.validators[index], - spec.get_current_epoch(state), - ) + assert spec.is_active_validator(state.validators[index], spec.get_current_epoch(state)) + + +@with_all_phases +@spec_state_test +def test_activation_queue_sorting(spec, state): + mock_activations = 10 + + epoch = spec.get_current_epoch(state) + for i in range(mock_activations): + mock_deposit(spec, state, i) + state.validators[i].activation_eligibility_epoch = epoch + 1 + + # give the last priority over the others + state.validators[mock_activations - 1].activation_eligibility_epoch = epoch + + # make sure we are hitting the churn + churn_limit = spec.get_churn_limit(state) + assert mock_activations > churn_limit + + yield from run_process_registry_updates(spec, state) + + # the first got in as second + assert state.validators[0].activation_epoch != spec.FAR_FUTURE_EPOCH + # the prioritized got in as first + assert state.validators[mock_activations - 1].activation_epoch != spec.FAR_FUTURE_EPOCH + # the second last is at the end of the queue, and did not make the churn, + # hence is not assigned an activation_epoch yet. + assert state.validators[mock_activations - 2].activation_epoch == spec.FAR_FUTURE_EPOCH + # the one at churn_limit - 1 did not make it, it was out-prioritized + assert state.validators[churn_limit - 1].activation_epoch == spec.FAR_FUTURE_EPOCH + # but the the one in front of the above did + assert state.validators[churn_limit - 2].activation_epoch != spec.FAR_FUTURE_EPOCH @with_all_phases From 0e3c2cef5ca56e011ea1ec776e8eac6aa0884f3e Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 25 Jun 2019 15:45:57 +0200 Subject: [PATCH 027/112] fix transfer tests, add 2 new tests --- .../block_processing/test_process_transfer.py | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py index ad7e6ff60..6903f0666 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_transfer.py @@ -114,9 +114,37 @@ def test_incorrect_slot(spec, state): @with_all_phases @spec_state_test -def test_insufficient_balance_for_fee_result_dust(spec, state): +def test_transfer_clean(spec, state): sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] - state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE + state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT + transfer = get_valid_transfer(spec, state, sender_index=sender_index, + amount=spec.MIN_DEPOSIT_AMOUNT, fee=0, signed=True) + + # un-activate so validator can transfer + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH + + yield from run_transfer_processing(spec, state, transfer) + + +@with_all_phases +@spec_state_test +def test_transfer_clean_split_to_fee(spec, state): + sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] + state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT + transfer = get_valid_transfer(spec, state, sender_index=sender_index, + amount=spec.MIN_DEPOSIT_AMOUNT // 2, fee=spec.MIN_DEPOSIT_AMOUNT // 2, signed=True) + + # un-activate so validator can transfer + state.validators[transfer.sender].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH + + yield from run_transfer_processing(spec, state, transfer) + + +@with_all_phases +@spec_state_test +def test_insufficient_balance_for_fee(spec, state): + sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] + state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=0, fee=1, signed=True) # un-activate so validator can transfer @@ -142,7 +170,7 @@ def test_insufficient_balance_for_fee_result_full(spec, state): @spec_state_test def test_insufficient_balance_for_amount_result_dust(spec, state): sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1] - state.balances[sender_index] = spec.MAX_EFFECTIVE_BALANCE + state.balances[sender_index] = spec.MIN_DEPOSIT_AMOUNT transfer = get_valid_transfer(spec, state, sender_index=sender_index, amount=1, fee=0, signed=True) # un-activate so validator can transfer From b2034a54a07264553f7aad38b838cedd98ff64ec Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 25 Jun 2019 22:22:17 +0200 Subject: [PATCH 028/112] generalize epoch processing testing, add final-processing tests --- .../run_epoch_process_base.py | 44 +++++++++++++++ .../test_process_crosslinks.py | 30 ++--------- .../test_process_final_updates.py | 53 +++++++++++++++++++ .../test_process_registry_updates.py | 31 ++--------- 4 files changed, 105 insertions(+), 53 deletions(-) create mode 100644 test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py create mode 100644 test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py new file mode 100644 index 000000000..13e1c3f3b --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py @@ -0,0 +1,44 @@ +from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block +from eth2spec.test.helpers.state import state_transition_and_sign_block + + +process_calls = ( + 'process_justification_and_finalization' + 'process_crosslinks' + 'process_rewards_and_penalties' + 'process_registry_updates' + 'process_reveal_deadlines' + 'process_challenge_deadlines' + 'process_slashings' + 'process_final_updates' + 'after_process_final_updates' +) + + +def run_epoch_processing_to(spec, state, process_name: str): + """ + Run the epoch processing functions up to ``process_name`` (incl.), yielding: + - pre-state ('pre'), state before calling ``process_name`` + - post-state ('post'), state after calling ``process_name`` + """ + # transition state to slot before state transition + slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 + block = build_empty_block_for_next_slot(spec, state) + block.slot = slot + sign_block(spec, state, block) + state_transition_and_sign_block(spec, state, block) + + # cache state before epoch transition + spec.process_slot(state) + + # process components of epoch transition before final-updates + for name in process_calls: + if name == process_name: + break + # only run when present. Later phases introduce more to the epoch-processing. + if hasattr(spec, name): + getattr(spec, name)(state) + + yield 'pre', state + getattr(spec, process_name)(state) + yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py index d51191efb..a38435b96 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py @@ -4,41 +4,19 @@ from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.helpers.state import ( next_epoch, next_slot, - state_transition_and_sign_block, ) -from eth2spec.test.helpers.block import apply_empty_block, sign_block +from eth2spec.test.helpers.block import apply_empty_block from eth2spec.test.helpers.attestations import ( add_attestation_to_state, - build_empty_block_for_next_slot, fill_aggregate_attestation, get_valid_attestation, sign_attestation, ) +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_to -def run_process_crosslinks(spec, state, valid=True): - """ - Run ``process_crosslinks``, yielding: - - pre-state ('pre') - - post-state ('post'). - If ``valid == False``, run expecting ``AssertionError`` - """ - # transition state to slot before state transition - slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 - block = build_empty_block_for_next_slot(spec, state) - block.slot = slot - sign_block(spec, state, block) - state_transition_and_sign_block(spec, state, block) - - # cache state before epoch transition - spec.process_slot(state) - - # process components of epoch transition before processing crosslinks - spec.process_justification_and_finalization(state) - - yield 'pre', state - spec.process_crosslinks(state) - yield 'post', state +def run_process_crosslinks(spec, state): + yield from run_epoch_processing_to(spec, state, 'process_crosslinks') @with_all_phases diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py new file mode 100644 index 000000000..ca2f9eb10 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py @@ -0,0 +1,53 @@ +from eth2spec.test.context import spec_state_test, with_all_phases +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_to + + +def run_process_final_updates(spec, state): + yield from run_epoch_processing_to(spec, state, 'process_final_updates') + + +@with_all_phases +@spec_state_test +def test_eth1_vote_reset(spec, state): + # skip ahead to near the end of the voting period + state.slot = spec.SLOTS_PER_ETH1_VOTING_PERIOD - 2 + for i in range(state.slot + 1): # add a vote for each skipped slot. + state.eth1_data_votes.append( + spec.Eth1Data(deposit_root=b'\xaa' * 32, + deposit_count=state.eth1_deposit_index, + block_hash=b'\xbb' * 32)) + + yield from run_process_final_updates(spec, state) + + assert len(state.eth1_data_votes) == 0 + + +@with_all_phases +@spec_state_test +def test_effective_balance_hysteresis(spec, state): + # Set some edge cases for balances + max = spec.MAX_EFFECTIVE_BALANCE + min = spec.EJECTION_BALANCE + inc = spec.EFFECTIVE_BALANCE_INCREMENT + half_inc = inc // 2 + cases = [ + (max, max, max), # as is + (max, max - 1, max - inc), # round down, step lower + (max, max + 1, max), # round down + (max, max - inc, max - inc), # exactly 1 step lower + (max, max - inc - 1, max - (2 * inc)), # just 1 over 1 step lower + (max, max - inc + 1, max - inc), # close to 1 step lower + (min, min + (half_inc * 3), min), # bigger balance, but not high enough + (min, min + (half_inc * 3) + 1, min + inc), # bigger balance, high enough, but small step + (min, min + (half_inc * 4) - 1, min + inc), # bigger balance, high enough, close to double step + (min, min + (half_inc * 4), min + (2 * inc)), # exact two step balance increment + (min, min + (half_inc * 4) + 1, min + (2 * inc)), # over two steps, round down + ] + for i, (pre_eff, bal, _) in enumerate(cases): + state.validators[i].effective_balance = pre_eff + state.balances[i] = bal + + yield from run_process_final_updates(spec, state) + + for i, (_, _, post_eff) in enumerate(cases): + assert state.validators[i].effective_balance == post_eff diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index 6c1319a5b..ae76e95c2 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -1,33 +1,10 @@ -from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block -from eth2spec.test.helpers.state import next_epoch, state_transition_and_sign_block +from eth2spec.test.helpers.state import next_epoch from eth2spec.test.context import spec_state_test, with_all_phases +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_to -def run_process_registry_updates(spec, state, valid=True): - """ - Run ``process_crosslinks``, yielding: - - pre-state ('pre') - - post-state ('post'). - If ``valid == False``, run expecting ``AssertionError`` - """ - # transition state to slot before state transition - slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 - block = build_empty_block_for_next_slot(spec, state) - block.slot = slot - sign_block(spec, state, block) - state_transition_and_sign_block(spec, state, block) - - # cache state before epoch transition - spec.process_slot(state) - - # process components of epoch transition before registry update - spec.process_justification_and_finalization(state) - spec.process_crosslinks(state) - spec.process_rewards_and_penalties(state) - - yield 'pre', state - spec.process_registry_updates(state) - yield 'post', state +def run_process_registry_updates(spec, state): + yield from run_epoch_processing_to(spec, state, 'process_registry_updates') def mock_deposit(spec, state, index): From c4c9bd32e2af615bae95220c0c9e2492dc5ab67b Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 25 Jun 2019 22:26:35 +0200 Subject: [PATCH 029/112] test_eth1_vote_no_reset --- .../test_process_final_updates.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py index ca2f9eb10..0c19f8e31 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py @@ -6,6 +6,23 @@ def run_process_final_updates(spec, state): yield from run_epoch_processing_to(spec, state, 'process_final_updates') +@with_all_phases +@spec_state_test +def test_eth1_vote_no_reset(spec, state): + assert spec.SLOTS_PER_ETH1_VOTING_PERIOD > spec.SLOTS_PER_EPOCH + # skip ahead to near the end of the epoch + state.slot = spec.SLOTS_PER_EPOCH - 2 + for i in range(state.slot + 1): # add a vote for each skipped slot. + state.eth1_data_votes.append( + spec.Eth1Data(deposit_root=b'\xaa' * 32, + deposit_count=state.eth1_deposit_index, + block_hash=b'\xbb' * 32)) + + yield from run_process_final_updates(spec, state) + + assert len(state.eth1_data_votes) == spec.SLOTS_PER_EPOCH + + @with_all_phases @spec_state_test def test_eth1_vote_reset(spec, state): From aedd281edbcacfa68ff7ec91d4f3f2b0031a61c7 Mon Sep 17 00:00:00 2001 From: protolambda Date: Tue, 25 Jun 2019 23:18:19 +0200 Subject: [PATCH 030/112] clean up epoch processing testing --- .../run_epoch_process_base.py | 51 ++++++++--------- .../test_process_final_updates.py | 55 +++++++++++++------ 2 files changed, 60 insertions(+), 46 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py index 13e1c3f3b..7e0cffc79 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py @@ -1,35 +1,29 @@ -from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block -from eth2spec.test.helpers.state import state_transition_and_sign_block + +process_calls = [ + 'process_justification_and_finalization', + 'process_crosslinks', + 'process_rewards_and_penalties', + 'process_registry_updates', + 'process_reveal_deadlines', + 'process_challenge_deadlines', + 'process_slashings', + 'process_final_updates', + 'after_process_final_updates', +] -process_calls = ( - 'process_justification_and_finalization' - 'process_crosslinks' - 'process_rewards_and_penalties' - 'process_registry_updates' - 'process_reveal_deadlines' - 'process_challenge_deadlines' - 'process_slashings' - 'process_final_updates' - 'after_process_final_updates' -) - - -def run_epoch_processing_to(spec, state, process_name: str): +def run_epoch_processing_to(spec, state, process_name: str, exclusive=False): """ - Run the epoch processing functions up to ``process_name`` (incl.), yielding: + Run the epoch processing functions up to ``process_name``. + If ``exclusive`` is True, the process itself will not be ran. + If ``exclusive`` is False (default), this function yields: - pre-state ('pre'), state before calling ``process_name`` - post-state ('post'), state after calling ``process_name`` """ - # transition state to slot before state transition - slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 - block = build_empty_block_for_next_slot(spec, state) - block.slot = slot - sign_block(spec, state, block) - state_transition_and_sign_block(spec, state, block) + slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - # cache state before epoch transition - spec.process_slot(state) + # transition state to slot before epoch state transition + spec.process_slots(state, slot) # process components of epoch transition before final-updates for name in process_calls: @@ -39,6 +33,7 @@ def run_epoch_processing_to(spec, state, process_name: str): if hasattr(spec, name): getattr(spec, name)(state) - yield 'pre', state - getattr(spec, process_name)(state) - yield 'post', state + if not exclusive: + yield 'pre', state + getattr(spec, process_name)(state) + yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py index 0c19f8e31..d1af7d396 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py @@ -10,8 +10,8 @@ def run_process_final_updates(spec, state): @spec_state_test def test_eth1_vote_no_reset(spec, state): assert spec.SLOTS_PER_ETH1_VOTING_PERIOD > spec.SLOTS_PER_EPOCH - # skip ahead to near the end of the epoch - state.slot = spec.SLOTS_PER_EPOCH - 2 + # skip ahead to the end of the epoch + state.slot = spec.SLOTS_PER_EPOCH - 1 for i in range(state.slot + 1): # add a vote for each skipped slot. state.eth1_data_votes.append( spec.Eth1Data(deposit_root=b'\xaa' * 32, @@ -26,8 +26,8 @@ def test_eth1_vote_no_reset(spec, state): @with_all_phases @spec_state_test def test_eth1_vote_reset(spec, state): - # skip ahead to near the end of the voting period - state.slot = spec.SLOTS_PER_ETH1_VOTING_PERIOD - 2 + # skip ahead to the end of the voting period + state.slot = spec.SLOTS_PER_ETH1_VOTING_PERIOD - 1 for i in range(state.slot + 1): # add a vote for each skipped slot. state.eth1_data_votes.append( spec.Eth1Data(deposit_root=b'\xaa' * 32, @@ -42,29 +42,48 @@ def test_eth1_vote_reset(spec, state): @with_all_phases @spec_state_test def test_effective_balance_hysteresis(spec, state): + # Prepare state up to the final-updates. + # Then overwrite the balances, we only want to focus to be on the hysteresis based changes. + run_epoch_processing_to(spec, state, 'process_final_updates') # Set some edge cases for balances max = spec.MAX_EFFECTIVE_BALANCE min = spec.EJECTION_BALANCE inc = spec.EFFECTIVE_BALANCE_INCREMENT half_inc = inc // 2 cases = [ - (max, max, max), # as is - (max, max - 1, max - inc), # round down, step lower - (max, max + 1, max), # round down - (max, max - inc, max - inc), # exactly 1 step lower - (max, max - inc - 1, max - (2 * inc)), # just 1 over 1 step lower - (max, max - inc + 1, max - inc), # close to 1 step lower - (min, min + (half_inc * 3), min), # bigger balance, but not high enough - (min, min + (half_inc * 3) + 1, min + inc), # bigger balance, high enough, but small step - (min, min + (half_inc * 4) - 1, min + inc), # bigger balance, high enough, close to double step - (min, min + (half_inc * 4), min + (2 * inc)), # exact two step balance increment - (min, min + (half_inc * 4) + 1, min + (2 * inc)), # over two steps, round down + (max, max, max, "as-is"), + (max, max - 1, max - inc, "round down, step lower"), + (max, max + 1, max, "round down"), + (max, max - inc, max - inc, "exactly 1 step lower"), + (max, max - inc - 1, max - (2 * inc), "just 1 over 1 step lower"), + (max, max - inc + 1, max - inc, "close to 1 step lower"), + (min, min + (half_inc * 3), min, "bigger balance, but not high enough"), + (min, min + (half_inc * 3) + 1, min + inc, "bigger balance, high enough, but small step"), + (min, min + (half_inc * 4) - 1, min + inc, "bigger balance, high enough, close to double step"), + (min, min + (half_inc * 4), min + (2 * inc), "exact two step balance increment"), + (min, min + (half_inc * 4) + 1, min + (2 * inc), "over two steps, round down"), ] - for i, (pre_eff, bal, _) in enumerate(cases): + current_epoch = spec.get_current_epoch(state) + for i, (pre_eff, bal, _, _) in enumerate(cases): + assert spec.is_active_validator(state.validators[i], current_epoch) state.validators[i].effective_balance = pre_eff state.balances[i] = bal + yield 'pre', state + spec.process_final_updates(state) + yield 'post', state + + for i, (_, _, post_eff, name) in enumerate(cases): + assert state.validators[i].effective_balance == post_eff, name + + +@with_all_phases +@spec_state_test +def test_historical_root_accumulator(spec, state): + # skip ahead to near the end of the historical roots period (excl block before epoch processing) + state.slot = spec.SLOTS_PER_HISTORICAL_ROOT - 1 + history_len = len(state.historical_roots) + yield from run_process_final_updates(spec, state) - for i, (_, _, post_eff) in enumerate(cases): - assert state.validators[i].effective_balance == post_eff + assert len(state.historical_roots) == history_len + 1 From c66031f55cf4b24b832f917778730c0aaf8e99dd Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 26 Jun 2019 00:01:21 +0200 Subject: [PATCH 031/112] fix crosslink tests, fix generalization of epoch processing --- .../epoch_processing/run_epoch_process_base.py | 5 ++++- .../epoch_processing/test_process_crosslinks.py | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py index 7e0cffc79..c69160fb0 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py @@ -23,7 +23,10 @@ def run_epoch_processing_to(spec, state, process_name: str, exclusive=False): slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) # transition state to slot before epoch state transition - spec.process_slots(state, slot) + spec.process_slots(state, slot - 1) + + # start transitioning, do one slot update before the epoch itself. + spec.process_slot(state) # process components of epoch transition before final-updates for name in process_calls: diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py index a38435b96..7e93675e8 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py @@ -4,8 +4,8 @@ from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.helpers.state import ( next_epoch, next_slot, -) -from eth2spec.test.helpers.block import apply_empty_block + state_transition_and_sign_block) +from eth2spec.test.helpers.block import apply_empty_block, build_empty_block_for_next_slot, sign_block from eth2spec.test.helpers.attestations import ( add_attestation_to_state, fill_aggregate_attestation, @@ -28,6 +28,14 @@ def test_no_attestations(spec, state): assert state.previous_crosslinks[shard] == state.current_crosslinks[shard] +def add_block_to_end_of_epoch(spec, state): + slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 + block = build_empty_block_for_next_slot(spec, state) + block.slot = slot + sign_block(spec, state, block) + state_transition_and_sign_block(spec, state, block) + + @with_all_phases @spec_state_test def test_single_crosslink_update_from_current_epoch(spec, state): @@ -43,6 +51,7 @@ def test_single_crosslink_update_from_current_epoch(spec, state): shard = attestation.data.crosslink.shard pre_crosslink = deepcopy(state.current_crosslinks[shard]) + add_block_to_end_of_epoch(spec, state) yield from run_process_crosslinks(spec, state) assert state.previous_crosslinks[shard] != state.current_crosslinks[shard] @@ -66,6 +75,7 @@ def test_single_crosslink_update_from_previous_epoch(spec, state): crosslink_deltas = spec.get_crosslink_deltas(state) + add_block_to_end_of_epoch(spec, state) yield from run_process_crosslinks(spec, state) assert state.previous_crosslinks[shard] != state.current_crosslinks[shard] From 46dc3f39bb4c7d01c4e059c69de437983ac20262 Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 26 Jun 2019 00:22:24 +0200 Subject: [PATCH 032/112] detach crosslink tests from extra block --- .../epoch_processing/test_process_crosslinks.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py index 7e93675e8..058c93733 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py @@ -3,9 +3,9 @@ from copy import deepcopy from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.helpers.state import ( next_epoch, - next_slot, - state_transition_and_sign_block) -from eth2spec.test.helpers.block import apply_empty_block, build_empty_block_for_next_slot, sign_block + next_slot +) +from eth2spec.test.helpers.block import apply_empty_block from eth2spec.test.helpers.attestations import ( add_attestation_to_state, fill_aggregate_attestation, @@ -28,14 +28,6 @@ def test_no_attestations(spec, state): assert state.previous_crosslinks[shard] == state.current_crosslinks[shard] -def add_block_to_end_of_epoch(spec, state): - slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) - 1 - block = build_empty_block_for_next_slot(spec, state) - block.slot = slot - sign_block(spec, state, block) - state_transition_and_sign_block(spec, state, block) - - @with_all_phases @spec_state_test def test_single_crosslink_update_from_current_epoch(spec, state): @@ -51,7 +43,6 @@ def test_single_crosslink_update_from_current_epoch(spec, state): shard = attestation.data.crosslink.shard pre_crosslink = deepcopy(state.current_crosslinks[shard]) - add_block_to_end_of_epoch(spec, state) yield from run_process_crosslinks(spec, state) assert state.previous_crosslinks[shard] != state.current_crosslinks[shard] @@ -75,7 +66,6 @@ def test_single_crosslink_update_from_previous_epoch(spec, state): crosslink_deltas = spec.get_crosslink_deltas(state) - add_block_to_end_of_epoch(spec, state) yield from run_process_crosslinks(spec, state) assert state.previous_crosslinks[shard] != state.current_crosslinks[shard] From 24aa0646c095cb2ef6060345a2813991be9e94cc Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 26 Jun 2019 03:17:46 +0200 Subject: [PATCH 033/112] new process-slashings tests, and epoch processing bugfix with transition-to-excl not working when not yielded from --- .../run_epoch_process_base.py | 23 ++-- .../test_process_crosslinks.py | 4 +- .../test_process_final_updates.py | 6 +- .../test_process_registry_updates.py | 4 +- .../test_process_slashings.py | 121 ++++++++++++++++++ 5 files changed, 142 insertions(+), 16 deletions(-) create mode 100644 test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py index c69160fb0..5b2a2ece4 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/run_epoch_process_base.py @@ -12,13 +12,9 @@ process_calls = [ ] -def run_epoch_processing_to(spec, state, process_name: str, exclusive=False): +def run_epoch_processing_to(spec, state, process_name: str): """ - Run the epoch processing functions up to ``process_name``. - If ``exclusive`` is True, the process itself will not be ran. - If ``exclusive`` is False (default), this function yields: - - pre-state ('pre'), state before calling ``process_name`` - - post-state ('post'), state after calling ``process_name`` + Processes to the next epoch transition, up to, but not including, the sub-transition named ``process_name`` """ slot = state.slot + (spec.SLOTS_PER_EPOCH - state.slot % spec.SLOTS_PER_EPOCH) @@ -36,7 +32,14 @@ def run_epoch_processing_to(spec, state, process_name: str, exclusive=False): if hasattr(spec, name): getattr(spec, name)(state) - if not exclusive: - yield 'pre', state - getattr(spec, process_name)(state) - yield 'post', state + +def run_epoch_processing_with(spec, state, process_name: str): + """ + Processes to the next epoch transition, up to and including the sub-transition named ``process_name`` + - pre-state ('pre'), state before calling ``process_name`` + - post-state ('post'), state after calling ``process_name`` + """ + run_epoch_processing_to(spec, state, process_name) + yield 'pre', state + getattr(spec, process_name)(state) + yield 'post', state diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py index 058c93733..599fde8e7 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_crosslinks.py @@ -12,11 +12,11 @@ from eth2spec.test.helpers.attestations import ( get_valid_attestation, sign_attestation, ) -from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_to +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with def run_process_crosslinks(spec, state): - yield from run_epoch_processing_to(spec, state, 'process_crosslinks') + yield from run_epoch_processing_with(spec, state, 'process_crosslinks') @with_all_phases diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py index d1af7d396..58882a44f 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_final_updates.py @@ -1,9 +1,11 @@ from eth2spec.test.context import spec_state_test, with_all_phases -from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_to +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import ( + run_epoch_processing_with, run_epoch_processing_to +) def run_process_final_updates(spec, state): - yield from run_epoch_processing_to(spec, state, 'process_final_updates') + yield from run_epoch_processing_with(spec, state, 'process_final_updates') @with_all_phases diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py index ae76e95c2..19500d4ab 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_registry_updates.py @@ -1,10 +1,10 @@ from eth2spec.test.helpers.state import next_epoch from eth2spec.test.context import spec_state_test, with_all_phases -from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_to +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import run_epoch_processing_with def run_process_registry_updates(spec, state): - yield from run_epoch_processing_to(spec, state, 'process_registry_updates') + yield from run_epoch_processing_with(spec, state, 'process_registry_updates') def mock_deposit(spec, state, index): diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py new file mode 100644 index 000000000..f1a23326b --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py @@ -0,0 +1,121 @@ +from eth2spec.test.context import spec_state_test, with_all_phases +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import ( + run_epoch_processing_with, run_epoch_processing_to +) + + +def run_process_slashings(spec, state): + yield from run_epoch_processing_with(spec, state, 'process_slashings') + + +def slash_validators(spec, state, indices, out_epochs): + total_slashed_balance = 0 + for i, out_epoch in zip(indices, out_epochs): + v = state.validators[i] + v.slashed = True + spec.initiate_validator_exit(state, i) + v.withdrawable_epoch = out_epoch + total_slashed_balance += v.effective_balance + + state.slashed_balances[ + spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR + ] = total_slashed_balance + + +@with_all_phases +@spec_state_test +def test_max_penalties(spec, state): + slashed_count = (len(state.validators) // 3) + 1 + out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2) + + slashed_indices = list(range(slashed_count)) + slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count) + + total_balance = spec.get_total_active_balance(state) + total_penalties = state.slashed_balances[spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR] + + assert total_balance // 3 <= total_penalties + + yield from run_process_slashings(spec, state) + + for i in slashed_indices: + assert state.balances[i] == 0 + + +@with_all_phases +@spec_state_test +def test_min_penalties(spec, state): + # run_epoch_processing_to(spec, state, 'process_slashings', exclusive=True) + + # Just the bare minimum for this one validator + pre_balance = state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE + # All the other validators get the maximum. + for i in range(1, len(state.validators)): + state.validators[i].effective_balance = state.balances[i] = spec.MAX_EFFECTIVE_BALANCE + + out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2) + + slash_validators(spec, state, [0], [out_epoch]) + + total_balance = spec.get_total_active_balance(state) + total_penalties = state.slashed_balances[spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR] + + # we are testing the minimum here, i.e. get slashed (effective_balance / MIN_SLASHING_PENALTY_QUOTIENT) + assert total_penalties * 3 / total_balance < 1 / spec.MIN_SLASHING_PENALTY_QUOTIENT + + yield from run_process_slashings(spec, state) + + assert state.balances[0] == pre_balance - (pre_balance // spec.MIN_SLASHING_PENALTY_QUOTIENT) + + +@with_all_phases +@spec_state_test +def test_scaled_penalties(spec, state): + # skip to next epoch + state.slot = spec.SLOTS_PER_EPOCH + + # Also mock some previous slashings, so that we test to have the delta in the penalties computation. + for i in range(spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR): + state.slashed_balances[i] = spec.MAX_EFFECTIVE_BALANCE * 3 + + # Mock the very last one (which is to be used for the delta balance computation) to be different. + # To enforce the client test runner to correctly get this one from the array, not the others. + prev_penalties = state.slashed_balances[ + (spec.get_current_epoch(state) + 1) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR + ] = spec.MAX_EFFECTIVE_BALANCE * 2 + + slashed_count = len(state.validators) // 4 + + assert slashed_count > 10 + + # make the balances non-uniform. + # Otherwise it would just be a simple 3/4 balance slashing. Test the per-validator scaled penalties. + for i in range(10): + state.validators[i].effective_balance += spec.EFFECTIVE_BALANCE_INCREMENT * 4 + state.balances[i] += spec.EFFECTIVE_BALANCE_INCREMENT * 4 + + total_balance = spec.get_total_active_balance(state) + + out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2) + + slashed_indices = list(range(slashed_count)) + + # Process up to the sub-transition, then Hi-jack and get the balances. + # We just want to test the slashings. + # But we are not interested in the other balance changes during the same epoch transition. + run_epoch_processing_to(spec, state, 'process_slashings') + pre_slash_balances = list(state.balances) + + slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count) + + yield 'pre', state + spec.process_slashings(state) + yield 'post', state + + total_penalties = state.slashed_balances[spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR] + total_penalties -= prev_penalties + + for i in slashed_indices: + v = state.validators[i] + penalty = v.effective_balance * total_penalties * 3 // total_balance + assert state.balances[i] == pre_slash_balances[i] - penalty From 7a418ed682fc3edd4d2693c4084f0e0eb2ea5130 Mon Sep 17 00:00:00 2001 From: protolambda Date: Wed, 26 Jun 2019 23:40:56 +0200 Subject: [PATCH 034/112] test messed up indices in attester slashings --- .../test_process_attester_slashing.py | 72 ++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py index 86b6811a2..226d4a561 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py @@ -154,9 +154,73 @@ def test_custody_bit_0_and_1_intersect(spec, state): yield from run_attester_slashing_processing(spec, state, attester_slashing, False) +@always_bls @with_all_phases @spec_state_test -def test_unsorted_att_1(spec, state): +def test_att1_bad_extra_index(spec, state): + attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True) + + indices = attester_slashing.attestation_1.custody_bit_0_indices + options = list(set(range(len(state.validators))) - set(indices)) + indices.append(options[len(options) // 2]) # add random index, not previously in attestation. + attester_slashing.attestation_1.custody_bit_0_indices = sorted(indices) + # Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not), + # see if the bad extra index is spotted, and slashing is aborted. + + yield from run_attester_slashing_processing(spec, state, attester_slashing, False) + + +@always_bls +@with_all_phases +@spec_state_test +def test_att1_bad_replaced_index(spec, state): + attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True) + + indices = attester_slashing.attestation_1.custody_bit_0_indices + options = list(set(range(len(state.validators))) - set(indices)) + indices[3] = options[len(options) // 2] # replace with random index, not previously in attestation. + attester_slashing.attestation_1.custody_bit_0_indices = sorted(indices) + # Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not), + # see if the bad replaced index is spotted, and slashing is aborted. + + yield from run_attester_slashing_processing(spec, state, attester_slashing, False) + + +@always_bls +@with_all_phases +@spec_state_test +def test_att2_bad_extra_index(spec, state): + attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True) + + indices = attester_slashing.attestation_2.custody_bit_0_indices + options = list(set(range(len(state.validators))) - set(indices)) + indices.append(options[len(options) // 2]) # add random index, not previously in attestation. + attester_slashing.attestation_2.custody_bit_0_indices = sorted(indices) + # Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not), + # see if the bad extra index is spotted, and slashing is aborted. + + yield from run_attester_slashing_processing(spec, state, attester_slashing, False) + + +@always_bls +@with_all_phases +@spec_state_test +def test_att2_bad_replaced_index(spec, state): + attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=True) + + indices = attester_slashing.attestation_2.custody_bit_0_indices + options = list(set(range(len(state.validators))) - set(indices)) + indices[3] = options[len(options) // 2] # replace with random index, not previously in attestation. + attester_slashing.attestation_2.custody_bit_0_indices = sorted(indices) + # Do not sign the modified attestation (it's ok to slash if attester signed, not if they did not), + # see if the bad replaced index is spotted, and slashing is aborted. + + yield from run_attester_slashing_processing(spec, state, attester_slashing, False) + + +@with_all_phases +@spec_state_test +def test_unsorted_att_1_bit0(spec, state): attester_slashing = get_valid_attester_slashing(spec, state, signed_1=False, signed_2=True) indices = attester_slashing.attestation_1.custody_bit_0_indices @@ -169,7 +233,7 @@ def test_unsorted_att_1(spec, state): @with_all_phases @spec_state_test -def test_unsorted_att_2(spec, state): +def test_unsorted_att_2_bit0(spec, state): attester_slashing = get_valid_attester_slashing(spec, state, signed_1=True, signed_2=False) indices = attester_slashing.attestation_2.custody_bit_0_indices @@ -178,3 +242,7 @@ def test_unsorted_att_2(spec, state): sign_indexed_attestation(spec, state, attester_slashing.attestation_2) yield from run_attester_slashing_processing(spec, state, attester_slashing, False) + + +# note: unsorted indices for custody bit 0 are to be introduced in phase 1 testing. + From 10e257490fc57e3fd335ac352d62abbd7a98ce68 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 26 Jun 2019 16:33:23 -0600 Subject: [PATCH 035/112] Clarify `get_randao_mix` accessor We avoid a genesis underflow by taking the randao epoch in `generate_seed` to be `+ EPOCHS_PER_HISTORICAL_VECTOR`. This conflicts with the expected epoch bounds noted in `get_randao_mix` and this PR attempts to clarify the situation by leaving a note. --- specs/core/0_beacon-chain.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 264c6d23b..31fb7c1db 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -737,7 +737,7 @@ def get_randao_mix(state: BeaconState, epoch: Epoch) -> Hash: """ Return the randao mix at a recent ``epoch``. - ``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch]. + ``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch], unless otherwise noted at a call site. """ return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] ``` @@ -762,6 +762,8 @@ def generate_seed(state: BeaconState, epoch: Epoch) -> Hash: """ Generate a seed for the given ``epoch``. + + Note that avoiding the underflow on ``get_randao_mix`` here violates the epoch validity condition given in that function's comment. """ return hash( get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + From ff2d711d51ccccff9ad60d6ef6f54c9a379d0d84 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 27 Jun 2019 00:35:01 +0200 Subject: [PATCH 036/112] test block application on same and on previous slot state --- .../eth2spec/test/sanity/test_blocks.py | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index bb6a6dc06..8150b06f6 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -11,7 +11,39 @@ from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing from eth2spec.test.helpers.attestations import get_valid_attestation from eth2spec.test.helpers.deposits import prepare_state_and_deposit -from eth2spec.test.context import spec_state_test, with_all_phases +from eth2spec.test.context import spec_state_test, with_all_phases, expect_assertion_error + + +@with_all_phases +@spec_state_test +def test_prev_slot_block_transition(spec, state): + # Go to clean slot + spec.process_slots(state, state.slot + 1) + # Make a block for it + block = build_empty_block(spec, state, slot=state.slot, signed=True) + # Transition to next slot, above block will not be invalid on top of new state. + spec.process_slots(state, state.slot + 1) + + yield 'pre', state + expect_assertion_error(lambda: state_transition_and_sign_block(spec, state, block)) + yield 'blocks', [block] + yield 'post', None + + +@with_all_phases +@spec_state_test +def test_same_slot_block_transition(spec, state): + # Same slot on top of pre-state, but move out of slot 0 first. + spec.process_slots(state, state.slot + 1) + + block = build_empty_block(spec, state, slot=state.slot, signed=True) + + yield 'pre', state + + state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [block] + yield 'post', state @with_all_phases From 8445d1d90c05a29bcc8158ca6c7e9c7754b2df2c Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 27 Jun 2019 00:37:32 +0200 Subject: [PATCH 037/112] fix formatting for lint --- .../phase_0/block_processing/test_process_attester_slashing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py index 226d4a561..7fcbd2da5 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attester_slashing.py @@ -245,4 +245,3 @@ def test_unsorted_att_2_bit0(spec, state): # note: unsorted indices for custody bit 0 are to be introduced in phase 1 testing. - From f7b3c87715dae19119ba6b2e6d27dcc8b54d9af8 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 27 Jun 2019 00:43:50 +0200 Subject: [PATCH 038/112] check invalid state root --- .../pyspec/eth2spec/test/sanity/test_blocks.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 8150b06f6..0a879dac6 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -66,6 +66,22 @@ def test_empty_block_transition(spec, state): assert spec.get_randao_mix(state, spec.get_current_epoch(state)) != spec.ZERO_HASH +@with_all_phases +@spec_state_test +def test_invalid_state_root(spec, state): + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + block.state_root = b"\xaa" * 32 + sign_block(spec, state, block) + + expect_assertion_error( + lambda: spec.state_transition(state, block, validate_state_root=True)) + + yield 'blocks', [block] + yield 'post', None + + @with_all_phases @spec_state_test def test_skipped_slots(spec, state): From 235c3d6841d5a29895ea0c9465fd447f5338b92e Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 27 Jun 2019 00:58:25 +0200 Subject: [PATCH 039/112] re-enable test_empty_epoch_transition_not_finalizing for minimal config --- .../eth2spec/test/sanity/test_blocks.py | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 0a879dac6..e56baee8c 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -123,26 +123,29 @@ def test_empty_epoch_transition(spec, state): assert spec.get_block_root_at_slot(state, slot) == block.parent_root -# @with_all_phases -# @spec_state_test -# def test_empty_epoch_transition_not_finalizing(spec, state): -# # copy for later balance lookups. -# pre_state = deepcopy(state) -# yield 'pre', state +@with_all_phases +@spec_state_test +def test_empty_epoch_transition_not_finalizing(spec, state): + # Don't run for non-minimal configs, it takes very long, and the effect + # of calling finalization/justifcation is just the same as with the minimal configuration. + if spec.SLOTS_PER_EPOCH > 8: + return -# block = build_empty_block_for_next_slot(spec, state) -# block.slot += spec.SLOTS_PER_EPOCH * 5 -# sign_block(spec, state, block, proposer_index=0) + # copy for later balance lookups. + pre_balances = list(state.balances) + yield 'pre', state -# state_transition_and_sign_block(spec, state, block) + spec.process_slots(state, state.slot + (spec.SLOTS_PER_EPOCH * 5)) + block = build_empty_block_for_next_slot(spec, state, signed=True) + state_transition_and_sign_block(spec, state, block) -# yield 'blocks', [block] -# yield 'post', state + yield 'blocks', [block] + yield 'post', state -# assert state.slot == block.slot -# assert state.finalized_epoch < spec.get_current_epoch(state) - 4 -# for index in range(len(state.validators)): -# assert get_balance(state, index) < get_balance(pre_state, index) + assert state.slot == block.slot + assert state.finalized_epoch < spec.get_current_epoch(state) - 4 + for index in range(len(state.validators)): + assert state.balances[index] < pre_balances[index] @with_all_phases From 23909ca72760b002c25278de9817ae26164c67d4 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 26 Jun 2019 17:06:34 -0600 Subject: [PATCH 040/112] Fix line lengths --- specs/core/0_beacon-chain.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 31fb7c1db..6f7a7a059 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -737,7 +737,8 @@ def get_randao_mix(state: BeaconState, epoch: Epoch) -> Hash: """ Return the randao mix at a recent ``epoch``. - ``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch], unless otherwise noted at a call site. + ``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch], unless + otherwise noted at a call site. """ return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] ``` @@ -763,7 +764,8 @@ def generate_seed(state: BeaconState, """ Generate a seed for the given ``epoch``. - Note that avoiding the underflow on ``get_randao_mix`` here violates the epoch validity condition given in that function's comment. + Note that avoiding the underflow on ``get_randao_mix`` here violates + the epoch validity condition given in that function's comment. """ return hash( get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + From aecaed7a662ffc7ad73b098b1834840b725fe76d Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 27 Jun 2019 01:47:15 +0200 Subject: [PATCH 041/112] move genesis tests, structure properly, add yield keys for future test-vec generator --- .../pyspec/eth2spec/test/genesis/__init__.py | 0 .../eth2spec/test/genesis/test_genesis.py | 37 ++++++++ .../test/genesis/test_genesis_trigger.py | 54 ++++++++++++ .../eth2spec/test/sanity/test_genesis.py | 87 ------------------- 4 files changed, 91 insertions(+), 87 deletions(-) create mode 100644 test_libs/pyspec/eth2spec/test/genesis/__init__.py create mode 100644 test_libs/pyspec/eth2spec/test/genesis/test_genesis.py create mode 100644 test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py delete mode 100644 test_libs/pyspec/eth2spec/test/sanity/test_genesis.py diff --git a/test_libs/pyspec/eth2spec/test/genesis/__init__.py b/test_libs/pyspec/eth2spec/test/genesis/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py new file mode 100644 index 000000000..a89ec8793 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py @@ -0,0 +1,37 @@ +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_genesis(spec): + deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) + genesis_time = 1546300800 + block_hash = b'\x12' * 32 + + yield "deposits", genesis_deposits + yield "time", genesis_time + + genesis_eth1_data = spec.Eth1Data( + deposit_root=deposit_root, + deposit_count=deposit_count, + block_hash=block_hash, + ) + + yield "eth1_data", genesis_eth1_data + genesis_state = spec.get_genesis_beacon_state( + genesis_deposits, + genesis_time, + genesis_eth1_data, + ) + + assert genesis_state.genesis_time == genesis_time + 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 == 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 new file mode 100644 index 000000000..873638dc9 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py @@ -0,0 +1,54 @@ +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, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) + genesis_time = 1546300800 + + yield "deposits", genesis_deposits + yield "time", genesis_time + yield "deposit_root", deposit_root + + 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.GENESIS_ACTIVE_VALIDATOR_COUNT + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) + genesis_time = 1546300800 + + yield "deposits", genesis_deposits + yield "time", genesis_time + yield "deposit_root", deposit_root + + 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.GENESIS_ACTIVE_VALIDATOR_COUNT + genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) + genesis_time = 1546300800 + yield "deposits", genesis_deposits + yield "time", genesis_time + yield "deposit_root", deposit_root + + 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/sanity/test_genesis.py b/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py deleted file mode 100644 index 780d039eb..000000000 --- a/test_libs/pyspec/eth2spec/test/sanity/test_genesis.py +++ /dev/null @@ -1,87 +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, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1546300800 - - yield genesis_deposits - yield genesis_time - yield deposit_root - - is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) - assert is_triggered is False - - yield is_triggered - - -@with_phases(['phase0']) -@spectest_with_bls_switch -def test_is_genesis_trigger_true(spec): - deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1546300800 - - yield genesis_deposits - yield genesis_time - yield deposit_root - - is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) - assert is_triggered is True - - yield is_triggered - - -@with_phases(['phase0']) -@spectest_with_bls_switch -def test_is_genesis_trigger_not_enough_balance(spec): - deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) - genesis_time = 1546300800 - yield genesis_deposits - yield genesis_time - yield deposit_root - - is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time, deposit_root) - assert is_triggered is False - - yield is_triggered - - -@with_phases(['phase0']) -@spectest_with_bls_switch -def test_genesis(spec): - deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1546300800 - block_hash = b'\x12' * 32 - - yield genesis_deposits - yield genesis_time - - genesis_eth1_data = spec.Eth1Data( - deposit_root=deposit_root, - deposit_count=deposit_count, - block_hash=block_hash, - ) - - yield genesis_eth1_data - genesis_state = spec.get_genesis_beacon_state( - genesis_deposits, - genesis_time, - genesis_eth1_data, - ) - - assert genesis_state.genesis_time == genesis_time - 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 == block_hash - - yield genesis_state From a0c2f5c6b5578d3ee09b155fb487ab739e22195a Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 27 Jun 2019 01:57:30 +0200 Subject: [PATCH 042/112] fix genesis testing code, add missing constant temporarily, fix py Generator/map/list problems --- specs/core/0_beacon-chain.md | 6 ++++-- .../pyspec/eth2spec/test/genesis/test_genesis_trigger.py | 3 ++- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index b0490cba5..1ff1d58b3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1137,14 +1137,16 @@ When `is_genesis_trigger(deposits, time) is True` for the first time let: ```python def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], time: uint64) -> bool: + SECONDS_PER_DAY = 86400 # Do not deploy too early if time - time % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: return False # Initialize deposit root state = BeaconState() - state.eth1_data.deposit_root = hash_tree_root(map(deposits, lambda deposit: deposit.data)) - + state.eth1_data.deposit_root = hash_tree_root( + Vector[DepositData, len(deposits)](list(map(lambda deposit: deposit.data, deposits))) + ) # Process deposits for deposit in deposits: process_deposit(state, deposit) diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py index 873638dc9..9425a1750 100644 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py @@ -26,7 +26,8 @@ def test_is_genesis_trigger_false(spec): def test_is_genesis_trigger_true(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1546300800 + SECONDS_PER_DAY = 86400 + genesis_time = 1578009600 - 2 * SECONDS_PER_DAY yield "deposits", genesis_deposits yield "time", genesis_time diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index eea019e8b..bda4f1699 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -82,7 +82,7 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) root = get_merkle_root((tuple(deposit_data_leaves))) - genesis_deposits = ( + genesis_deposits = list( spec.Deposit(proof=list(get_merkle_proof(tree, item_index=index)), data=deposit_data) for index, deposit_data in enumerate(genesis_deposit_data_list) ) From e49519a53b5c1492fc39978316edafeef88769d3 Mon Sep 17 00:00:00 2001 From: protolambda Date: Thu, 27 Jun 2019 02:50:49 +0200 Subject: [PATCH 043/112] wrong end epoch test --- .../test_process_attestation.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py index 59e99ac0c..daac7efed 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py @@ -85,6 +85,29 @@ def test_success_since_max_epochs_per_crosslink(spec, state): yield from run_attestation_processing(spec, state, attestation) +@with_all_phases +@spec_state_test +def test_wrong_end_epoch_with_max_epochs_per_crosslink(spec, state): + for _ in range(spec.MAX_EPOCHS_PER_CROSSLINK + 2): + next_epoch(spec, state) + apply_empty_block(spec, state) + + attestation = get_valid_attestation(spec, state) + data = attestation.data + # test logic sanity check: make sure the attestation only includes MAX_EPOCHS_PER_CROSSLINK epochs + assert data.crosslink.end_epoch - data.crosslink.start_epoch == spec.MAX_EPOCHS_PER_CROSSLINK + # Now change it to be different + data.crosslink.end_epoch += 1 + + sign_attestation(spec, state, attestation) + + for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY): + next_slot(spec, state) + apply_empty_block(spec, state) + + yield from run_attestation_processing(spec, state, attestation, False) + + @with_all_phases @always_bls @spec_state_test From bcfe383e2555ee14261c995044ee3cf503432297 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Thu, 27 Jun 2019 08:44:44 +0100 Subject: [PATCH 044/112] WIP --- configs/constant_presets/mainnet.yaml | 2 +- configs/constant_presets/minimal.yaml | 2 +- specs/core/0_beacon-chain.md | 37 +++++++++++-------- specs/light_client/sync_protocol.md | 4 +- .../pyspec/eth2spec/test/helpers/genesis.py | 4 +- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index 9f7ca950f..2aa45cde3 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -10,7 +10,7 @@ SHARD_COUNT: 1024 # 2**7 (= 128) TARGET_COMMITTEE_SIZE: 128 # 2**12 (= 4,096) -MAX_INDICES_PER_ATTESTATION: 4096 +MAX_VALIDATORS_PER_COMMITTEE: 4096 # 2**2 (= 4) MIN_PER_EPOCH_CHURN_LIMIT: 4 # 2**16 (= 65,536) diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index 3e3f7ccb4..417f11c94 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -9,7 +9,7 @@ SHARD_COUNT: 8 # [customized] unsecure, but fast TARGET_COMMITTEE_SIZE: 4 # 2**12 (= 4,096) -MAX_INDICES_PER_ATTESTATION: 4096 +MAX_VALIDATORS_PER_COMMITTEE: 4096 # 2**2 (= 4) MIN_PER_EPOCH_CHURN_LIMIT: 4 # 2**16 (= 65,536) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6cf6db0cc..a7d47e108 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -30,7 +30,7 @@ - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - [`IndexedAttestation`](#indexedattestation) - [`PendingAttestation`](#pendingattestation) - - [`CompactCommitteees`](#CompactCommitteees) + - [`CompactCommittees`](#CompactCommittees) - [`Eth1Data`](#eth1data) - [`HistoricalBatch`](#historicalbatch) - [`DepositData`](#depositdata) @@ -69,7 +69,7 @@ - [`get_block_root_at_slot`](#get_block_root_at_slot) - [`get_block_root`](#get_block_root) - [`get_randao_mix`](#get_randao_mix) - - [`get_compact_committee_root`](#get_compact_committee_root) + - [`get_compact_committees_root`](#get_compact_committees_root) - [`generate_seed`](#generate_seed) - [`get_beacon_proposer_index`](#get_beacon_proposer_index) - [`verify_merkle_branch`](#verify_merkle_branch) @@ -361,14 +361,19 @@ class PendingAttestation(Container): proposer_index: ValidatorIndex ``` -#### `CompactCommitteees` +#### `CompactCommittee` ```python -class CompactCommitteees(Container): - data: Vector[Container( - pubkeys: List[Bytes48, MAX_VALIDATORS_PER_COMMITTEE] - compact_validators: List[uint64, MAX_VALIDATORS_PER_COMMITTEE] - ), SHARD_COUNT] +class CompactCommittee(Container): + pubkeys: List[Bytes48, MAX_VALIDATORS_PER_COMMITTEE] + compact_validators: List[uint64, MAX_VALIDATORS_PER_COMMITTEE] +``` + +#### `CompactCommittees` + +```python +class CompactCommittees(Container): + data: Vector[CompactCommittee, SHARD_COUNT] ``` #### `Eth1Data` @@ -522,7 +527,7 @@ class BeaconState(Container): # Shuffling start_shard: Shard randao_mixes: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] - compact_committee_roots: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Committee digests for light clients + compact_committees_roots: Vector[Hash, EPOCHS_PER_HISTORICAL_VECTOR] # Committee digests for light clients # Slashings slashed_balances: Vector[Gwei, EPOCHS_PER_SLASHED_BALANCES_VECTOR] # Sums of slashed effective balances # Attestations @@ -753,14 +758,14 @@ def get_randao_mix(state: BeaconState, return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] ``` -### `get_compact_committee_root` +### `get_compact_committees_root` ```python -def get_compact_committee_root(state: BeaconState, epoch: Epoch) -> Hash: +def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash: """ Return the compact committee root for the current epoch. """ - committee_data = CompactCommitteees().data + committee_data = CompactCommittees().data for committee_number in range(get_epoch_committee_count(state, epoch)): shard = (get_epoch_start_shard(state, epoch) + committee_number) % SHARD_COUNT for index in get_crosslink_committee(state, epoch, shard): @@ -782,7 +787,7 @@ def generate_seed(state: BeaconState, """ return hash( get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + - get_compact_committee_root(state, epoch) + + get_compact_committees_root(state, epoch) + int_to_bytes(epoch, length=32) ) ``` @@ -1190,9 +1195,9 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH - # Populate compact_committee_roots + # Populate compact_committees_roots for index in range(EPOCHS_PER_HISTORICAL_VECTOR): - state.compact_committee_roots[index] = get_compact_committee_root(state, GENESIS_EPOCH) + state.compact_committees_roots[index] = get_compact_committees_root(state, GENESIS_EPOCH) return state ``` @@ -1546,7 +1551,7 @@ def process_final_updates(state: BeaconState) -> None: state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT) # Set active index root index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % EPOCHS_PER_HISTORICAL_VECTOR - state.compact_committee_roots[index_root_position] = get_compact_committee_root(state, next_epoch + ACTIVATION_EXIT_DELAY) + state.compact_committees_roots[index_root_position] = get_compact_committees_root(state, next_epoch + ACTIVATION_EXIT_DELAY) # Set total slashed balances state.slashed_balances[next_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] = ( state.slashed_balances[current_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index 045bf5608..a29ed05c8 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -31,7 +31,7 @@ We define an "expansion" of an object as an object where a field in an object th We define two expansions: -* `ExtendedBeaconState`, which is identical to a `BeaconState` except `active_index_roots: List[Bytes32]` is replaced by `active_indices: List[List[ValidatorIndex]]`, where `BeaconState.active_index_roots[i] = hash_tree_root(ExtendedBeaconState.active_indices[i])`. +* `ExtendedBeaconState`, which is identical to a `BeaconState` except `compact_committees_roots: List[Bytes32]` is replaced by `active_indices: List[List[ValidatorIndex]]`, where `BeaconState.compact_committees_roots[i] = hash_tree_root(ExtendedBeaconState.active_indices[i])`. * `ExtendedBeaconBlock`, which is identical to a `BeaconBlock` except `state_root` is replaced with the corresponding `state: ExtendedBeaconState`. ### `get_active_validator_indices` @@ -40,7 +40,7 @@ Note that there is now a new way to compute `get_active_validator_indices`: ```python def get_active_validator_indices(state: ExtendedBeaconState, epoch: Epoch) -> List[ValidatorIndex]: - return state.active_indices[epoch % ACTIVE_INDEX_ROOTS_LENGTH] + return state.active_indices[epoch % compact_committees_rootS_LENGTH] ``` Note that it takes `state` instead of `state.validators` as an argument. This does not affect its use in `get_shuffled_committee`, because `get_shuffled_committee` has access to the full `state` as one of its arguments. diff --git a/test_libs/pyspec/eth2spec/test/helpers/genesis.py b/test_libs/pyspec/eth2spec/test/helpers/genesis.py index ce0be19bb..c793254c8 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/genesis.py +++ b/test_libs/pyspec/eth2spec/test/helpers/genesis.py @@ -41,9 +41,9 @@ def create_genesis_state(spec, num_validators): validator.activation_eligibility_epoch = spec.GENESIS_EPOCH validator.activation_epoch = spec.GENESIS_EPOCH - genesis_active_index_root = hash_tree_root(List[spec.ValidatorIndex, spec.VALIDATOR_REGISTRY_LIMIT]( + genesis_compact_committees_root = hash_tree_root(List[spec.ValidatorIndex, spec.VALIDATOR_REGISTRY_LIMIT]( spec.get_active_validator_indices(state, spec.GENESIS_EPOCH))) for index in range(spec.EPOCHS_PER_HISTORICAL_VECTOR): - state.active_index_roots[index] = genesis_active_index_root + state.compact_committees_roots[index] = genesis_compact_committees_root return state From ee712ecdde94bf00a0df44e412bd4ede2637e967 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Thu, 27 Jun 2019 11:21:45 +0100 Subject: [PATCH 045/112] Make HW happy :) --- specs/core/0_beacon-chain.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1ff1d58b3..ea99bb473 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1142,13 +1142,12 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], if time - time % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: return False - # Initialize deposit root - state = BeaconState() - state.eth1_data.deposit_root = hash_tree_root( - Vector[DepositData, len(deposits)](list(map(lambda deposit: deposit.data, deposits))) - ) # Process deposits - for deposit in deposits: + state = BeaconState() + for i, deposit in enumerate(deposits): + state.eth1_data.deposit_root = hash_tree_root( + Vector[DepositData, len(deposits)](list(map(lambda deposit: deposit.data, deposits[:i]))) + ) process_deposit(state, deposit) # Count active validators at genesis @@ -1183,7 +1182,7 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH - # Populate active_index_roots + # Populate active_index_roots genesis_active_index_root = hash_tree_root( List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, GENESIS_EPOCH)) ) From 853f5fc3f0a8ff671ec9bf946d5cf2a84e1c4f9e Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Thu, 27 Jun 2019 19:05:27 +0100 Subject: [PATCH 046/112] Apply Danny's suggestions --- specs/core/0_beacon-chain.md | 45 ++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a7d47e108..ba2cf771b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -30,10 +30,10 @@ - [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit) - [`IndexedAttestation`](#indexedattestation) - [`PendingAttestation`](#pendingattestation) - - [`CompactCommittees`](#CompactCommittees) - [`Eth1Data`](#eth1data) - [`HistoricalBatch`](#historicalbatch) - [`DepositData`](#depositdata) + - [`CompactCommittee`](#compactcommittee) - [`BeaconBlockHeader`](#beaconblockheader) - [Beacon operations](#beacon-operations) - [`ProposerSlashing`](#proposerslashing) @@ -361,21 +361,6 @@ class PendingAttestation(Container): proposer_index: ValidatorIndex ``` -#### `CompactCommittee` - -```python -class CompactCommittee(Container): - pubkeys: List[Bytes48, MAX_VALIDATORS_PER_COMMITTEE] - compact_validators: List[uint64, MAX_VALIDATORS_PER_COMMITTEE] -``` - -#### `CompactCommittees` - -```python -class CompactCommittees(Container): - data: Vector[CompactCommittee, SHARD_COUNT] -``` - #### `Eth1Data` ```python @@ -403,6 +388,14 @@ class DepositData(Container): signature: BLSSignature ``` +#### `CompactCommittee` + +```python +class CompactCommittee(Container): + pubkeys: List[Bytes48, MAX_VALIDATORS_PER_COMMITTEE] + compact_validators: List[uint64, MAX_VALIDATORS_PER_COMMITTEE] +``` + #### `BeaconBlockHeader` ```python @@ -765,16 +758,18 @@ def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash: """ Return the compact committee root for the current epoch. """ - committee_data = CompactCommittees().data + committees = Vector[CompactCommittee, SHARD_COUNT]() + start_shard = get_epoch_start_shard(state, epoch) for committee_number in range(get_epoch_committee_count(state, epoch)): - shard = (get_epoch_start_shard(state, epoch) + committee_number) % SHARD_COUNT + shard = (start_shard + committee_number) % SHARD_COUNT for index in get_crosslink_committee(state, epoch, shard): - validator = validators[index] - committee_data[shard].pubkeys.append(validator.pubkey) - # `index` (top 7 bytes) + `slashed` (8th bit) + `effective_balance` (bottom 7 bits) - compact_validator = index << 8 + validator.slashed << 7 + validator.effective_balance // GWEI_PER_ETH - committee_data[shard].compact_validators.append(compact_validator) - return hash_tree_root(committee_data) + validator = state.validators[index] + committees[shard].pubkeys.append(validator.pubkey) + compact_balance = validator.effective_balance // EFFECTIVE_BALANCE_INCREMENT + # `index` (top 6 bytes) + `slashed` (16th bit) + `compact_balance` (bottom 15 bits) + compact_validator = uint64(index << 16 + validator.slashed << 15 + compact_balance) + committees[shard].compact_validators.append(compact_validator) + return hash_tree_root(committees) ``` ### `generate_seed` @@ -787,7 +782,7 @@ def generate_seed(state: BeaconState, """ return hash( get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + - get_compact_committees_root(state, epoch) + + state.compact_committees_roots[epoch] + int_to_bytes(epoch, length=32) ) ``` From 384fa8854a92666694aabd5b4c923d2968438148 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 28 Jun 2019 00:19:55 +0200 Subject: [PATCH 047/112] justification/finalization testing groundwork --- ..._process_justification_and_finalization.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py new file mode 100644 index 000000000..95f00edd4 --- /dev/null +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -0,0 +1,74 @@ +from eth2spec.test.context import spec_state_test, with_all_phases +from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import ( + run_epoch_processing_with +) + + +def run_process_just_and_fin(spec, state): + yield from run_epoch_processing_with(spec, state, 'process_justification_and_finalization') + + +def get_committee_size(spec, state, slot): + epoch = spec.slot_to_epoch(slot) + epoch_start_shard = spec.get_epoch_start_shard(state, epoch) + committees_per_slot = spec.get_epoch_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH + shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT + committee_index = (shard + spec.SHARD_COUNT - spec.get_epoch_start_shard(state, epoch)) % spec.SHARD_COUNT + committee_count = spec.get_epoch_committee_count(state, epoch) + indices = spec.get_active_validator_indices(state, epoch) + start = (len(indices) * committee_index) // committee_count + end = (len(indices) * (committee_index + 1)) // committee_count + size = end - start + return size + + +def add_mock_attestations(spec, state, target_epoch, att_count, att_ratio): + # we must be at the end of the epoch + assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0 + + previous_epoch = spec.get_previous_epoch(state) + current_epoch = spec.get_current_epoch(state) + + if current_epoch == target_epoch: + attestations = state.current_epoch_attestations + elif previous_epoch == target_epoch: + attestations = state.previous_epoch_attestations + else: + raise Exception(f"cannot target epoch ${target_epoch} from epoch ${current_epoch}") + + total = 0 + while total < att_count: + for i in range(spec.SLOTS_PER_EPOCH): + size = get_committee_size(spec, state, state.slot + i) + # Create a bitfield filled with the given count per attestation, + # exactly on the right-most part of the committee field. + attesting_count = int(size * att_ratio) + aggregation_bitfield = ((1 << attesting_count) - 1).to_bytes(length=((size + 7) // 8), byteorder='big') + + attestations.append(spec.PendingAttestation( + aggregation_bitfield=aggregation_bitfield, + data=spec.AttestationData( + beacon_block_root=b'\xaa' * 32, + source_epoch=0, + source_root=b'\xbb' * 32, + target_root=b'\xbb' * 32, + crosslink=spec.Crosslink() + ), + inclusion_delay=0, + )) + total += 1 + + +@with_all_phases +@spec_state_test +def test_rule_1(spec, state): + previous_epoch = spec.get_previous_epoch(state) + current_epoch = spec.get_current_epoch(state) + + # TODO + # add_mock_attestations(spec, state, ...) + # get indices attesting e.g. current_epoch_attestations + # set their balances + # yield from run_process_just_and_fin(spec, state) + # check finalization + From 990cc55db74628c045ba9919a65c2d9f5d8d0692 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 27 Jun 2019 16:32:10 -0600 Subject: [PATCH 048/112] fix committee typing error --- motes.md | 42 ++++++++++++++++++++++++++++++++++++ notes.txt | 1 + specs/core/0_beacon-chain.md | 4 ++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 motes.md create mode 100644 notes.txt diff --git a/motes.md b/motes.md new file mode 100644 index 000000000..e01ba19b7 --- /dev/null +++ b/motes.md @@ -0,0 +1,42 @@ +* `BLS_WITHDRAWAL_PREFIX` + * Why int rather than bytes? +* `MIN_SEED_LOOKAHEAD` + * Is this actually tunable? + * If so, what are the reprecussions? +* `ACTIVATION_EXIT_DELAY` + * Reaquaint with purpose +* AttesterSlashings + * `MAX_ATTESTER_SLASHINGS` is 1. + * Are there scenarios in which validators can create more effective slashable + messages than can be included on chain? For example, Validators split up to + create double attestations for checkpoints but different (junk) crosslink + data to prevent them from being aggregatable to the fullest + * Max is for block size, no? +* Signature domains + * Max 4byte ints +* `Version` not defined in one of the lists of custom types (2!!). ensure in spec +* `PendingAttestation` + * Don't think `proposer_index` is actually necessary here because effective + balance is stable until end of epoch so can do dynamic lookups +* is_genesis_trigger + * only run at ends of blocks to preserve invariant that eth1data.deposit_root + is the deposit root at the _end_ of an eth1 block +* `Attestation` + * why bitfields not together? +* `Transfer` + * replay mechanism... say the slot gets missed and you sign another transfer + * in a fork you could include both transfers +* `get_previous_epoch` + * do a once over on the genesis stuff +* `get_epoch_start_shard` + * checking next hinges upon the fact that the validator set for the next + epoch is 100% known at the current epoch. Ensure this is the case +* `get_block_root_at_slot` .. `generate_seed` can be bade into one line + function signatures +* `get_shuffled_index` + * I think it should be maybe `assert index_count <= VALIDATOR_REGISTRY_LIMIT` + * is the `2**40` special for security of alg? probably. + + +pubkey/privkey g1 vs g2 + diff --git a/notes.txt b/notes.txt new file mode 100644 index 000000000..421ad7750 --- /dev/null +++ b/notes.txt @@ -0,0 +1 @@ +* `BLS_WITHDRAWAL_PREFIX` -- diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ba2cf771b..842b16b98 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -758,7 +758,7 @@ def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash: """ Return the compact committee root for the current epoch. """ - committees = Vector[CompactCommittee, SHARD_COUNT]() + committees = [CompactCommittee() for _ in range(SHARD_COUNT)] start_shard = get_epoch_start_shard(state, epoch) for committee_number in range(get_epoch_committee_count(state, epoch)): shard = (start_shard + committee_number) % SHARD_COUNT @@ -769,7 +769,7 @@ def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash: # `index` (top 6 bytes) + `slashed` (16th bit) + `compact_balance` (bottom 15 bits) compact_validator = uint64(index << 16 + validator.slashed << 15 + compact_balance) committees[shard].compact_validators.append(compact_validator) - return hash_tree_root(committees) + return hash_tree_root(Vector[CompactCommittee, SHARD_COUNT](committees)) ``` ### `generate_seed` From 2252142e01b9431cedbd5f1a2824a41db4e430dc Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 28 Jun 2019 10:24:16 +0800 Subject: [PATCH 049/112] padding version normal merkle tree --- .../pyspec/eth2spec/utils/merkle_minimal.py | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py index 038b555cf..e3e81f3a5 100644 --- a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py +++ b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py @@ -1,4 +1,5 @@ from .hash_function import hash +from math import log2 ZERO_BYTES32 = b'\x00' * 32 @@ -8,11 +9,10 @@ for layer in range(1, 100): zerohashes.append(hash(zerohashes[layer - 1] + zerohashes[layer - 1])) -# Compute a Merkle root of a right-zerobyte-padded 2**32 sized tree -def calc_merkle_tree_from_leaves(values): +def calc_merkle_tree_from_leaves(values, layer_count=32): values = list(values) tree = [values[::]] - for h in range(32): + for h in range(layer_count): if len(values) % 2 == 1: values.append(zerohashes[h]) values = [hash(values[i] + values[i + 1]) for i in range(0, len(values), 2)] @@ -20,8 +20,11 @@ def calc_merkle_tree_from_leaves(values): return tree -def get_merkle_root(values): - return calc_merkle_tree_from_leaves(values)[-1][0] +def get_merkle_root(values, pad_to=1): + layer_count = int(log2(pad_to)) + if len(values) == 0: + return zerohashes[layer_count] + return calc_merkle_tree_from_leaves(values, layer_count)[-1][0] def get_merkle_proof(tree, item_index): @@ -32,19 +35,7 @@ def get_merkle_proof(tree, item_index): return proof -def next_power_of_two(v: int) -> int: - """ - Get the next power of 2. (for 64 bit range ints). - 0 is a special case, to have non-empty defaults. - Examples: - 0 -> 1, 1 -> 1, 2 -> 2, 3 -> 4, 32 -> 32, 33 -> 64 - """ - if v == 0: - return 1 - return 1 << (v - 1).bit_length() - - -def merkleize_chunks(chunks, pad_to: int = 1): +def merkleize_chunks(chunks, pad_to: int=1): count = len(chunks) depth = max(count - 1, 0).bit_length() max_depth = max(depth, (pad_to - 1).bit_length()) From 5a8f3e495a8be99d6f6ae821c141e1b881d44d92 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 11:10:17 -0600 Subject: [PATCH 050/112] set committees root for next epoch rather tahn ACTIVaTION_EXIT_DELAY in the future --- specs/core/0_beacon-chain.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 842b16b98..8f55addbc 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -698,6 +698,9 @@ def get_shard_delta(state: BeaconState, epoch: Epoch) -> int: ```python def get_epoch_start_shard(state: BeaconState, epoch: Epoch) -> Shard: + """ + Return the start shard of the 0th committee in an epoch. + """ assert epoch <= get_current_epoch(state) + 1 check_epoch = Epoch(get_current_epoch(state) + 1) shard = Shard((state.start_shard + get_shard_delta(state, get_current_epoch(state))) % SHARD_COUNT) @@ -767,7 +770,7 @@ def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash: committees[shard].pubkeys.append(validator.pubkey) compact_balance = validator.effective_balance // EFFECTIVE_BALANCE_INCREMENT # `index` (top 6 bytes) + `slashed` (16th bit) + `compact_balance` (bottom 15 bits) - compact_validator = uint64(index << 16 + validator.slashed << 15 + compact_balance) + compact_validator = uint64((index << 16) + (validator.slashed << 15) + compact_balance) committees[shard].compact_validators.append(compact_validator) return hash_tree_root(Vector[CompactCommittee, SHARD_COUNT](committees)) ``` @@ -782,7 +785,7 @@ def generate_seed(state: BeaconState, """ return hash( get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + - state.compact_committees_roots[epoch] + + state.compact_committees_roots[epoch % EPOCHS_PER_HISTORICAL_VECTOR] + int_to_bytes(epoch, length=32) ) ``` @@ -1546,7 +1549,7 @@ def process_final_updates(state: BeaconState) -> None: state.start_shard = Shard((state.start_shard + get_shard_delta(state, current_epoch)) % SHARD_COUNT) # Set active index root index_root_position = (next_epoch + ACTIVATION_EXIT_DELAY) % EPOCHS_PER_HISTORICAL_VECTOR - state.compact_committees_roots[index_root_position] = get_compact_committees_root(state, next_epoch + ACTIVATION_EXIT_DELAY) + state.compact_committees_roots[index_root_position] = get_compact_committees_root(state, next_epoch) # Set total slashed balances state.slashed_balances[next_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] = ( state.slashed_balances[current_epoch % EPOCHS_PER_SLASHED_BALANCES_VECTOR] From b40e2284a0f601dd6f6ac80f833d4036c244ecfb Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 11:20:24 -0600 Subject: [PATCH 051/112] use active index root for generate seed mix in --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 8f55addbc..80977c8f7 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -785,7 +785,7 @@ def generate_seed(state: BeaconState, """ return hash( get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + - state.compact_committees_roots[epoch % EPOCHS_PER_HISTORICAL_VECTOR] + + hash_tree_root(List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, epoch))) + int_to_bytes(epoch, length=32) ) ``` From 9993a2879629b7e27f97086ff3d5d70cc3da6a2f Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 11:26:05 -0600 Subject: [PATCH 052/112] lint --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 80977c8f7..490ac0c96 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -764,7 +764,7 @@ def get_compact_committees_root(state: BeaconState, epoch: Epoch) -> Hash: committees = [CompactCommittee() for _ in range(SHARD_COUNT)] start_shard = get_epoch_start_shard(state, epoch) for committee_number in range(get_epoch_committee_count(state, epoch)): - shard = (start_shard + committee_number) % SHARD_COUNT + shard = Shard((start_shard + committee_number) % SHARD_COUNT) for index in get_crosslink_committee(state, epoch, shard): validator = state.validators[index] committees[shard].pubkeys.append(validator.pubkey) @@ -1535,7 +1535,7 @@ def process_slashings(state: BeaconState) -> None: ```python def process_final_updates(state: BeaconState) -> None: current_epoch = get_current_epoch(state) - next_epoch = current_epoch + 1 + next_epoch = Shard(current_epoch + 1) # Reset eth1 data votes if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0: state.eth1_data_votes = [] From 4dc526fbb7d619d0675950b703dcb30c5eb22836 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 29 Jun 2019 02:16:16 +0800 Subject: [PATCH 053/112] In the end, `get_merkle_root` is back --- scripts/build_spec.py | 6 ++- specs/core/0_beacon-chain.md | 44 ++++++++++++++++--- .../test/genesis/test_genesis_trigger.py | 9 ++-- .../pyspec/eth2spec/test/helpers/deposits.py | 17 +++---- .../pyspec/eth2spec/utils/merkle_minimal.py | 2 +- .../eth2spec/utils/test_merkle_minimal.py | 5 ++- 6 files changed, 59 insertions(+), 24 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index 99c5cd69d..1bdebd130 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -11,7 +11,8 @@ from typing import ( ) -PHASE0_IMPORTS = '''from typing import ( +PHASE0_IMPORTS = '''from math import log2 +from typing import ( Any, Callable, Dict, Set, Sequence, Tuple, ) @@ -36,7 +37,8 @@ from eth2spec.utils.bls import ( from eth2spec.utils.hash_function import hash ''' -PHASE1_IMPORTS = '''from typing import ( +PHASE1_IMPORTS = '''from math import log2 +from typing import ( Any, Callable, Dict, Optional, Set, Sequence, MutableSequence, Tuple, ) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ea99bb473..25a7340d3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -51,6 +51,8 @@ - [`hash`](#hash) - [`hash_tree_root`](#hash_tree_root) - [`signing_root`](#signing_root) + - [`calc_merkle_tree_from_leaves`](#calc_merkle_tree_from_leaves) + - [`get_merkle_root`](#get_merkle_root) - [`bls_domain`](#bls_domain) - [`slot_to_epoch`](#slot_to_epoch) - [`get_previous_epoch`](#get_previous_epoch) @@ -558,6 +560,33 @@ The `hash` function is SHA256. `def signing_root(object: Container) -> Hash` is a function for computing signing messages, as defined in the [SimpleSerialize spec](../simple-serialize.md#self-signed-containers). +### `calc_merkle_tree_from_leaves` + +```python +zerohashes = [ZERO_HASH] +for layer in range(1, 100): + zerohashes.append(hash(zerohashes[layer - 1] + zerohashes[layer - 1])) +def calc_merkle_tree_from_leaves(values: Sequence[Hash], layer_count: int=32) -> Sequence[Sequence[Hash]]: + values = list(values) + tree = [values[::]] + for h in range(layer_count): + if len(values) % 2 == 1: + values.append(zerohashes[h]) + values = [hash(values[i] + values[i + 1]) for i in range(0, len(values), 2)] + tree.append(values[::]) + return tree +``` + +### `get_merkle_root` + +```python +def get_merkle_root(values: Sequence[Hash], pad_to: int=1) -> Hash: + layer_count = int(log2(pad_to)) + if len(values) == 0: + return zerohashes[layer_count] + return calc_merkle_tree_from_leaves(values, layer_count)[-1][0] +``` + ### `bls_domain` ```python @@ -1144,10 +1173,10 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], # Process deposits state = BeaconState() - for i, deposit in enumerate(deposits): - state.eth1_data.deposit_root = hash_tree_root( - Vector[DepositData, len(deposits)](list(map(lambda deposit: deposit.data, deposits[:i]))) - ) + for deposit_index, deposit in enumerate(deposits): + leaves = [hash_tree_root(d.data) for d in deposits[:deposit_index + 1]] + state.eth1_data.deposit_root = get_merkle_root(leaves, 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_deposit_index = deposit_index process_deposit(state, deposit) # Count active validators at genesis @@ -1173,9 +1202,14 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth ) # Process genesis deposits - for deposit in deposits: + for deposit_index, deposit in enumerate(deposits): + leaves = [hash_tree_root(d.data) for d in deposits[:deposit_index + 1]] + state.eth1_data.deposit_root = get_merkle_root(leaves, 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_deposit_index = deposit_index process_deposit(state, deposit) + assert state.eth1_data.deposit_root == eth1_data.deposit_root + # Process genesis activations for validator in state.validators: if validator.effective_balance == MAX_EFFECTIVE_BALANCE: diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py index 9425a1750..783def3ba 100644 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py @@ -8,12 +8,11 @@ from eth2spec.test.helpers.deposits import ( @spectest_with_bls_switch def test_is_genesis_trigger_false(spec): deposit_count = 2 - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) + genesis_deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1546300800 yield "deposits", genesis_deposits yield "time", genesis_time - yield "deposit_root", deposit_root is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time) assert is_triggered is False @@ -25,13 +24,12 @@ def test_is_genesis_trigger_false(spec): @spectest_with_bls_switch def test_is_genesis_trigger_true(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) + 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 - yield "deposit_root", deposit_root is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time) assert is_triggered is True @@ -43,11 +41,10 @@ def test_is_genesis_trigger_true(spec): @spectest_with_bls_switch def test_is_genesis_trigger_not_enough_balance(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) + genesis_deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE - 1) genesis_time = 1546300800 yield "deposits", genesis_deposits yield "time", genesis_time - yield "deposit_root", deposit_root is_triggered = spec.is_genesis_trigger(genesis_deposits, genesis_time) assert is_triggered is False diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index bda4f1699..60ff2a3db 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -41,7 +41,9 @@ def build_deposit(spec, amount, withdrawal_credentials, signed): - deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed) + deposit_data = build_deposit_data( + spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed, + ) item = deposit_data.hash_tree_root() index = len(deposit_data_leaves) @@ -63,6 +65,7 @@ def build_deposit(spec, def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False): genesis_deposit_data_list = [] deposit_data_leaves = [] + genesis_deposits = [] for validator_index in range(genesis_validator_count): pubkey = pubkeys[validator_index] privkey = privkeys[validator_index] @@ -79,13 +82,11 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False deposit_data_leaves.append(item) genesis_deposit_data_list.append(deposit_data) - tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) - root = get_merkle_root((tuple(deposit_data_leaves))) - - genesis_deposits = list( - spec.Deposit(proof=list(get_merkle_proof(tree, item_index=index)), data=deposit_data) - for index, deposit_data in enumerate(genesis_deposit_data_list) - ) + tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) + root = get_merkle_root((tuple(deposit_data_leaves)), 2**32) + genesis_deposits.append( + spec.Deposit(proof=list(get_merkle_proof(tree, item_index=validator_index)), data=deposit_data) + ) return genesis_deposits, root diff --git a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py index e3e81f3a5..e9416ea05 100644 --- a/test_libs/pyspec/eth2spec/utils/merkle_minimal.py +++ b/test_libs/pyspec/eth2spec/utils/merkle_minimal.py @@ -1,5 +1,5 @@ from .hash_function import hash -from math import log2 +from math import log2 ZERO_BYTES32 = b'\x00' * 32 diff --git a/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py b/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py index 1c72a649b..f1ed768e6 100644 --- a/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py +++ b/test_libs/pyspec/eth2spec/utils/test_merkle_minimal.py @@ -1,5 +1,5 @@ import pytest -from .merkle_minimal import zerohashes, merkleize_chunks +from .merkle_minimal import zerohashes, merkleize_chunks, get_merkle_root from .hash_function import hash @@ -53,6 +53,7 @@ cases = [ 'depth,count,pow2,value', cases, ) -def test_merkleize_chunks(depth, count, pow2, value): +def test_merkleize_chunks_and_get_merkle_root(depth, count, pow2, value): chunks = [e(i) for i in range(count)] assert merkleize_chunks(chunks, pad_to=pow2) == value + assert get_merkle_root(chunks, pad_to=pow2) == value From cb2bfd67dc18d19f69f293c424370437ec08ae0e Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 29 Jun 2019 02:27:48 +0800 Subject: [PATCH 054/112] Apply Proto's feedback of list(map(...)) --- specs/core/0_beacon-chain.md | 8 ++++---- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 25a7340d3..9e59212fd 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1173,9 +1173,9 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], # Process deposits state = BeaconState() + leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) for deposit_index, deposit in enumerate(deposits): - leaves = [hash_tree_root(d.data) for d in deposits[:deposit_index + 1]] - state.eth1_data.deposit_root = get_merkle_root(leaves, 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_data.deposit_root = get_merkle_root(leaves[:deposit_index + 1], 2**DEPOSIT_CONTRACT_TREE_DEPTH) state.eth1_deposit_index = deposit_index process_deposit(state, deposit) @@ -1202,9 +1202,9 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth ) # Process genesis deposits + leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) for deposit_index, deposit in enumerate(deposits): - leaves = [hash_tree_root(d.data) for d in deposits[:deposit_index + 1]] - state.eth1_data.deposit_root = get_merkle_root(leaves, 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_data.deposit_root = get_merkle_root(leaves[:deposit_index + 1], 2**DEPOSIT_CONTRACT_TREE_DEPTH) state.eth1_deposit_index = deposit_index process_deposit(state, deposit) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 60ff2a3db..529dd8c12 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -51,8 +51,6 @@ def build_deposit(spec, tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) root = get_merkle_root((tuple(deposit_data_leaves))) proof = list(get_merkle_proof(tree, item_index=index)) - assert spec.verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, index, root) - deposit = spec.Deposit( proof=list(proof), index=index, From 7bc6a46eaaecfe73dcdbc99067f8f7ae77d7c220 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 29 Jun 2019 02:51:24 +0800 Subject: [PATCH 055/112] Fix `build_deposit` --- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 529dd8c12..d7df156a3 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -48,20 +48,20 @@ def build_deposit(spec, item = deposit_data.hash_tree_root() index = len(deposit_data_leaves) deposit_data_leaves.append(item) - tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) - root = get_merkle_root((tuple(deposit_data_leaves))) + tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves), spec.DEPOSIT_CONTRACT_TREE_DEPTH) + root = get_merkle_root((tuple(deposit_data_leaves)), 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH) proof = list(get_merkle_proof(tree, item_index=index)) deposit = spec.Deposit( proof=list(proof), index=index, data=deposit_data, ) + assert spec.verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, index, root) return deposit, root, deposit_data_leaves def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False): - genesis_deposit_data_list = [] deposit_data_leaves = [] genesis_deposits = [] for validator_index in range(genesis_validator_count): @@ -78,10 +78,9 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False sign_deposit_data(spec, deposit_data, privkey) # state=None item = deposit_data.hash_tree_root() deposit_data_leaves.append(item) - genesis_deposit_data_list.append(deposit_data) - tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) - root = get_merkle_root((tuple(deposit_data_leaves)), 2**32) + tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves), spec.DEPOSIT_CONTRACT_TREE_DEPTH) + root = get_merkle_root((tuple(deposit_data_leaves)), 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH) genesis_deposits.append( spec.Deposit(proof=list(get_merkle_proof(tree, item_index=validator_index)), data=deposit_data) ) From d5c2ecb6f73a3c2ea673332d45739704b6af9b29 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 15:44:26 -0600 Subject: [PATCH 056/112] remove local notes files --- motes.md | 42 ------------------------------------------ notes.txt | 1 - 2 files changed, 43 deletions(-) delete mode 100644 motes.md delete mode 100644 notes.txt diff --git a/motes.md b/motes.md deleted file mode 100644 index e01ba19b7..000000000 --- a/motes.md +++ /dev/null @@ -1,42 +0,0 @@ -* `BLS_WITHDRAWAL_PREFIX` - * Why int rather than bytes? -* `MIN_SEED_LOOKAHEAD` - * Is this actually tunable? - * If so, what are the reprecussions? -* `ACTIVATION_EXIT_DELAY` - * Reaquaint with purpose -* AttesterSlashings - * `MAX_ATTESTER_SLASHINGS` is 1. - * Are there scenarios in which validators can create more effective slashable - messages than can be included on chain? For example, Validators split up to - create double attestations for checkpoints but different (junk) crosslink - data to prevent them from being aggregatable to the fullest - * Max is for block size, no? -* Signature domains - * Max 4byte ints -* `Version` not defined in one of the lists of custom types (2!!). ensure in spec -* `PendingAttestation` - * Don't think `proposer_index` is actually necessary here because effective - balance is stable until end of epoch so can do dynamic lookups -* is_genesis_trigger - * only run at ends of blocks to preserve invariant that eth1data.deposit_root - is the deposit root at the _end_ of an eth1 block -* `Attestation` - * why bitfields not together? -* `Transfer` - * replay mechanism... say the slot gets missed and you sign another transfer - * in a fork you could include both transfers -* `get_previous_epoch` - * do a once over on the genesis stuff -* `get_epoch_start_shard` - * checking next hinges upon the fact that the validator set for the next - epoch is 100% known at the current epoch. Ensure this is the case -* `get_block_root_at_slot` .. `generate_seed` can be bade into one line - function signatures -* `get_shuffled_index` - * I think it should be maybe `assert index_count <= VALIDATOR_REGISTRY_LIMIT` - * is the `2**40` special for security of alg? probably. - - -pubkey/privkey g1 vs g2 - diff --git a/notes.txt b/notes.txt deleted file mode 100644 index 421ad7750..000000000 --- a/notes.txt +++ /dev/null @@ -1 +0,0 @@ -* `BLS_WITHDRAWAL_PREFIX` -- From 3a60f64b9275f0dea931bf240eba2d1f083a22e8 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 01:22:29 +0200 Subject: [PATCH 057/112] refactor finalization test helper func --- ..._process_justification_and_finalization.py | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 95f00edd4..f0fe35e8b 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -1,3 +1,4 @@ +import math from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import ( run_epoch_processing_with @@ -8,41 +9,46 @@ def run_process_just_and_fin(spec, state): yield from run_epoch_processing_with(spec, state, 'process_justification_and_finalization') -def get_committee_size(spec, state, slot): +def get_shards_for_slot(spec, state, slot): epoch = spec.slot_to_epoch(slot) epoch_start_shard = spec.get_epoch_start_shard(state, epoch) committees_per_slot = spec.get_epoch_committee_count(state, epoch) // spec.SLOTS_PER_EPOCH shard = (epoch_start_shard + committees_per_slot * (slot % spec.SLOTS_PER_EPOCH)) % spec.SHARD_COUNT - committee_index = (shard + spec.SHARD_COUNT - spec.get_epoch_start_shard(state, epoch)) % spec.SHARD_COUNT - committee_count = spec.get_epoch_committee_count(state, epoch) - indices = spec.get_active_validator_indices(state, epoch) + return [shard + i for i in range(committees_per_slot)] + + +def get_committee_size(spec, epoch_start_shard, shard, committee_count, indices): + committee_index = (shard + spec.SHARD_COUNT - epoch_start_shard) % spec.SHARD_COUNT start = (len(indices) * committee_index) // committee_count end = (len(indices) * (committee_index + 1)) // committee_count size = end - start - return size + return size, -def add_mock_attestations(spec, state, target_epoch, att_count, att_ratio): +def add_mock_attestations(spec, state, epoch, att_count, att_ratio): # we must be at the end of the epoch assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0 previous_epoch = spec.get_previous_epoch(state) current_epoch = spec.get_current_epoch(state) - if current_epoch == target_epoch: + if current_epoch == epoch: attestations = state.current_epoch_attestations - elif previous_epoch == target_epoch: + elif previous_epoch == epoch: attestations = state.previous_epoch_attestations else: - raise Exception(f"cannot target epoch ${target_epoch} from epoch ${current_epoch}") + raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}") + committee_count = spec.get_epoch_committee_count(state, epoch) + indices = spec.get_active_validator_indices(state, epoch) + epoch_start_shard = spec.get_epoch_start_shard(state, epoch) total = 0 - while total < att_count: - for i in range(spec.SLOTS_PER_EPOCH): - size = get_committee_size(spec, state, state.slot + i) + for i in range(spec.SLOTS_PER_EPOCH): + for shard in get_shards_for_slot(spec, state, state.slot + i): + size = get_committee_size(spec, epoch_start_shard, shard, committee_count, indices) # Create a bitfield filled with the given count per attestation, # exactly on the right-most part of the committee field. - attesting_count = int(size * att_ratio) + attesting_count = math.ceil(size * att_ratio) aggregation_bitfield = ((1 << attesting_count) - 1).to_bytes(length=((size + 7) // 8), byteorder='big') attestations.append(spec.PendingAttestation( @@ -54,16 +60,20 @@ def add_mock_attestations(spec, state, target_epoch, att_count, att_ratio): target_root=b'\xbb' * 32, crosslink=spec.Crosslink() ), - inclusion_delay=0, + inclusion_delay=1, )) total += 1 + if total >= att_count: + return + + raise Exception(f"could not fill state with {att_count} attestations for epoch {epoch}") @with_all_phases @spec_state_test def test_rule_1(spec, state): - previous_epoch = spec.get_previous_epoch(state) - current_epoch = spec.get_current_epoch(state) + # previous_epoch = spec.get_previous_epoch(state) + # current_epoch = spec.get_current_epoch(state) # TODO # add_mock_attestations(spec, state, ...) @@ -71,4 +81,4 @@ def test_rule_1(spec, state): # set their balances # yield from run_process_just_and_fin(spec, state) # check finalization - + pass From 518db42de75b9714347cd4ad2d549691f28afe6b Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 03:19:30 +0200 Subject: [PATCH 058/112] fix attestation tests to work with checkpoints --- .../test/phase_0/block_processing/test_process_attestation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py index a1f87f059..f083a07f4 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_attestation.py @@ -205,7 +205,7 @@ def test_future_target_epoch(spec, state): state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY - attestation.data.target_epoch = spec.get_current_epoch(state) + 1 # target epoch will be too new to handle + attestation.data.target.epoch = spec.get_current_epoch(state) + 1 # target epoch will be too new to handle sign_attestation(spec, state, attestation) yield from run_attestation_processing(spec, state, attestation, False) From efd9d173d786c87ad4daf4710615cd739ee2d584 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 03:19:57 +0200 Subject: [PATCH 059/112] update attester slashings processing tests --- .../test_process_slashings.py | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py index f1a23326b..7be23a04d 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_slashings.py @@ -17,8 +17,8 @@ def slash_validators(spec, state, indices, out_epochs): v.withdrawable_epoch = out_epoch total_slashed_balance += v.effective_balance - state.slashed_balances[ - spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR + state.slashings[ + spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHINGS_VECTOR ] = total_slashed_balance @@ -26,13 +26,13 @@ def slash_validators(spec, state, indices, out_epochs): @spec_state_test def test_max_penalties(spec, state): slashed_count = (len(state.validators) // 3) + 1 - out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2) + out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2) slashed_indices = list(range(slashed_count)) slash_validators(spec, state, slashed_indices, [out_epoch] * slashed_count) total_balance = spec.get_total_active_balance(state) - total_penalties = state.slashed_balances[spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR] + total_penalties = sum(state.slashings) assert total_balance // 3 <= total_penalties @@ -44,28 +44,30 @@ def test_max_penalties(spec, state): @with_all_phases @spec_state_test -def test_min_penalties(spec, state): - # run_epoch_processing_to(spec, state, 'process_slashings', exclusive=True) - +def test_small_penalty(spec, state): # Just the bare minimum for this one validator - pre_balance = state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE + state.balances[0] = state.validators[0].effective_balance = spec.EJECTION_BALANCE # All the other validators get the maximum. for i in range(1, len(state.validators)): state.validators[i].effective_balance = state.balances[i] = spec.MAX_EFFECTIVE_BALANCE - out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2) + out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2) slash_validators(spec, state, [0], [out_epoch]) total_balance = spec.get_total_active_balance(state) - total_penalties = state.slashed_balances[spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR] + total_penalties = sum(state.slashings) - # we are testing the minimum here, i.e. get slashed (effective_balance / MIN_SLASHING_PENALTY_QUOTIENT) - assert total_penalties * 3 / total_balance < 1 / spec.MIN_SLASHING_PENALTY_QUOTIENT + assert total_balance // 3 > total_penalties - yield from run_process_slashings(spec, state) + run_epoch_processing_to(spec, state, 'process_slashings') + pre_slash_balances = list(state.balances) + yield 'pre', state + spec.process_slashings(state) + yield 'post', state - assert state.balances[0] == pre_balance - (pre_balance // spec.MIN_SLASHING_PENALTY_QUOTIENT) + assert state.balances[0] == pre_slash_balances[0] - (state.validators[0].effective_balance + * 3 * total_penalties // total_balance) @with_all_phases @@ -75,14 +77,13 @@ def test_scaled_penalties(spec, state): state.slot = spec.SLOTS_PER_EPOCH # Also mock some previous slashings, so that we test to have the delta in the penalties computation. - for i in range(spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR): - state.slashed_balances[i] = spec.MAX_EFFECTIVE_BALANCE * 3 - - # Mock the very last one (which is to be used for the delta balance computation) to be different. - # To enforce the client test runner to correctly get this one from the array, not the others. - prev_penalties = state.slashed_balances[ - (spec.get_current_epoch(state) + 1) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR - ] = spec.MAX_EFFECTIVE_BALANCE * 2 + base = spec.EJECTION_BALANCE + incr = spec.EFFECTIVE_BALANCE_INCREMENT + # Just add some random slashings. non-zero slashings are at least the minimal effective balance. + state.slashings[0] = base + (incr * 12) + state.slashings[4] = base + (incr * 3) + state.slashings[5] = base + (incr * 6) + state.slashings[spec.EPOCHS_PER_SLASHINGS_VECTOR - 1] = base + (incr * 7) slashed_count = len(state.validators) // 4 @@ -90,13 +91,17 @@ def test_scaled_penalties(spec, state): # make the balances non-uniform. # Otherwise it would just be a simple 3/4 balance slashing. Test the per-validator scaled penalties. + diff = spec.MAX_EFFECTIVE_BALANCE - base + increments = diff // incr for i in range(10): - state.validators[i].effective_balance += spec.EFFECTIVE_BALANCE_INCREMENT * 4 - state.balances[i] += spec.EFFECTIVE_BALANCE_INCREMENT * 4 + state.validators[i].effective_balance = base + (incr * (i % increments)) + assert state.validators[i].effective_balance <= spec.MAX_EFFECTIVE_BALANCE + # add/remove some, see if balances different than the effective balances are picked up + state.balances[i] = state.validators[i].effective_balance + i - 5 total_balance = spec.get_total_active_balance(state) - out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2) + out_epoch = spec.get_current_epoch(state) + (spec.EPOCHS_PER_SLASHINGS_VECTOR // 2) slashed_indices = list(range(slashed_count)) @@ -112,8 +117,7 @@ def test_scaled_penalties(spec, state): spec.process_slashings(state) yield 'post', state - total_penalties = state.slashed_balances[spec.get_current_epoch(state) % spec.EPOCHS_PER_SLASHED_BALANCES_VECTOR] - total_penalties -= prev_penalties + total_penalties = sum(state.slashings) for i in slashed_indices: v = state.validators[i] From afb34c71e6aeaa3b088b46b685f03a9dfaba8a9b Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 03:22:14 +0200 Subject: [PATCH 060/112] fix broken block test for checkpoint use --- test_libs/pyspec/eth2spec/test/sanity/test_blocks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index e56baee8c..019563978 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -143,7 +143,7 @@ def test_empty_epoch_transition_not_finalizing(spec, state): yield 'post', state assert state.slot == block.slot - assert state.finalized_epoch < spec.get_current_epoch(state) - 4 + assert state.finalized_checkpoint.epoch < spec.get_current_epoch(state) - 4 for index in range(len(state.validators)): assert state.balances[index] < pre_balances[index] From cfbdee709bd408572d10c70f2a7adb3dd72220aa Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 05:04:25 +0200 Subject: [PATCH 061/112] finalization testing --- ..._process_justification_and_finalization.py | 226 ++++++++++++++++-- 1 file changed, 204 insertions(+), 22 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index f0fe35e8b..0afa4f307 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -22,10 +22,10 @@ def get_committee_size(spec, epoch_start_shard, shard, committee_count, indices) start = (len(indices) * committee_index) // committee_count end = (len(indices) * (committee_index + 1)) // committee_count size = end - start - return size, + return size -def add_mock_attestations(spec, state, epoch, att_count, att_ratio): +def add_mock_attestations(spec, state, epoch, att_ratio, source, target): # we must be at the end of the epoch assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0 @@ -42,9 +42,9 @@ def add_mock_attestations(spec, state, epoch, att_count, att_ratio): committee_count = spec.get_epoch_committee_count(state, epoch) indices = spec.get_active_validator_indices(state, epoch) epoch_start_shard = spec.get_epoch_start_shard(state, epoch) - total = 0 - for i in range(spec.SLOTS_PER_EPOCH): - for shard in get_shards_for_slot(spec, state, state.slot + i): + epoch_start_slot = spec.get_epoch_start_slot(epoch) + for slot in range(epoch_start_slot, epoch_start_slot + spec.SLOTS_PER_EPOCH): + for shard in get_shards_for_slot(spec, state, slot): size = get_committee_size(spec, epoch_start_shard, shard, committee_count, indices) # Create a bitfield filled with the given count per attestation, # exactly on the right-most part of the committee field. @@ -55,30 +55,212 @@ def add_mock_attestations(spec, state, epoch, att_count, att_ratio): aggregation_bitfield=aggregation_bitfield, data=spec.AttestationData( beacon_block_root=b'\xaa' * 32, - source_epoch=0, - source_root=b'\xbb' * 32, - target_root=b'\xbb' * 32, + source=source, + target=source, crosslink=spec.Crosslink() ), inclusion_delay=1, )) - total += 1 - if total >= att_count: - return - raise Exception(f"could not fill state with {att_count} attestations for epoch {epoch}") + +def finalize_on_234(spec, state, epoch, support): + assert epoch > 4 + state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch + + # 43210 -- epochs ago + # 3210x -- justification bitfield indices + # 11*0. -- justification bitfield contents, . = this epoch, * is being justified now + # checkpoints for the epochs ago: + c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) + c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) + c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) + # c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + + old_finalized = state.finalized_checkpoint + state.previous_justified_checkpoint = c4 + state.current_justified_checkpoint = c3 + bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + bits[3:4] = [1, 1] # mock 3rd and 4th latest epochs as justified + # mock the 2nd latest epoch as justifiable, with 4th as source + add_mock_attestations(spec, state, + epoch=epoch - 2, + att_ratio=support, + source=c4, + target=c2) + + # process! + yield from run_process_just_and_fin(spec, state) + + if support >= (2 / 3): + assert state.previous_justified_checkpoint == c3 # changed to old current + assert state.current_justified_checkpoint == c2 # changed to 2nd latest + assert state.finalized_checkpoint == c4 # finalized old previous justified epoch + else: + assert state.previous_justified_checkpoint == c3 # changed to old current + assert state.current_justified_checkpoint == c3 # still old current + assert state.finalized_checkpoint == old_finalized # no new finalized + + +def finalize_on_23(spec, state, epoch, support): + assert epoch > 3 + state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch + + # 43210 -- epochs ago + # 3210x -- justification bitfield indices + # 01*0. -- justification bitfield contents, . = this epoch, * is being justified now + # checkpoints for the epochs ago: + # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) + c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) + c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) + # c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + + old_finalized = state.finalized_checkpoint + state.previous_justified_checkpoint = c3 + state.current_justified_checkpoint = c3 + bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + bits[2] = 1 # mock 3rd latest epoch as justified + # mock the 2nd latest epoch as justifiable, with 3rd as source + add_mock_attestations(spec, state, + epoch=epoch - 2, + att_ratio=support, + source=c3, + target=c2) + + # process! + yield from run_process_just_and_fin(spec, state) + + if support >= (2 / 3): + assert state.previous_justified_checkpoint == c3 # changed to old current + assert state.current_justified_checkpoint == c2 # changed to 2nd latest + assert state.finalized_checkpoint == c3 # finalized old previous justified epoch + else: + assert state.previous_justified_checkpoint == c3 # changed to old current + assert state.current_justified_checkpoint == c3 # still old current + assert state.finalized_checkpoint == old_finalized # no new finalized + + +def finalize_on_123(spec, state, epoch, support): + assert epoch > 3 + state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch + + # 43210 -- epochs ago + # 3210x -- justification bitfield indices + # 011*. -- justification bitfield contents, . = this epoch, * is being justified now + # checkpoints for the epochs ago: + # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) + c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) + c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) + c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + + old_finalized = state.finalized_checkpoint + state.previous_justified_checkpoint = c3 + state.current_justified_checkpoint = c2 + bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + bits[1:2] = [1, 1] # mock 2rd and 3th latest epochs as justified + # mock the 1st latest epoch as justifiable, with 3rd as source + add_mock_attestations(spec, state, + epoch=epoch - 1, + att_ratio=support, + source=c3, + target=c1) + + # process! + yield from run_process_just_and_fin(spec, state) + + if support >= (2 / 3): + assert state.previous_justified_checkpoint == c2 # changed to old current + assert state.current_justified_checkpoint == c1 # changed to 1st latest + assert state.finalized_checkpoint == c2 # finalized old current + else: + assert state.previous_justified_checkpoint == c2 # changed to old current + assert state.current_justified_checkpoint == c2 # still old current + assert state.finalized_checkpoint == old_finalized # no new finalized + + +def finalize_on_12(spec, state, epoch, support): + assert epoch > 2 + state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch + + # 43210 -- epochs ago + # 3210 -- justification bitfield indices + # 001*. -- justification bitfield contents, . = this epoch, * is being justified now + # checkpoints for the epochs ago: + # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) + # c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) + c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) + c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + + old_finalized = state.finalized_checkpoint + state.previous_justified_checkpoint = c2 + state.current_justified_checkpoint = c2 + bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + bits[3] = 1 # mock 3rd latest epoch as justified + # mock the 1st latest epoch as justifiable, with 2nd as source + add_mock_attestations(spec, state, + epoch=epoch - 1, + att_ratio=support, + source=c2, + target=c1) + + # process! + yield from run_process_just_and_fin(spec, state) + + if support >= (2 / 3): + assert state.previous_justified_checkpoint == c2 # changed to old current + assert state.current_justified_checkpoint == c1 # changed to 1st latest + assert state.finalized_checkpoint == c2 # finalized previous justified epoch + else: + assert state.previous_justified_checkpoint == c2 # changed to old current + assert state.current_justified_checkpoint == c2 # still old current + assert state.finalized_checkpoint == old_finalized # no new finalized @with_all_phases @spec_state_test -def test_rule_1(spec, state): - # previous_epoch = spec.get_previous_epoch(state) - # current_epoch = spec.get_current_epoch(state) +def test_234_ok_support(spec, state): + yield from finalize_on_234(spec, state, 5, 1.0) - # TODO - # add_mock_attestations(spec, state, ...) - # get indices attesting e.g. current_epoch_attestations - # set their balances - # yield from run_process_just_and_fin(spec, state) - # check finalization - pass + +@with_all_phases +@spec_state_test +def test_234_poor_support(spec, state): + yield from finalize_on_234(spec, state, 5, 0.6) + + +@with_all_phases +@spec_state_test +def test_23_ok_support(spec, state): + yield from finalize_on_23(spec, state, 4, 1.0) + + +@with_all_phases +@spec_state_test +def test_23_poor_support(spec, state): + yield from finalize_on_23(spec, state, 4, 0.6) + + +@with_all_phases +@spec_state_test +def test_123_ok_support(spec, state): + yield from finalize_on_123(spec, state, 4, 1.0) + + +@with_all_phases +@spec_state_test +def test_123_poor_support(spec, state): + yield from finalize_on_123(spec, state, 4, 0.6) + + +@with_all_phases +@spec_state_test +def test_12_ok_support(spec, state): + yield from finalize_on_12(spec, state, 3, 1.0) + + +@with_all_phases +@spec_state_test +def test_12_poor_support(spec, state): + yield from finalize_on_12(spec, state, 3, 0.6) + + +# TODO: bring ratios closer to 2/3 for edge case testing. From f484b1e98c44564c33672d49da23a42ed38ccc22 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 23:18:22 -0600 Subject: [PATCH 062/112] some fixes to finality_12 --- .../test_process_justification_and_finalization.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 0afa4f307..b1d94c4fb 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -189,12 +189,14 @@ def finalize_on_12(spec, state, epoch, support): # c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root + state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root old_finalized = state.finalized_checkpoint state.previous_justified_checkpoint = c2 state.current_justified_checkpoint = c2 - bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - bits[3] = 1 # mock 3rd latest epoch as justified + state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + state.justification_bits[0] = 1 # mock latest epoch as justified # mock the 1st latest epoch as justifiable, with 2nd as source add_mock_attestations(spec, state, epoch=epoch - 1, From 1885e285e3b57a51450910e77e19cf6d505b34c6 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 23:28:36 -0600 Subject: [PATCH 063/112] fix source/target epochs in test_12 --- .../test_process_justification_and_finalization.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index b1d94c4fb..afb25fdae 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -187,8 +187,8 @@ def finalize_on_12(spec, state, epoch, support): # checkpoints for the epochs ago: # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) # c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) - c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + c2 = spec.Checkpoint(epoch=epoch - 1, root=b'\xbb' * 32) + c1 = spec.Checkpoint(epoch=epoch, root=b'\xcc' * 32) state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root From bc5e947efc01141909aaf952167d6b20e6eb9d63 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 23:38:14 -0600 Subject: [PATCH 064/112] aggregation_bitfield - bits --- .../test_process_justification_and_finalization.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index afb25fdae..879c982f0 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -49,10 +49,10 @@ def add_mock_attestations(spec, state, epoch, att_ratio, source, target): # Create a bitfield filled with the given count per attestation, # exactly on the right-most part of the committee field. attesting_count = math.ceil(size * att_ratio) - aggregation_bitfield = ((1 << attesting_count) - 1).to_bytes(length=((size + 7) // 8), byteorder='big') + aggregation_bits = [i < attesting_count for i in range(size)] attestations.append(spec.PendingAttestation( - aggregation_bitfield=aggregation_bitfield, + aggregation_bits=aggregation_bits, data=spec.AttestationData( beacon_block_root=b'\xaa' * 32, source=source, From 022f1e7108a2d6971c147b22a3fef2b0aacebbc9 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 28 Jun 2019 23:59:20 -0600 Subject: [PATCH 065/112] fix source/target --- .../test_process_justification_and_finalization.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 879c982f0..246f20c9e 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -56,7 +56,7 @@ def add_mock_attestations(spec, state, epoch, att_ratio, source, target): data=spec.AttestationData( beacon_block_root=b'\xaa' * 32, source=source, - target=source, + target=target, crosslink=spec.Crosslink() ), inclusion_delay=1, @@ -187,8 +187,8 @@ def finalize_on_12(spec, state, epoch, support): # checkpoints for the epochs ago: # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) # c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) - c2 = spec.Checkpoint(epoch=epoch - 1, root=b'\xbb' * 32) - c1 = spec.Checkpoint(epoch=epoch, root=b'\xcc' * 32) + c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) + c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root From 129fd6297e1218f0655dda2bf8eb2b49a75bd387 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sat, 29 Jun 2019 00:03:06 -0600 Subject: [PATCH 066/112] add shard to mock crosslink to separate attestations from eachother --- .../test_process_justification_and_finalization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 246f20c9e..adcf6ea1d 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -57,7 +57,7 @@ def add_mock_attestations(spec, state, epoch, att_ratio, source, target): beacon_block_root=b'\xaa' * 32, source=source, target=target, - crosslink=spec.Crosslink() + crosslink=spec.Crosslink(shard=shard) ), inclusion_delay=1, )) From ad943bbd06def7e25918ffaa3c39793175741176 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 08:39:27 +0100 Subject: [PATCH 067/112] Make deposit root the root of an SSZ vector --- deposit_contract/contracts/validator_registration.v.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deposit_contract/contracts/validator_registration.v.py b/deposit_contract/contracts/validator_registration.v.py index 14f100520..0c129dac4 100644 --- a/deposit_contract/contracts/validator_registration.v.py +++ b/deposit_contract/contracts/validator_registration.v.py @@ -43,7 +43,8 @@ def to_little_endian_64(value: uint256) -> bytes[8]: @public @constant def get_deposit_root() -> bytes32: - node: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 + zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 + node: bytes32 = zero_bytes32 size: uint256 = self.deposit_count for height in range(DEPOSIT_CONTRACT_TREE_DEPTH): if bitwise_and(size, 1) == 1: # More gas efficient than `size % 2 == 1` @@ -51,7 +52,7 @@ def get_deposit_root() -> bytes32: else: node = sha256(concat(node, self.zero_hashes[height])) size /= 2 - return node + return sha256(concat(node, slice(zero_bytes32, start=0, len=24), self.to_little_endian_64(deposit_amount)) @public From d820dbd7b1b402076ff7195db43fe826db19ebb0 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 09:01:05 +0100 Subject: [PATCH 068/112] Compile contract --- deposit_contract/contracts/validator_registration.json | 2 +- deposit_contract/contracts/validator_registration.v.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deposit_contract/contracts/validator_registration.json b/deposit_contract/contracts/validator_registration.json index 1988b28c0..5f154fa4c 100644 --- a/deposit_contract/contracts/validator_registration.json +++ b/deposit_contract/contracts/validator_registration.json @@ -1 +1 @@ -{"abi": [{"name": "Deposit", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_deposit_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 79221}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 10433}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}], "constant": false, "payable": true, "type": "function", "gas": 1334417}], "bytecode": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b50506111c656600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63c5f2892f60005114156103cf57341561029057600080fd5b6000610140526001546101605261018060006020818352015b600160016101605116141561032a57600061018051602081106102cb57600080fd5b600060c052602060c02001546020826102200101526020810190506101405160208261022001015260208101905080610220526102209050602060c0825160208401600060025af161031c57600080fd5b60c051905061014052610398565b6000610140516020826101a0010152602081019050610180516020811061035057600080fd5b600260c052602060c02001546020826101a0010152602081019050806101a0526101a09050602060c0825160208401600060025af161038e57600080fd5b60c0519050610140525b61016060026103a657600080fd5b60028151048152505b81516001018083528114156102a9575b50506101405160005260206000f3005b63621fd13060005114156104e15734156103e857600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f8201039050610220511015156104335761044c565b610220516101e001526102205160200161022052610411565b6101c0805160200180610280828460006004600a8704601201f161046f57600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156104a1576104bd565b60006102e0516102a001535b8151600101808352811415610491575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561103b57606060046101403760506004356004016101a037603060043560040135111561051757600080fd5b604060243560040161022037602060243560040135111561053757600080fd5b608060443560040161028037606060443560040135111561055757600080fd5b63ffffffff6001541061056957600080fd5b633b9aca00610340526103405161057f57600080fd5b61034051340461032052633b9aca0061032051101561059d57600080fd5b60306101a051146105ad57600080fd5b602061022051146105bd57600080fd5b606061028051146105cd57600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a05110151561065d57610676565b6104a05161046001526104a0516020016104a05261063b565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f16106dd57600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a05110151561078e576107a7565b6105a05161056001526105a0516020016105a05261076c565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161082e57600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161086657600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156108a4576108c1565b6000610620516020850101535b8151600101808352811415610893575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f161091857600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b836106205110151561095657610973565b6000610620516020850101535b8151600101808352811415610945575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f16109ca57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a0857610a25565b6000610620516020850101535b81516001018083528114156109f7575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610a7c57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610aba57610ad7565b6000610620516020850101535b8151600101808352811415610aa9575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610b2e57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b6c57610b89565b6000610620516020850101535b8151600101808352811415610b5b575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527fdc5fc95703516abd38fa03c3737ff3b52dc52347055c8028460fdf5bbe2f12ce61064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610c2057600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610c8057600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610ca957600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610ce957600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610d1d57600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610d9a57600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610dd157600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610e3757600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610e8c57600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af1610eff57600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af1610f3657600080fd5b60c0519050610b00526001805460018254011015610f5357600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d2051161415610fa357610b0051610d405160208110610f9257600080fd5b600060c052602060c0200155611037565b6000610d405160208110610fb657600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161100757600080fd5b60c0519050610b0052610d20600261101e57600080fd5b60028151048152505b8151600101808352811415610f6e575b5050005b60006000fd5b6101856111c6036101856000396101856111c6036000f3"} \ No newline at end of file +{"abi": [{"name": "Deposit", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_deposit_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 91830}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 10433}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}], "constant": false, "payable": true, "type": "function", "gas": 1334417}], "bytecode": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b505061136756600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63c5f2892f600051141561057057341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905060006018602082066102c001602082840111156103fa57600080fd5b6020806102e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f15050805182019150506101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e051610300516103205163806732896103405260015461036052610360516006580161009b565b506103c0526000610420525b6103c05160206001820306601f8201039050610420511015156104c2576104db565b610420516103e0015261042051602001610420526104a0565b61032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526101805261016052610140526103c060088060208461044001018260208501600060046012f150508051820191505080610440526104409050602060c0825160208401600060025af161056157600080fd5b60c051905060005260206000f3005b63621fd130600051141561068257341561058957600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f8201039050610220511015156105d4576105ed565b610220516101e0015261022051602001610220526105b2565b6101c0805160200180610280828460006004600a8704601201f161061057600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156106425761065e565b60006102e0516102a001535b8151600101808352811415610632575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d60005114156111dc57606060046101403760506004356004016101a03760306004356004013511156106b857600080fd5b60406024356004016102203760206024356004013511156106d857600080fd5b60806044356004016102803760606044356004013511156106f857600080fd5b63ffffffff6001541061070a57600080fd5b633b9aca00610340526103405161072057600080fd5b61034051340461032052633b9aca0061032051101561073e57600080fd5b60306101a0511461074e57600080fd5b6020610220511461075e57600080fd5b6060610280511461076e57600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a0511015156107fe57610817565b6104a05161046001526104a0516020016104a0526107dc565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161087e57600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a05110151561092f57610948565b6105a05161056001526105a0516020016105a05261090d565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f16109cf57600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f1610a0757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b8361062051101515610a4557610a62565b6000610620516020850101535b8151600101808352811415610a34575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610ab957600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610af757610b14565b6000610620516020850101535b8151600101808352811415610ae6575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b6b57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ba957610bc6565b6000610620516020850101535b8151600101808352811415610b98575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610c1d57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610c5b57610c78565b6000610620516020850101535b8151600101808352811415610c4a575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610ccf57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610d0d57610d2a565b6000610620516020850101535b8151600101808352811415610cfc575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527fdc5fc95703516abd38fa03c3737ff3b52dc52347055c8028460fdf5bbe2f12ce61064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610dc157600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610e2157600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610e4a57600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e8a57600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610ebe57600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610f3b57600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f7257600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610fd857600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba0016020828401111561102d57600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af16110a057600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af16110d757600080fd5b60c0519050610b005260018054600182540110156110f457600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d205116141561114457610b0051610d40516020811061113357600080fd5b600060c052602060c02001556111d8565b6000610d40516020811061115757600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af16111a857600080fd5b60c0519050610b0052610d2060026111bf57600080fd5b60028151048152505b815160010180835281141561110f575b5050005b60006000fd5b61018561136703610185600039610185611367036000f3"} \ No newline at end of file diff --git a/deposit_contract/contracts/validator_registration.v.py b/deposit_contract/contracts/validator_registration.v.py index 0c129dac4..c1f3c6c79 100644 --- a/deposit_contract/contracts/validator_registration.v.py +++ b/deposit_contract/contracts/validator_registration.v.py @@ -52,7 +52,7 @@ def get_deposit_root() -> bytes32: else: node = sha256(concat(node, self.zero_hashes[height])) size /= 2 - return sha256(concat(node, slice(zero_bytes32, start=0, len=24), self.to_little_endian_64(deposit_amount)) + return sha256(concat(node, slice(zero_bytes32, start=0, len=24), self.to_little_endian_64(self.deposit_count))) @public From 34b8d8ab335c31b451d0cfb46fc78cdab723b4f5 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 09:13:42 +0100 Subject: [PATCH 069/112] Start modifying test --- deposit_contract/tests/contracts/test_deposit.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/deposit_contract/tests/contracts/test_deposit.py b/deposit_contract/tests/contracts/test_deposit.py index 783af3356..80c3b11c1 100644 --- a/deposit_contract/tests/contracts/test_deposit.py +++ b/deposit_contract/tests/contracts/test_deposit.py @@ -15,6 +15,7 @@ from eth2spec.phase0.spec import ( DepositData, ) from eth2spec.utils.hash_function import hash +from eth2spec.utils.ssz.ssz_typing import List from eth2spec.utils.ssz.ssz_impl import ( hash_tree_root, ) @@ -137,7 +138,7 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input ) deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(10)] - leaf_nodes = [] + deposit_data_list = List[DepositData, 2**32]() for i in range(0, 10): tx_hash = registration_contract.functions.deposit( *deposit_input, @@ -151,13 +152,11 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input assert log["index"] == i.to_bytes(8, 'little') - deposit_data = DepositData( + deposit_data_list[i] = DepositData( pubkey=deposit_input[0], withdrawal_credentials=deposit_input[1], amount=deposit_amount_list[i], signature=deposit_input[2], ) - hash_tree_root_result = hash_tree_root(deposit_data) - leaf_nodes.append(hash_tree_root_result) - root = compute_merkle_root(leaf_nodes) + root = hash_tree_root(deposit_data_list) assert root == registration_contract.functions.get_deposit_root().call() From d5d3e49c5f7958a717740c8a13538116a3cd952f Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 09:25:19 +0100 Subject: [PATCH 070/112] Tests pass --- .../contracts/validator_registration.json | 2 +- .../contracts/validator_registration.v.py | 2 +- .../tests/contracts/test_deposit.py | 196 ++++++++---------- 3 files changed, 93 insertions(+), 107 deletions(-) diff --git a/deposit_contract/contracts/validator_registration.json b/deposit_contract/contracts/validator_registration.json index 5f154fa4c..a3d309269 100644 --- a/deposit_contract/contracts/validator_registration.json +++ b/deposit_contract/contracts/validator_registration.json @@ -1 +1 @@ -{"abi": [{"name": "Deposit", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_deposit_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 91830}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 10433}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}], "constant": false, "payable": true, "type": "function", "gas": 1334417}], "bytecode": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b505061136756600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63c5f2892f600051141561057057341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905060006018602082066102c001602082840111156103fa57600080fd5b6020806102e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f15050805182019150506101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e051610300516103205163806732896103405260015461036052610360516006580161009b565b506103c0526000610420525b6103c05160206001820306601f8201039050610420511015156104c2576104db565b610420516103e0015261042051602001610420526104a0565b61032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526101805261016052610140526103c060088060208461044001018260208501600060046012f150508051820191505080610440526104409050602060c0825160208401600060025af161056157600080fd5b60c051905060005260206000f3005b63621fd130600051141561068257341561058957600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f8201039050610220511015156105d4576105ed565b610220516101e0015261022051602001610220526105b2565b6101c0805160200180610280828460006004600a8704601201f161061057600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156106425761065e565b60006102e0516102a001535b8151600101808352811415610632575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d60005114156111dc57606060046101403760506004356004016101a03760306004356004013511156106b857600080fd5b60406024356004016102203760206024356004013511156106d857600080fd5b60806044356004016102803760606044356004013511156106f857600080fd5b63ffffffff6001541061070a57600080fd5b633b9aca00610340526103405161072057600080fd5b61034051340461032052633b9aca0061032051101561073e57600080fd5b60306101a0511461074e57600080fd5b6020610220511461075e57600080fd5b6060610280511461076e57600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a0511015156107fe57610817565b6104a05161046001526104a0516020016104a0526107dc565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161087e57600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a05110151561092f57610948565b6105a05161056001526105a0516020016105a05261090d565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f16109cf57600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f1610a0757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b8361062051101515610a4557610a62565b6000610620516020850101535b8151600101808352811415610a34575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610ab957600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610af757610b14565b6000610620516020850101535b8151600101808352811415610ae6575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b6b57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ba957610bc6565b6000610620516020850101535b8151600101808352811415610b98575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610c1d57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610c5b57610c78565b6000610620516020850101535b8151600101808352811415610c4a575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610ccf57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610d0d57610d2a565b6000610620516020850101535b8151600101808352811415610cfc575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527fdc5fc95703516abd38fa03c3737ff3b52dc52347055c8028460fdf5bbe2f12ce61064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610dc157600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610e2157600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610e4a57600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e8a57600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610ebe57600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610f3b57600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f7257600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610fd857600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba0016020828401111561102d57600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af16110a057600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af16110d757600080fd5b60c0519050610b005260018054600182540110156110f457600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d205116141561114457610b0051610d40516020811061113357600080fd5b600060c052602060c02001556111d8565b6000610d40516020811061115757600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af16111a857600080fd5b60c0519050610b0052610d2060026111bf57600080fd5b60028151048152505b815160010180835281141561110f575b5050005b60006000fd5b61018561136703610185600039610185611367036000f3"} \ No newline at end of file +{"abi": [{"name": "Deposit", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_deposit_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 91674}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 10433}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}], "constant": false, "payable": true, "type": "function", "gas": 1334417}], "bytecode": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b50506112ff56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63c5f2892f600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527fdc5fc95703516abd38fa03c3737ff3b52dc52347055c8028460fdf5bbe2f12ce61064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b6101856112ff036101856000396101856112ff036000f3"} \ No newline at end of file diff --git a/deposit_contract/contracts/validator_registration.v.py b/deposit_contract/contracts/validator_registration.v.py index c1f3c6c79..b49cc45e1 100644 --- a/deposit_contract/contracts/validator_registration.v.py +++ b/deposit_contract/contracts/validator_registration.v.py @@ -52,7 +52,7 @@ def get_deposit_root() -> bytes32: else: node = sha256(concat(node, self.zero_hashes[height])) size /= 2 - return sha256(concat(node, slice(zero_bytes32, start=0, len=24), self.to_little_endian_64(self.deposit_count))) + return sha256(concat(node, self.to_little_endian_64(self.deposit_count), slice(zero_bytes32, start=0, len=24))) @public diff --git a/deposit_contract/tests/contracts/test_deposit.py b/deposit_contract/tests/contracts/test_deposit.py index 80c3b11c1..58e4158a3 100644 --- a/deposit_contract/tests/contracts/test_deposit.py +++ b/deposit_contract/tests/contracts/test_deposit.py @@ -21,116 +21,101 @@ from eth2spec.utils.ssz.ssz_impl import ( ) -def compute_merkle_root(leaf_nodes): - assert len(leaf_nodes) >= 1 - empty_node = b'\x00' * 32 - child_nodes = leaf_nodes[:] - for _ in range(DEPOSIT_CONTRACT_TREE_DEPTH): - parent_nodes = [] - if len(child_nodes) % 2 == 1: - child_nodes.append(empty_node) - for j in range(0, len(child_nodes), 2): - parent_nodes.append(hash(child_nodes[j] + child_nodes[j + 1])) - child_nodes = parent_nodes - empty_node = hash(empty_node + empty_node) - return child_nodes[0] +# @pytest.fixture +# def deposit_input(): +# """ +# pubkey: bytes[48] +# withdrawal_credentials: bytes[32] +# signature: bytes[96] +# """ +# return ( +# b'\x11' * 48, +# b'\x22' * 32, +# b'\x33' * 96, +# ) -@pytest.fixture -def deposit_input(): - """ - pubkey: bytes[48] - withdrawal_credentials: bytes[32] - signature: bytes[96] - """ - return ( - b'\x11' * 48, - b'\x22' * 32, - b'\x33' * 96, - ) +# @pytest.mark.parametrize( +# 'success,deposit_amount', +# [ +# (True, FULL_DEPOSIT_AMOUNT), +# (True, MIN_DEPOSIT_AMOUNT), +# (False, MIN_DEPOSIT_AMOUNT - 1), +# (True, FULL_DEPOSIT_AMOUNT + 1) +# ] +# ) +# def test_deposit_amount(registration_contract, +# w3, +# success, +# deposit_amount, +# assert_tx_failed, +# deposit_input): +# call = registration_contract.functions.deposit(*deposit_input) +# if success: +# assert call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) +# else: +# assert_tx_failed( +# lambda: call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) +# ) -@pytest.mark.parametrize( - 'success,deposit_amount', - [ - (True, FULL_DEPOSIT_AMOUNT), - (True, MIN_DEPOSIT_AMOUNT), - (False, MIN_DEPOSIT_AMOUNT - 1), - (True, FULL_DEPOSIT_AMOUNT + 1) - ] -) -def test_deposit_amount(registration_contract, - w3, - success, - deposit_amount, - assert_tx_failed, - deposit_input): - call = registration_contract.functions.deposit(*deposit_input) - if success: - assert call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) - else: - assert_tx_failed( - lambda: call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) - ) +# @pytest.mark.parametrize( +# 'invalid_pubkey,invalid_withdrawal_credentials,invalid_signature,success', +# [ +# (False, False, False, True), +# (True, False, False, False), +# (False, True, False, False), +# (False, False, True, False), +# ] +# ) +# def test_deposit_inputs(registration_contract, +# w3, +# assert_tx_failed, +# deposit_input, +# invalid_pubkey, +# invalid_withdrawal_credentials, +# invalid_signature, +# success): +# pubkey = deposit_input[0][2:] if invalid_pubkey else deposit_input[0] +# if invalid_withdrawal_credentials: # this one is different to satisfy linter +# withdrawal_credentials = deposit_input[1][2:] +# else: +# withdrawal_credentials = deposit_input[1] +# signature = deposit_input[2][2:] if invalid_signature else deposit_input[2] + +# call = registration_contract.functions.deposit( +# pubkey, +# withdrawal_credentials, +# signature, +# ) +# if success: +# assert call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) +# else: +# assert_tx_failed( +# lambda: call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) +# ) -@pytest.mark.parametrize( - 'invalid_pubkey,invalid_withdrawal_credentials,invalid_signature,success', - [ - (False, False, False, True), - (True, False, False, False), - (False, True, False, False), - (False, False, True, False), - ] -) -def test_deposit_inputs(registration_contract, - w3, - assert_tx_failed, - deposit_input, - invalid_pubkey, - invalid_withdrawal_credentials, - invalid_signature, - success): - pubkey = deposit_input[0][2:] if invalid_pubkey else deposit_input[0] - if invalid_withdrawal_credentials: # this one is different to satisfy linter - withdrawal_credentials = deposit_input[1][2:] - else: - withdrawal_credentials = deposit_input[1] - signature = deposit_input[2][2:] if invalid_signature else deposit_input[2] +# def test_deposit_log(registration_contract, a0, w3, deposit_input): +# log_filter = registration_contract.events.Deposit.createFilter( +# fromBlock='latest', +# ) - call = registration_contract.functions.deposit( - pubkey, - withdrawal_credentials, - signature, - ) - if success: - assert call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) - else: - assert_tx_failed( - lambda: call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) - ) +# deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(3)] +# for i in range(3): +# registration_contract.functions.deposit( +# *deposit_input, +# ).transact({"value": deposit_amount_list[i] * eth_utils.denoms.gwei}) +# logs = log_filter.get_new_entries() +# assert len(logs) == 1 +# log = logs[0]['args'] -def test_deposit_log(registration_contract, a0, w3, deposit_input): - log_filter = registration_contract.events.Deposit.createFilter( - fromBlock='latest', - ) - - deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(3)] - for i in range(3): - registration_contract.functions.deposit( - *deposit_input, - ).transact({"value": deposit_amount_list[i] * eth_utils.denoms.gwei}) - - logs = log_filter.get_new_entries() - assert len(logs) == 1 - log = logs[0]['args'] - - assert log['pubkey'] == deposit_input[0] - assert log['withdrawal_credentials'] == deposit_input[1] - assert log['amount'] == deposit_amount_list[i].to_bytes(8, 'little') - assert log['signature'] == deposit_input[2] - assert log['index'] == i.to_bytes(8, 'little') +# assert log['pubkey'] == deposit_input[0] +# assert log['withdrawal_credentials'] == deposit_input[1] +# assert log['amount'] == deposit_amount_list[i].to_bytes(8, 'little') +# assert log['signature'] == deposit_input[2] +# assert log['index'] == i.to_bytes(8, 'little') def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input): log_filter = registration_contract.events.Deposit.createFilter( @@ -138,7 +123,7 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input ) deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(10)] - deposit_data_list = List[DepositData, 2**32]() + deposit_data_list = [] for i in range(0, 10): tx_hash = registration_contract.functions.deposit( *deposit_input, @@ -152,11 +137,12 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input assert log["index"] == i.to_bytes(8, 'little') - deposit_data_list[i] = DepositData( + deposit_data_list.append(DepositData( pubkey=deposit_input[0], withdrawal_credentials=deposit_input[1], amount=deposit_amount_list[i], signature=deposit_input[2], - ) - root = hash_tree_root(deposit_data_list) + )) + + root = hash_tree_root(List[DepositData, 2**32](*(tuple(deposit_data_list)))) assert root == registration_contract.functions.get_deposit_root().call() From a7ceec1e8a6a68a4ba6bf96be4f22f91be0ceffa Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 09:28:46 +0100 Subject: [PATCH 071/112] Uncomment tests --- .../tests/contracts/test_deposit.py | 171 +++++++++--------- 1 file changed, 86 insertions(+), 85 deletions(-) diff --git a/deposit_contract/tests/contracts/test_deposit.py b/deposit_contract/tests/contracts/test_deposit.py index 58e4158a3..94c7b29d1 100644 --- a/deposit_contract/tests/contracts/test_deposit.py +++ b/deposit_contract/tests/contracts/test_deposit.py @@ -21,101 +21,102 @@ from eth2spec.utils.ssz.ssz_impl import ( ) -# @pytest.fixture -# def deposit_input(): -# """ -# pubkey: bytes[48] -# withdrawal_credentials: bytes[32] -# signature: bytes[96] -# """ -# return ( -# b'\x11' * 48, -# b'\x22' * 32, -# b'\x33' * 96, -# ) +@pytest.fixture +def deposit_input(): + """ + pubkey: bytes[48] + withdrawal_credentials: bytes[32] + signature: bytes[96] + """ + return ( + b'\x11' * 48, + b'\x22' * 32, + b'\x33' * 96, + ) -# @pytest.mark.parametrize( -# 'success,deposit_amount', -# [ -# (True, FULL_DEPOSIT_AMOUNT), -# (True, MIN_DEPOSIT_AMOUNT), -# (False, MIN_DEPOSIT_AMOUNT - 1), -# (True, FULL_DEPOSIT_AMOUNT + 1) -# ] -# ) -# def test_deposit_amount(registration_contract, -# w3, -# success, -# deposit_amount, -# assert_tx_failed, -# deposit_input): -# call = registration_contract.functions.deposit(*deposit_input) -# if success: -# assert call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) -# else: -# assert_tx_failed( -# lambda: call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) -# ) +@pytest.mark.parametrize( + 'success,deposit_amount', + [ + (True, FULL_DEPOSIT_AMOUNT), + (True, MIN_DEPOSIT_AMOUNT), + (False, MIN_DEPOSIT_AMOUNT - 1), + (True, FULL_DEPOSIT_AMOUNT + 1) + ] +) +def test_deposit_amount(registration_contract, + w3, + success, + deposit_amount, + assert_tx_failed, + deposit_input): + call = registration_contract.functions.deposit(*deposit_input) + if success: + assert call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) + else: + assert_tx_failed( + lambda: call.transact({"value": deposit_amount * eth_utils.denoms.gwei}) + ) -# @pytest.mark.parametrize( -# 'invalid_pubkey,invalid_withdrawal_credentials,invalid_signature,success', -# [ -# (False, False, False, True), -# (True, False, False, False), -# (False, True, False, False), -# (False, False, True, False), -# ] -# ) -# def test_deposit_inputs(registration_contract, -# w3, -# assert_tx_failed, -# deposit_input, -# invalid_pubkey, -# invalid_withdrawal_credentials, -# invalid_signature, -# success): -# pubkey = deposit_input[0][2:] if invalid_pubkey else deposit_input[0] -# if invalid_withdrawal_credentials: # this one is different to satisfy linter -# withdrawal_credentials = deposit_input[1][2:] -# else: -# withdrawal_credentials = deposit_input[1] -# signature = deposit_input[2][2:] if invalid_signature else deposit_input[2] +@pytest.mark.parametrize( + 'invalid_pubkey,invalid_withdrawal_credentials,invalid_signature,success', + [ + (False, False, False, True), + (True, False, False, False), + (False, True, False, False), + (False, False, True, False), + ] +) +def test_deposit_inputs(registration_contract, + w3, + assert_tx_failed, + deposit_input, + invalid_pubkey, + invalid_withdrawal_credentials, + invalid_signature, + success): + pubkey = deposit_input[0][2:] if invalid_pubkey else deposit_input[0] + if invalid_withdrawal_credentials: # this one is different to satisfy linter + withdrawal_credentials = deposit_input[1][2:] + else: + withdrawal_credentials = deposit_input[1] + signature = deposit_input[2][2:] if invalid_signature else deposit_input[2] -# call = registration_contract.functions.deposit( -# pubkey, -# withdrawal_credentials, -# signature, -# ) -# if success: -# assert call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) -# else: -# assert_tx_failed( -# lambda: call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) -# ) + call = registration_contract.functions.deposit( + pubkey, + withdrawal_credentials, + signature, + ) + if success: + assert call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) + else: + assert_tx_failed( + lambda: call.transact({"value": FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei}) + ) -# def test_deposit_log(registration_contract, a0, w3, deposit_input): -# log_filter = registration_contract.events.Deposit.createFilter( -# fromBlock='latest', -# ) +def test_deposit_log(registration_contract, a0, w3, deposit_input): + log_filter = registration_contract.events.Deposit.createFilter( + fromBlock='latest', + ) -# deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(3)] -# for i in range(3): -# registration_contract.functions.deposit( -# *deposit_input, -# ).transact({"value": deposit_amount_list[i] * eth_utils.denoms.gwei}) + deposit_amount_list = [randint(MIN_DEPOSIT_AMOUNT, FULL_DEPOSIT_AMOUNT * 2) for _ in range(3)] + for i in range(3): + registration_contract.functions.deposit( + *deposit_input, + ).transact({"value": deposit_amount_list[i] * eth_utils.denoms.gwei}) -# logs = log_filter.get_new_entries() -# assert len(logs) == 1 -# log = logs[0]['args'] + logs = log_filter.get_new_entries() + assert len(logs) == 1 + log = logs[0]['args'] + + assert log['pubkey'] == deposit_input[0] + assert log['withdrawal_credentials'] == deposit_input[1] + assert log['amount'] == deposit_amount_list[i].to_bytes(8, 'little') + assert log['signature'] == deposit_input[2] + assert log['index'] == i.to_bytes(8, 'little') -# assert log['pubkey'] == deposit_input[0] -# assert log['withdrawal_credentials'] == deposit_input[1] -# assert log['amount'] == deposit_amount_list[i].to_bytes(8, 'little') -# assert log['signature'] == deposit_input[2] -# assert log['index'] == i.to_bytes(8, 'little') def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input): log_filter = registration_contract.events.Deposit.createFilter( From 7fdf59d012065e59c4d9e771ce03a9d10cf85530 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sat, 29 Jun 2019 18:09:05 +0800 Subject: [PATCH 072/112] `active_validator_count >= GENESIS_ACTIVE_VALIDATOR_COUNT`: per Eth1 block --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 9e59212fd..7cd5725b1 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1186,7 +1186,7 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], active_validator_count += 1 # Check effective balance to trigger genesis - return active_validator_count == GENESIS_ACTIVE_VALIDATOR_COUNT + return active_validator_count >= GENESIS_ACTIVE_VALIDATOR_COUNT ``` ### Genesis state From b05bebf45c1bfe31fdf9ee195283827be4f145e0 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Sat, 29 Jun 2019 12:23:03 +0200 Subject: [PATCH 073/112] Fix list slicing --- ..._process_justification_and_finalization.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index adcf6ea1d..3e2f6e967 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -74,13 +74,15 @@ def finalize_on_234(spec, state, epoch, support): c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - # c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + state.block_roots[spec.get_epoch_start_slot(c4.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c4.root + state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root + state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root old_finalized = state.finalized_checkpoint state.previous_justified_checkpoint = c4 state.current_justified_checkpoint = c3 - bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - bits[3:4] = [1, 1] # mock 3rd and 4th latest epochs as justified + state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + state.justification_bits[1:3] = [1, 1] # mock 3rd and 4th latest epochs as justified # mock the 2nd latest epoch as justifiable, with 4th as source add_mock_attestations(spec, state, epoch=epoch - 2, @@ -109,16 +111,16 @@ def finalize_on_23(spec, state, epoch, support): # 3210x -- justification bitfield indices # 01*0. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - # c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root + state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root old_finalized = state.finalized_checkpoint state.previous_justified_checkpoint = c3 state.current_justified_checkpoint = c3 - bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - bits[2] = 1 # mock 3rd latest epoch as justified + state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + state.justification_bits[1] = 1 # mock 2nd latest epoch as justified # mock the 2nd latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 2, @@ -147,16 +149,18 @@ def finalize_on_123(spec, state, epoch, support): # 3210x -- justification bitfield indices # 011*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root + state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root + state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root old_finalized = state.finalized_checkpoint state.previous_justified_checkpoint = c3 state.current_justified_checkpoint = c2 - bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - bits[1:2] = [1, 1] # mock 2rd and 3th latest epochs as justified + state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() + state.justification_bits[0:2] = [1, 1] # mock 1st and 2nd latest epochs as justified # mock the 1st latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 1, @@ -185,8 +189,6 @@ def finalize_on_12(spec, state, epoch, support): # 3210 -- justification bitfield indices # 001*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - # c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) - # c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root From f9ca7c97c9bc4d994ba88ee721afcfc04336673b Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Sat, 29 Jun 2019 13:01:59 +0200 Subject: [PATCH 074/112] Fix 123 finalisation --- .../test_process_justification_and_finalization.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 3e2f6e967..42ef73084 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -149,6 +149,7 @@ def finalize_on_123(spec, state, epoch, support): # 3210x -- justification bitfield indices # 011*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: + c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) @@ -157,7 +158,7 @@ def finalize_on_123(spec, state, epoch, support): state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root old_finalized = state.finalized_checkpoint - state.previous_justified_checkpoint = c3 + state.previous_justified_checkpoint = c4 state.current_justified_checkpoint = c2 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() state.justification_bits[0:2] = [1, 1] # mock 1st and 2nd latest epochs as justified From 2eca6ef09d6d94656863907ba2fed5213788f213 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Sat, 29 Jun 2019 13:10:09 +0200 Subject: [PATCH 075/112] Corrects justification comments --- .../test_process_justification_and_finalization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 42ef73084..02439f664 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -82,7 +82,7 @@ def finalize_on_234(spec, state, epoch, support): state.previous_justified_checkpoint = c4 state.current_justified_checkpoint = c3 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - state.justification_bits[1:3] = [1, 1] # mock 3rd and 4th latest epochs as justified + state.justification_bits[1:3] = [1, 1] # mock 2nd and 3rd latest epochs as justified # mock the 2nd latest epoch as justifiable, with 4th as source add_mock_attestations(spec, state, epoch=epoch - 2, From 0680d8cc536f72a863d9e9ec1975a2fd5ff1729c Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Sat, 29 Jun 2019 14:35:07 +0200 Subject: [PATCH 076/112] Makes justification ratios more marginal --- ..._process_justification_and_finalization.py | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 02439f664..406bdbf7f 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -25,7 +25,7 @@ def get_committee_size(spec, epoch_start_shard, shard, committee_count, indices) return size -def add_mock_attestations(spec, state, epoch, att_ratio, source, target): +def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False): # we must be at the end of the epoch assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0 @@ -48,7 +48,8 @@ def add_mock_attestations(spec, state, epoch, att_ratio, source, target): size = get_committee_size(spec, epoch_start_shard, shard, committee_count, indices) # Create a bitfield filled with the given count per attestation, # exactly on the right-most part of the committee field. - attesting_count = math.ceil(size * att_ratio) + attesting_count = math.ceil(size * 2 /3) + attesting_count = attesting_count if sufficient_support else attesting_count - 1 aggregation_bits = [i < attesting_count for i in range(size)] attestations.append(spec.PendingAttestation( @@ -63,7 +64,7 @@ def add_mock_attestations(spec, state, epoch, att_ratio, source, target): )) -def finalize_on_234(spec, state, epoch, support): +def finalize_on_234(spec, state, epoch, sufficient_support): assert epoch > 4 state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch @@ -86,14 +87,14 @@ def finalize_on_234(spec, state, epoch, support): # mock the 2nd latest epoch as justifiable, with 4th as source add_mock_attestations(spec, state, epoch=epoch - 2, - att_ratio=support, source=c4, - target=c2) + target=c2, + sufficient_support=sufficient_support) # process! yield from run_process_just_and_fin(spec, state) - if support >= (2 / 3): + if sufficient_support: assert state.previous_justified_checkpoint == c3 # changed to old current assert state.current_justified_checkpoint == c2 # changed to 2nd latest assert state.finalized_checkpoint == c4 # finalized old previous justified epoch @@ -103,7 +104,7 @@ def finalize_on_234(spec, state, epoch, support): assert state.finalized_checkpoint == old_finalized # no new finalized -def finalize_on_23(spec, state, epoch, support): +def finalize_on_23(spec, state, epoch, sufficient_support): assert epoch > 3 state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch @@ -124,14 +125,14 @@ def finalize_on_23(spec, state, epoch, support): # mock the 2nd latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 2, - att_ratio=support, source=c3, - target=c2) + target=c2, + sufficient_support=sufficient_support) # process! yield from run_process_just_and_fin(spec, state) - if support >= (2 / 3): + if sufficient_support: assert state.previous_justified_checkpoint == c3 # changed to old current assert state.current_justified_checkpoint == c2 # changed to 2nd latest assert state.finalized_checkpoint == c3 # finalized old previous justified epoch @@ -141,7 +142,7 @@ def finalize_on_23(spec, state, epoch, support): assert state.finalized_checkpoint == old_finalized # no new finalized -def finalize_on_123(spec, state, epoch, support): +def finalize_on_123(spec, state, epoch, sufficient_support): assert epoch > 3 state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch @@ -165,14 +166,14 @@ def finalize_on_123(spec, state, epoch, support): # mock the 1st latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 1, - att_ratio=support, source=c3, - target=c1) + target=c1, + sufficient_support=sufficient_support) # process! yield from run_process_just_and_fin(spec, state) - if support >= (2 / 3): + if sufficient_support: assert state.previous_justified_checkpoint == c2 # changed to old current assert state.current_justified_checkpoint == c1 # changed to 1st latest assert state.finalized_checkpoint == c2 # finalized old current @@ -182,7 +183,7 @@ def finalize_on_123(spec, state, epoch, support): assert state.finalized_checkpoint == old_finalized # no new finalized -def finalize_on_12(spec, state, epoch, support): +def finalize_on_12(spec, state, epoch, sufficient_support): assert epoch > 2 state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch @@ -203,14 +204,14 @@ def finalize_on_12(spec, state, epoch, support): # mock the 1st latest epoch as justifiable, with 2nd as source add_mock_attestations(spec, state, epoch=epoch - 1, - att_ratio=support, source=c2, - target=c1) + target=c1, + sufficient_support=sufficient_support) # process! yield from run_process_just_and_fin(spec, state) - if support >= (2 / 3): + if sufficient_support: assert state.previous_justified_checkpoint == c2 # changed to old current assert state.current_justified_checkpoint == c1 # changed to 1st latest assert state.finalized_checkpoint == c2 # finalized previous justified epoch @@ -223,49 +224,46 @@ def finalize_on_12(spec, state, epoch, support): @with_all_phases @spec_state_test def test_234_ok_support(spec, state): - yield from finalize_on_234(spec, state, 5, 1.0) + yield from finalize_on_234(spec, state, 5, True) @with_all_phases @spec_state_test def test_234_poor_support(spec, state): - yield from finalize_on_234(spec, state, 5, 0.6) + yield from finalize_on_234(spec, state, 5, False) @with_all_phases @spec_state_test def test_23_ok_support(spec, state): - yield from finalize_on_23(spec, state, 4, 1.0) + yield from finalize_on_23(spec, state, 4, True) @with_all_phases @spec_state_test def test_23_poor_support(spec, state): - yield from finalize_on_23(spec, state, 4, 0.6) + yield from finalize_on_23(spec, state, 4, False) @with_all_phases @spec_state_test def test_123_ok_support(spec, state): - yield from finalize_on_123(spec, state, 4, 1.0) + yield from finalize_on_123(spec, state, 4, True) @with_all_phases @spec_state_test def test_123_poor_support(spec, state): - yield from finalize_on_123(spec, state, 4, 0.6) + yield from finalize_on_123(spec, state, 4, False) @with_all_phases @spec_state_test def test_12_ok_support(spec, state): - yield from finalize_on_12(spec, state, 3, 1.0) + yield from finalize_on_12(spec, state, 3, True) @with_all_phases @spec_state_test def test_12_poor_support(spec, state): - yield from finalize_on_12(spec, state, 3, 0.6) - - -# TODO: bring ratios closer to 2/3 for edge case testing. + yield from finalize_on_12(spec, state, 3, False) From 4ed7af7bacb2602d97ea67596b8b21d4b019b150 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Sat, 29 Jun 2019 15:48:39 +0200 Subject: [PATCH 077/112] mock attestation refactor --- ..._process_justification_and_finalization.py | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 406bdbf7f..66e2095b4 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -1,4 +1,3 @@ -import math from eth2spec.test.context import spec_state_test, with_all_phases from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import ( run_epoch_processing_with @@ -39,29 +38,37 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support else: raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}") - committee_count = spec.get_epoch_committee_count(state, epoch) - indices = spec.get_active_validator_indices(state, epoch) - epoch_start_shard = spec.get_epoch_start_shard(state, epoch) + total_balance = spec.get_total_active_balance(state) + remaining_balance = total_balance * 2 // 3 + epoch_start_slot = spec.get_epoch_start_slot(epoch) for slot in range(epoch_start_slot, epoch_start_slot + spec.SLOTS_PER_EPOCH): for shard in get_shards_for_slot(spec, state, slot): - size = get_committee_size(spec, epoch_start_shard, shard, committee_count, indices) + committee = spec.get_crosslink_committee(state, spec.slot_to_epoch(slot), shard) # Create a bitfield filled with the given count per attestation, # exactly on the right-most part of the committee field. - attesting_count = math.ceil(size * 2 /3) - attesting_count = attesting_count if sufficient_support else attesting_count - 1 - aggregation_bits = [i < attesting_count for i in range(size)] - attestations.append(spec.PendingAttestation( - aggregation_bits=aggregation_bits, - data=spec.AttestationData( - beacon_block_root=b'\xaa' * 32, - source=source, - target=target, - crosslink=spec.Crosslink(shard=shard) - ), - inclusion_delay=1, - )) + aggregation_bits = [0] * len(committee) + for v in range(len(committee) * 2 // 3 + 1): + if remaining_balance > 0: + remaining_balance -= state.validators[v].effective_balance + aggregation_bits[v] = 1 + elif not sufficient_support: + aggregation_bits[v - 1] = 0 + break + else: + break + + attestations.append(spec.PendingAttestation( + aggregation_bits=aggregation_bits, + data=spec.AttestationData( + beacon_block_root=b'\xaa' * 32, + source=source, + target=target, + crosslink=spec.Crosslink(shard=shard) + ), + inclusion_delay=1, + )) def finalize_on_234(spec, state, epoch, sufficient_support): From b162a8ff8a40f372c1dcfc36b6030b4c9038f225 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 16:48:08 +0200 Subject: [PATCH 078/112] simplify list creation --- deposit_contract/tests/contracts/test_deposit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deposit_contract/tests/contracts/test_deposit.py b/deposit_contract/tests/contracts/test_deposit.py index 94c7b29d1..8c165f0f9 100644 --- a/deposit_contract/tests/contracts/test_deposit.py +++ b/deposit_contract/tests/contracts/test_deposit.py @@ -145,5 +145,5 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input signature=deposit_input[2], )) - root = hash_tree_root(List[DepositData, 2**32](*(tuple(deposit_data_list)))) + root = hash_tree_root(List[DepositData, 2**32](*deposit_data_list)) assert root == registration_contract.functions.get_deposit_root().call() From 0c29c5125f0e890e5bdd7d9e14afd166d0b6b260 Mon Sep 17 00:00:00 2001 From: Carl Beekhuizen Date: Sat, 29 Jun 2019 17:10:12 +0200 Subject: [PATCH 079/112] Finnish refactor --- .../test_process_justification_and_finalization.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 66e2095b4..50a0a0cab 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -16,14 +16,6 @@ def get_shards_for_slot(spec, state, slot): return [shard + i for i in range(committees_per_slot)] -def get_committee_size(spec, epoch_start_shard, shard, committee_count, indices): - committee_index = (shard + spec.SHARD_COUNT - epoch_start_shard) % spec.SHARD_COUNT - start = (len(indices) * committee_index) // committee_count - end = (len(indices) * (committee_index + 1)) // committee_count - size = end - start - return size - - def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False): # we must be at the end of the epoch assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0 From 5d633bfdf36c5b4a9e069e302cecd70bbd782b13 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 18:14:17 +0200 Subject: [PATCH 080/112] bugfix attestation creation so that it works on mainnet with multiple committees per slot, and improve bitfield index descriptions --- ..._process_justification_and_finalization.py | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index 50a0a0cab..d043d8d97 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -36,6 +36,11 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support epoch_start_slot = spec.get_epoch_start_slot(epoch) for slot in range(epoch_start_slot, epoch_start_slot + spec.SLOTS_PER_EPOCH): for shard in get_shards_for_slot(spec, state, slot): + # Check if we already have had sufficient balance. (and undone if we don't want it). + # If so, do not create more attestations. (we do not have empty pending attestations normally anyway) + if remaining_balance < 0: + return + committee = spec.get_crosslink_committee(state, spec.slot_to_epoch(slot), shard) # Create a bitfield filled with the given count per attestation, # exactly on the right-most part of the committee field. @@ -45,22 +50,23 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support if remaining_balance > 0: remaining_balance -= state.validators[v].effective_balance aggregation_bits[v] = 1 - elif not sufficient_support: - aggregation_bits[v - 1] = 0 - break else: break - attestations.append(spec.PendingAttestation( - aggregation_bits=aggregation_bits, - data=spec.AttestationData( - beacon_block_root=b'\xaa' * 32, - source=source, - target=target, - crosslink=spec.Crosslink(shard=shard) - ), - inclusion_delay=1, - )) + # remove just one attester to make the marginal support insufficient + if not sufficient_support: + aggregation_bits[aggregation_bits.index(1)] = 0 + + attestations.append(spec.PendingAttestation( + aggregation_bits=aggregation_bits, + data=spec.AttestationData( + beacon_block_root=b'\xaa' * 32, + source=source, + target=target, + crosslink=spec.Crosslink(shard=shard) + ), + inclusion_delay=1, + )) def finalize_on_234(spec, state, epoch, sufficient_support): @@ -82,7 +88,7 @@ def finalize_on_234(spec, state, epoch, sufficient_support): state.previous_justified_checkpoint = c4 state.current_justified_checkpoint = c3 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - state.justification_bits[1:3] = [1, 1] # mock 2nd and 3rd latest epochs as justified + state.justification_bits[1:3] = [1, 1] # mock 3rd and 4th latest epochs as justified (indices are pre-shift) # mock the 2nd latest epoch as justifiable, with 4th as source add_mock_attestations(spec, state, epoch=epoch - 2, @@ -93,12 +99,11 @@ def finalize_on_234(spec, state, epoch, sufficient_support): # process! yield from run_process_just_and_fin(spec, state) + assert state.previous_justified_checkpoint == c3 # changed to old current if sufficient_support: - assert state.previous_justified_checkpoint == c3 # changed to old current assert state.current_justified_checkpoint == c2 # changed to 2nd latest assert state.finalized_checkpoint == c4 # finalized old previous justified epoch else: - assert state.previous_justified_checkpoint == c3 # changed to old current assert state.current_justified_checkpoint == c3 # still old current assert state.finalized_checkpoint == old_finalized # no new finalized @@ -108,7 +113,8 @@ def finalize_on_23(spec, state, epoch, sufficient_support): state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch # 43210 -- epochs ago - # 3210x -- justification bitfield indices + # 210xx -- justification bitfield indices (pre shift) + # 3210x -- justification bitfield indices (post shift) # 01*0. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) @@ -120,7 +126,7 @@ def finalize_on_23(spec, state, epoch, sufficient_support): state.previous_justified_checkpoint = c3 state.current_justified_checkpoint = c3 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - state.justification_bits[1] = 1 # mock 2nd latest epoch as justified + state.justification_bits[1] = 1 # mock 3rd latest epoch as justified (indices are pre-shift) # mock the 2nd latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 2, @@ -131,12 +137,11 @@ def finalize_on_23(spec, state, epoch, sufficient_support): # process! yield from run_process_just_and_fin(spec, state) + assert state.previous_justified_checkpoint == c3 # changed to old current if sufficient_support: - assert state.previous_justified_checkpoint == c3 # changed to old current assert state.current_justified_checkpoint == c2 # changed to 2nd latest assert state.finalized_checkpoint == c3 # finalized old previous justified epoch else: - assert state.previous_justified_checkpoint == c3 # changed to old current assert state.current_justified_checkpoint == c3 # still old current assert state.finalized_checkpoint == old_finalized # no new finalized @@ -146,7 +151,8 @@ def finalize_on_123(spec, state, epoch, sufficient_support): state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch # 43210 -- epochs ago - # 3210x -- justification bitfield indices + # 210xx -- justification bitfield indices (pre shift) + # 3210x -- justification bitfield indices (post shift) # 011*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) @@ -158,10 +164,10 @@ def finalize_on_123(spec, state, epoch, sufficient_support): state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root old_finalized = state.finalized_checkpoint - state.previous_justified_checkpoint = c4 + state.previous_justified_checkpoint = c4 # not c3, otherwise finalize 23 would trigger. state.current_justified_checkpoint = c2 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - state.justification_bits[0:2] = [1, 1] # mock 1st and 2nd latest epochs as justified + state.justification_bits[0:2] = [1, 1] # mock 2nd and 3rd latest epochs as justified (indices are pre-shift) # mock the 1st latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 1, @@ -172,12 +178,11 @@ def finalize_on_123(spec, state, epoch, sufficient_support): # process! yield from run_process_just_and_fin(spec, state) + assert state.previous_justified_checkpoint == c2 # changed to old current if sufficient_support: - assert state.previous_justified_checkpoint == c2 # changed to old current assert state.current_justified_checkpoint == c1 # changed to 1st latest assert state.finalized_checkpoint == c2 # finalized old current else: - assert state.previous_justified_checkpoint == c2 # changed to old current assert state.current_justified_checkpoint == c2 # still old current assert state.finalized_checkpoint == old_finalized # no new finalized @@ -187,7 +192,8 @@ def finalize_on_12(spec, state, epoch, sufficient_support): state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch # 43210 -- epochs ago - # 3210 -- justification bitfield indices + # 210xx -- justification bitfield indices (pre shift) + # 3210x -- justification bitfield indices (post shift) # 001*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) @@ -199,7 +205,7 @@ def finalize_on_12(spec, state, epoch, sufficient_support): state.previous_justified_checkpoint = c2 state.current_justified_checkpoint = c2 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - state.justification_bits[0] = 1 # mock latest epoch as justified + state.justification_bits[0] = 1 # mock 2nd latest epoch as justified (this is pre-shift) # mock the 1st latest epoch as justifiable, with 2nd as source add_mock_attestations(spec, state, epoch=epoch - 1, @@ -210,12 +216,11 @@ def finalize_on_12(spec, state, epoch, sufficient_support): # process! yield from run_process_just_and_fin(spec, state) + assert state.previous_justified_checkpoint == c2 # changed to old current if sufficient_support: - assert state.previous_justified_checkpoint == c2 # changed to old current assert state.current_justified_checkpoint == c1 # changed to 1st latest assert state.finalized_checkpoint == c2 # finalized previous justified epoch else: - assert state.previous_justified_checkpoint == c2 # changed to old current assert state.current_justified_checkpoint == c2 # still old current assert state.finalized_checkpoint == old_finalized # no new finalized From f0a8e392434fa06e96b84249c4dd9533d8012cfb Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 17:29:21 +0100 Subject: [PATCH 081/112] WIP --- specs/core/0_beacon-chain.md | 4 +- .../pyspec/eth2spec/test/helpers/deposits.py | 40 ++++++++----------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6f28c0e3d..138d3fd2a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -437,7 +437,7 @@ class Attestation(Container): ```python class Deposit(Container): - proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH] # Merkle path to deposit root + proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit root data: DepositData ``` @@ -1682,7 +1682,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, - depth=DEPOSIT_CONTRACT_TREE_DEPTH, + depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, index=state.eth1_deposit_index, root=state.eth1_data.deposit_root, ) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 20ff7440f..5a0909185 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -1,11 +1,13 @@ from eth2spec.test.helpers.keys import pubkeys, privkeys from eth2spec.utils.bls import bls_sign from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_root, get_merkle_proof -from eth2spec.utils.ssz.ssz_impl import signing_root +from eth2spec.utils.ssz.ssz_impl import signing_root, hash_tree_root +from eth2spec.utils.ssz.ssz_typing import List +from eth2spec.phase0.spec import DepositData def build_deposit_data(spec, state, pubkey, privkey, amount, withdrawal_credentials, signed=False): - deposit_data = spec.DepositData( + deposit_data = DepositData( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, @@ -29,27 +31,21 @@ def sign_deposit_data(spec, state, deposit_data, privkey): def build_deposit(spec, state, - deposit_data_leaves, + deposit_data_list, pubkey, privkey, amount, withdrawal_credentials, signed): deposit_data = build_deposit_data(spec, state, pubkey, privkey, amount, withdrawal_credentials, signed) - - item = deposit_data.hash_tree_root() - index = len(deposit_data_leaves) - deposit_data_leaves.append(item) - tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves)) - root = get_merkle_root((tuple(deposit_data_leaves))) - proof = list(get_merkle_proof(tree, item_index=index)) - assert spec.verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, index, root) - - deposit = spec.Deposit( - proof=list(proof), - index=index, - data=deposit_data, - ) + deposit_data_list.append(deposit_data) + index = len(deposit_data_list) + root = hash_tree_root(List[DepositData, 2**32](*deposit_data_list)) + tree = calc_merkle_tree_from_leaves(tuple([d.hash_tree_root() for d in deposit_data_list])) + proof = list(get_merkle_proof(tree, item_index=index)) + [index.to_bytes(32, 'little')] + leaf = deposit_data.hash_tree_root() + assert spec.verify_merkle_branch(leaf, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH + 1, index, root) + deposit = spec.Deposit(proof, index, deposit_data) return deposit, root, deposit_data_leaves @@ -58,9 +54,7 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c """ Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount. """ - pre_validator_count = len(state.validators) - # fill previous deposits with zero-hash - deposit_data_leaves = [spec.ZERO_HASH] * pre_validator_count + deposit_data_list = [] pubkey = pubkeys[validator_index] privkey = privkeys[validator_index] @@ -69,10 +63,10 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c if withdrawal_credentials is None: withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:] - deposit, root, deposit_data_leaves = build_deposit( + deposit, root, deposit_data_list = build_deposit( spec, state, - deposit_data_leaves, + deposit_data_list, pubkey, privkey, amount, @@ -81,5 +75,5 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c ) state.eth1_data.deposit_root = root - state.eth1_data.deposit_count = len(deposit_data_leaves) + state.eth1_data.deposit_count = len(deposit_data_list) return deposit From bc8df3cba3ccef7ce28b202720d6f698971e5126 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sat, 29 Jun 2019 12:04:56 -0500 Subject: [PATCH 082/112] minor typo Co-Authored-By: Alex Stokes --- specs/light_client/sync_protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/light_client/sync_protocol.md b/specs/light_client/sync_protocol.md index a29ed05c8..cb7b6ce10 100644 --- a/specs/light_client/sync_protocol.md +++ b/specs/light_client/sync_protocol.md @@ -40,7 +40,7 @@ Note that there is now a new way to compute `get_active_validator_indices`: ```python def get_active_validator_indices(state: ExtendedBeaconState, epoch: Epoch) -> List[ValidatorIndex]: - return state.active_indices[epoch % compact_committees_rootS_LENGTH] + return state.active_indices[epoch % EPOCHS_PER_HISTORICAL_VECTOR] ``` Note that it takes `state` instead of `state.validators` as an argument. This does not affect its use in `get_shuffled_committee`, because `get_shuffled_committee` has access to the full `state` as one of its arguments. From d0009b09807b11b970866cd4cffea075e602fee8 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 01:12:25 +0800 Subject: [PATCH 083/112] Pass `genesis_eth1_block_hash` instead of `genesis_eth1_data` --- specs/core/0_beacon-chain.md | 15 ++++++--------- .../pyspec/eth2spec/test/genesis/test_genesis.py | 16 +++++----------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 7cd5725b1..1ddf58b05 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1157,10 +1157,7 @@ When `is_genesis_trigger(deposits, time) is True` for the first time let: * `genesis_deposits = deposits` * `genesis_time = time - time % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` -* `genesis_eth1_data` be the object of type `Eth1Data` where: - * `genesis_eth1_data.deposit_root` is the deposit root for the last deposit in `deposits` - * `genesis_eth1_data.deposit_count = len(genesis_deposits)` - * `genesis_eth1_data.block_hash` is the Eth 1.0 block hash that emitted the log for the last deposit in `deposits` +* `genesis_eth1_block_hash` is the Eth 1.0 block hash that emitted the log for the last deposit in `deposits` *Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder: @@ -1176,6 +1173,7 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) for deposit_index, deposit in enumerate(deposits): state.eth1_data.deposit_root = get_merkle_root(leaves[:deposit_index + 1], 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_data.deposit_count = deposit_index + 1 state.eth1_deposit_index = deposit_index process_deposit(state, deposit) @@ -1191,13 +1189,13 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], ### Genesis state -Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_data)`. +Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_block_hash)`. ```python -def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth1_data: Eth1Data) -> BeaconState: +def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, genesis_eth1_block_hash: Hash) -> BeaconState: state = BeaconState( genesis_time=genesis_time, - eth1_data=eth1_data, + eth1_data=Eth1Data(block_hash=genesis_eth1_block_hash), latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) @@ -1205,11 +1203,10 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) for deposit_index, deposit in enumerate(deposits): state.eth1_data.deposit_root = get_merkle_root(leaves[:deposit_index + 1], 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_data.deposit_count = deposit_index + 1 state.eth1_deposit_index = deposit_index process_deposit(state, deposit) - assert state.eth1_data.deposit_root == eth1_data.deposit_root - # Process genesis activations for validator in state.validators: if validator.effective_balance == MAX_EFFECTIVE_BALANCE: diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py index a89ec8793..0d2b4fbac 100644 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py @@ -10,28 +10,22 @@ def test_genesis(spec): deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1546300800 - block_hash = b'\x12' * 32 + genesis_eth1_block_hash = b'\x12' * 32 yield "deposits", genesis_deposits - yield "time", genesis_time + yield "genesis_time", genesis_time - genesis_eth1_data = spec.Eth1Data( - deposit_root=deposit_root, - deposit_count=deposit_count, - block_hash=block_hash, - ) - - yield "eth1_data", genesis_eth1_data + yield "genesis_eth1_block_hash", genesis_eth1_block_hash genesis_state = spec.get_genesis_beacon_state( genesis_deposits, genesis_time, - genesis_eth1_data, + genesis_eth1_block_hash, ) assert genesis_state.genesis_time == genesis_time 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 == block_hash + assert genesis_state.eth1_data.block_hash == genesis_eth1_block_hash yield "state", genesis_state From 1b66323806505a465236f3adb924ea3a777e02cb Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 01:44:17 +0800 Subject: [PATCH 084/112] head to 1229 --- scripts/build_spec.py | 6 ++-- specs/core/0_beacon-chain.md | 33 ++----------------- .../pyspec/eth2spec/test/helpers/deposits.py | 25 +++++++------- 3 files changed, 17 insertions(+), 47 deletions(-) diff --git a/scripts/build_spec.py b/scripts/build_spec.py index e4e95c7ec..1f5fe1ee6 100644 --- a/scripts/build_spec.py +++ b/scripts/build_spec.py @@ -11,8 +11,7 @@ from typing import ( ) -PHASE0_IMPORTS = '''from math import log2 -from typing import ( +PHASE0_IMPORTS = '''from typing import ( Any, Callable, Dict, Set, Sequence, Tuple, ) @@ -37,8 +36,7 @@ from eth2spec.utils.bls import ( from eth2spec.utils.hash_function import hash ''' -PHASE1_IMPORTS = '''from math import log2 -from typing import ( +PHASE1_IMPORTS = '''from typing import ( Any, Callable, Dict, Optional, Set, Sequence, MutableSequence, Tuple, ) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f9d529e0c..e51fbde3e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -52,8 +52,6 @@ - [`hash`](#hash) - [`hash_tree_root`](#hash_tree_root) - [`signing_root`](#signing_root) - - [`calc_merkle_tree_from_leaves`](#calc_merkle_tree_from_leaves) - - [`get_merkle_root`](#get_merkle_root) - [`bls_domain`](#bls_domain) - [`slot_to_epoch`](#slot_to_epoch) - [`get_previous_epoch`](#get_previous_epoch) @@ -562,33 +560,6 @@ The `hash` function is SHA256. `def signing_root(object: Container) -> Hash` is a function for computing signing messages, as defined in the [SimpleSerialize spec](../simple-serialize.md#self-signed-containers). -### `calc_merkle_tree_from_leaves` - -```python -zerohashes = [ZERO_HASH] -for layer in range(1, 100): - zerohashes.append(hash(zerohashes[layer - 1] + zerohashes[layer - 1])) -def calc_merkle_tree_from_leaves(values: Sequence[Hash], layer_count: int=32) -> Sequence[Sequence[Hash]]: - values = list(values) - tree = [values[::]] - for h in range(layer_count): - if len(values) % 2 == 1: - values.append(zerohashes[h]) - values = [hash(values[i] + values[i + 1]) for i in range(0, len(values), 2)] - tree.append(values[::]) - return tree -``` - -### `get_merkle_root` - -```python -def get_merkle_root(values: Sequence[Hash], pad_to: int=1) -> Hash: - layer_count = int(log2(pad_to)) - if len(values) == 0: - return zerohashes[layer_count] - return calc_merkle_tree_from_leaves(values, layer_count)[-1][0] -``` - ### `bls_domain` ```python @@ -1146,7 +1117,7 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], state = BeaconState() leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) for deposit_index, deposit in enumerate(deposits): - state.eth1_data.deposit_root = get_merkle_root(leaves[:deposit_index + 1], 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_data.deposit_root = hash_tree_root(leaves) state.eth1_data.deposit_count = deposit_index + 1 state.eth1_deposit_index = deposit_index process_deposit(state, deposit) @@ -1176,7 +1147,7 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, gen # Process genesis deposits leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) for deposit_index, deposit in enumerate(deposits): - state.eth1_data.deposit_root = get_merkle_root(leaves[:deposit_index + 1], 2**DEPOSIT_CONTRACT_TREE_DEPTH) + state.eth1_data.deposit_root = hash_tree_root(leaves) state.eth1_data.deposit_count = deposit_index + 1 state.eth1_deposit_index = deposit_index process_deposit(state, deposit) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index ac842405e..a0d59b9a6 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -47,10 +47,10 @@ def build_deposit(spec, spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed, ) - deposit_data = build_deposit_data(spec, state, pubkey, privkey, amount, withdrawal_credentials, signed) + deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed) deposit_data_list.append(deposit_data) index = len(deposit_data_list) - root = hash_tree_root(List[DepositData, 2**32](*deposit_data_list)) + root = hash_tree_root(List[DepositData, 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH](*deposit_data_list)) tree = calc_merkle_tree_from_leaves(tuple([d.hash_tree_root() for d in deposit_data_list])) proof = list(get_merkle_proof(tree, item_index=index)) + [index.to_bytes(32, 'little')] leaf = deposit_data.hash_tree_root() @@ -61,7 +61,7 @@ def build_deposit(spec, def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False): - deposit_data_leaves = [] + deposit_data_list = [] genesis_deposits = [] for validator_index in range(genesis_validator_count): pubkey = pubkeys[validator_index] @@ -73,16 +73,17 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False withdrawal_credentials=withdrawal_credentials, amount=amount, ) - if signed: - sign_deposit_data(spec, deposit_data, privkey) # state=None - item = deposit_data.hash_tree_root() - deposit_data_leaves.append(item) - - tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves), spec.DEPOSIT_CONTRACT_TREE_DEPTH) - root = get_merkle_root((tuple(deposit_data_leaves)), 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH) - genesis_deposits.append( - spec.Deposit(proof=list(get_merkle_proof(tree, item_index=validator_index)), data=deposit_data) + deposit, root, deposit_data_list = build_deposit( + spec, + None, + deposit_data_list, + pubkey, + privkey, + amount, + withdrawal_credentials, + signed, ) + genesis_deposits.append(deposit) return genesis_deposits, root From 6b81e747b25a0b478099c594abd640317d6f6767 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 29 Jun 2019 18:50:23 +0100 Subject: [PATCH 085/112] Fix comment --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 619bd3c01..b5e36bcf0 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1167,7 +1167,7 @@ def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, eth validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH - # Populate active_index_roots + # Populate compact_committees_roots genesis_committee_root = get_compact_committees_root(state, GENESIS_EPOCH) for index in range(EPOCHS_PER_HISTORICAL_VECTOR): state.compact_committees_roots[index] = genesis_committee_root From c8dc30eec20bd8116e94ff8d38e1082ec650eb0f Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 01:56:10 +0800 Subject: [PATCH 086/112] Recover from auto-merge --- specs/core/0_beacon-chain.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index e51fbde3e..f62469d59 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -124,8 +124,7 @@ This document represents the specification for Phase 0 of Ethereum 2.0 -- The Beacon Chain. -At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of [validators](#dfn-validator). In the initial deployment phases of Ethereum 2.0, the only mechanism to become a [validator](#dfn-validator) is to make a one-way ETH transaction to a deposit contract on Eth 1.0. Activation as a [validator](#dfn-validator) happens when Eth 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior. - +At the core of Ethereum 2.0 is a system chain called the "beacon chain". The beacon chain stores and manages the registry of [validators](#dfn-validator). In the initial deployment phases of Ethereum 2.0, the only mechanism to become a [validator](#dfn-validator) is to make a one-way ETH transaction to a deposit contract on Ethereum 1.0. Activation as a [validator](#dfn-validator) happens when Ethereum 1.0 deposit receipts are processed by the beacon chain, the activation balance is reached, and a queuing process is completed. Exit is either voluntary or done forcibly as a penalty for misbehavior. The primary source of load on the beacon chain is "attestations". Attestations are simultaneously availability votes for a shard block and proof-of-stake votes for a beacon block. A sufficient number of attestations for the same shard block create a "crosslink", confirming the shard segment up to that shard block into the beacon chain. Crosslinks also serve as infrastructure for asynchronous cross-shard communication. ## Notation @@ -134,7 +133,7 @@ Code snippets appearing in `this style` are to be interpreted as Python code. ## Terminology -* **Validator**—a registered participant in the beacon chain. You can become one by sending ether into the Eth 1.0 deposit contract. +* **Validator**—a registered participant in the beacon chain. You can become one by sending ether into the Ethereum 1.0 deposit contract. * **Active validator**—an active participant in the Ethereum 2.0 consensus invited to, among other things, propose and attest to blocks and vote for crosslinks. * **Committee**—a (pseudo-) randomly sampled subset of [active validators](#dfn-active-validator). When a committee is referred to collectively, as in "this committee attests to X", this is assumed to mean "some subset of that committee that contains enough [validators](#dfn-validator) that the protocol recognizes it as representing the committee". * **Proposer**—the [validator](#dfn-validator) that creates a beacon chain block. @@ -194,7 +193,7 @@ The following values are (non-configurable) constants used throughout the specif | `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | | `JUSTIFICATION_BITS_LENGTH` | `4` | -* For the safety of cr>>osslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) +* For the safety of crosslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.) ### Gwei values @@ -1095,14 +1094,14 @@ def slash_validator(state: BeaconState, Before genesis has been triggered and for every Eth 1.0 block call `is_genesis_trigger(deposits, time)` where: -* `deposits` is the list of all deposits up to the Eth 1.0 block, ordered chronologically -* `time` is the Unix time of the Eth 1.0 block +* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log +* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log -When `is_genesis_trigger(deposits, time) is True` for the first time let: +When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: * `genesis_deposits = deposits` -* `genesis_time = time - time % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` -* `genesis_eth1_block_hash` is the Eth 1.0 block hash that emitted the log for the last deposit in `deposits` +* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` +* `genesis_eth1_block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` *Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder: From 354cd1c1e19fa1008e43b3861da308d9472a5e12 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 02:02:05 +0800 Subject: [PATCH 087/112] Clean up leftover and linter --- specs/core/0_beacon-chain.md | 10 ++++++---- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 7 +------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f62469d59..5aa57c294 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1092,7 +1092,7 @@ def slash_validator(state: BeaconState, ### Genesis trigger -Before genesis has been triggered and for every Eth 1.0 block call `is_genesis_trigger(deposits, time)` where: +Before genesis has been triggered and whenever the deposit contract emits a `Deposit` log, call the function `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where: * `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log * `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log @@ -1106,10 +1106,10 @@ When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: *Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder: ```python -def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], time: uint64) -> bool: +def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], timestamp: uint64) -> bool: SECONDS_PER_DAY = 86400 # Do not deploy too early - if time - time % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: + if timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: return False # Process deposits @@ -1136,7 +1136,9 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_block_hash)`. ```python -def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, genesis_eth1_block_hash: Hash) -> BeaconState: +def get_genesis_beacon_state(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], + genesis_time: int, + genesis_eth1_block_hash: Hash) -> BeaconState: state = BeaconState( genesis_time=genesis_time, eth1_data=Eth1Data(block_hash=genesis_eth1_block_hash), diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index a0d59b9a6..39ecbd2d7 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -1,6 +1,6 @@ from eth2spec.test.helpers.keys import pubkeys, privkeys from eth2spec.utils.bls import bls_sign -from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_root, get_merkle_proof +from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_proof from eth2spec.utils.ssz.ssz_impl import signing_root, hash_tree_root from eth2spec.utils.ssz.ssz_typing import List from eth2spec.phase0.spec import DepositData @@ -68,11 +68,6 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False privkey = privkeys[validator_index] # insecurely use pubkey as withdrawal key if no credentials provided withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:] - deposit_data = spec.DepositData( - pubkey=pubkey, - withdrawal_credentials=withdrawal_credentials, - amount=amount, - ) deposit, root, deposit_data_list = build_deposit( spec, None, From e4eebef3a4098e49123895532226fcabe87b768d Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 20:09:43 +0200 Subject: [PATCH 088/112] fix broken deposits test, now same error as others --- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 9 ++------- .../phase_0/block_processing/test_process_deposit.py | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 39ecbd2d7..7f5975dd4 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -3,11 +3,10 @@ from eth2spec.utils.bls import bls_sign from eth2spec.utils.merkle_minimal import calc_merkle_tree_from_leaves, get_merkle_proof from eth2spec.utils.ssz.ssz_impl import signing_root, hash_tree_root from eth2spec.utils.ssz.ssz_typing import List -from eth2spec.phase0.spec import DepositData def build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=None, signed=False): - deposit_data = DepositData( + deposit_data = spec.DepositData( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, @@ -43,14 +42,10 @@ def build_deposit(spec, amount, withdrawal_credentials, signed): - deposit_data = build_deposit_data( - spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed, - ) - deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed) deposit_data_list.append(deposit_data) index = len(deposit_data_list) - root = hash_tree_root(List[DepositData, 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH](*deposit_data_list)) + root = hash_tree_root(List[spec.DepositData, 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH](*deposit_data_list)) tree = calc_merkle_tree_from_leaves(tuple([d.hash_tree_root() for d in deposit_data_list])) proof = list(get_merkle_proof(tree, item_index=index)) + [index.to_bytes(32, 'little')] leaf = deposit_data.hash_tree_root() diff --git a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py index d0a62ff6b..d596523ec 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/block_processing/test_process_deposit.py @@ -117,7 +117,7 @@ def test_invalid_withdrawal_credentials_top_up(spec, state): @with_all_phases @spec_state_test def test_wrong_deposit_for_deposit_count(spec, state): - deposit_data_leaves = [spec.ZERO_HASH] * len(state.validators) + deposit_data_leaves = [spec.DepositData() for _ in range(len(state.validators))] # build root for deposit_1 index_1 = len(deposit_data_leaves) From fb165dc14e11cafb273f96f8e75352cc73df73da Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 20:33:11 +0200 Subject: [PATCH 089/112] fixes a few tests, not all --- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 7f5975dd4..99c39211e 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -43,14 +43,14 @@ def build_deposit(spec, withdrawal_credentials, signed): deposit_data = build_deposit_data(spec, pubkey, privkey, amount, withdrawal_credentials, state=state, signed=signed) - deposit_data_list.append(deposit_data) index = len(deposit_data_list) + deposit_data_list.append(deposit_data) root = hash_tree_root(List[spec.DepositData, 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH](*deposit_data_list)) tree = calc_merkle_tree_from_leaves(tuple([d.hash_tree_root() for d in deposit_data_list])) - proof = list(get_merkle_proof(tree, item_index=index)) + [index.to_bytes(32, 'little')] + proof = list(get_merkle_proof(tree, item_index=index)) + [(index + 1).to_bytes(32, 'little')] leaf = deposit_data.hash_tree_root() assert spec.verify_merkle_branch(leaf, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH + 1, index, root) - deposit = spec.Deposit(proof, index, deposit_data) + deposit = spec.Deposit(proof=proof, data=deposit_data) return deposit, root, deposit_data_list From ff185c348697c024f1ebc7e2706cd3b1717eec36 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 20:40:25 +0200 Subject: [PATCH 090/112] fix deposit state mocking for tests --- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index 99c39211e..b46363e62 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -102,6 +102,7 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c signed, ) + state.eth1_deposit_index = 0 state.eth1_data.deposit_root = root state.eth1_data.deposit_count = len(deposit_data_list) return deposit From 125660c5af055209c8bdeb422947f85e4b518626 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 03:20:11 +0800 Subject: [PATCH 091/112] Update input `deposits` type from `Sequence[Deposit]` to `List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH` and fix tests --- specs/core/0_beacon-chain.md | 17 ++++++++++------- .../pyspec/eth2spec/test/helpers/deposits.py | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 5aa57c294..a77ec77a3 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1092,9 +1092,8 @@ def slash_validator(state: BeaconState, ### Genesis trigger -Before genesis has been triggered and whenever the deposit contract emits a `Deposit` log, call the function `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where: - -* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log +Before genesis has been triggered and for every Ethereum 1.0 block call `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where: +* `deposits` is the SSZ list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log * `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: @@ -1114,9 +1113,11 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], # Process deposits state = BeaconState() - leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) + leaves = list(map(lambda deposit: deposit.data, deposits)) for deposit_index, deposit in enumerate(deposits): - state.eth1_data.deposit_root = hash_tree_root(leaves) + state.eth1_data.deposit_root = hash_tree_root( + List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:deposit_index + 1]) + ) state.eth1_data.deposit_count = deposit_index + 1 state.eth1_deposit_index = deposit_index process_deposit(state, deposit) @@ -1146,9 +1147,11 @@ def get_genesis_beacon_state(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DE ) # Process genesis deposits - leaves = list(map(lambda deposit: hash_tree_root(deposit.data), deposits)) + leaves = list(map(lambda deposit: deposit.data, deposits)) for deposit_index, deposit in enumerate(deposits): - state.eth1_data.deposit_root = hash_tree_root(leaves) + state.eth1_data.deposit_root = hash_tree_root( + List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:deposit_index + 1]) + ) state.eth1_data.deposit_count = deposit_index + 1 state.eth1_deposit_index = deposit_index process_deposit(state, deposit) diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index b46363e62..f79dcf3ff 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -75,7 +75,7 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False ) genesis_deposits.append(deposit) - return genesis_deposits, root + return List[spec.Deposit, 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH](*genesis_deposits), root def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_credentials=None, signed=False): From 56caa483144d26f0f5cd09b5128fad2c259e9e93 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 03:27:25 +0800 Subject: [PATCH 092/112] Should use Sequence --- specs/core/0_beacon-chain.md | 6 +++--- test_libs/pyspec/eth2spec/test/helpers/deposits.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a77ec77a3..c70fc006e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1093,7 +1093,7 @@ def slash_validator(state: BeaconState, ### Genesis trigger Before genesis has been triggered and for every Ethereum 1.0 block call `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where: -* `deposits` is the SSZ list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log +* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log * `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: @@ -1105,7 +1105,7 @@ When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: *Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder: ```python -def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], timestamp: uint64) -> bool: +def is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool: SECONDS_PER_DAY = 86400 # Do not deploy too early if timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: @@ -1137,7 +1137,7 @@ def is_genesis_trigger(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_block_hash)`. ```python -def get_genesis_beacon_state(deposits: List[Deposit, 2**DEPOSIT_CONTRACT_TREE_DEPTH], +def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, genesis_eth1_block_hash: Hash) -> BeaconState: state = BeaconState( diff --git a/test_libs/pyspec/eth2spec/test/helpers/deposits.py b/test_libs/pyspec/eth2spec/test/helpers/deposits.py index f79dcf3ff..b46363e62 100644 --- a/test_libs/pyspec/eth2spec/test/helpers/deposits.py +++ b/test_libs/pyspec/eth2spec/test/helpers/deposits.py @@ -75,7 +75,7 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False ) genesis_deposits.append(deposit) - return List[spec.Deposit, 2**spec.DEPOSIT_CONTRACT_TREE_DEPTH](*genesis_deposits), root + return genesis_deposits, root def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_credentials=None, signed=False): From 302b3afe2ae2dcb0287096dec8b8121dca5d248f Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 21:37:54 +0200 Subject: [PATCH 093/112] rename/fix roots in justification tests for consistency --- .../test_process_justification_and_finalization.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index d043d8d97..c76692a95 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -77,8 +77,8 @@ def finalize_on_234(spec, state, epoch, sufficient_support): # 3210x -- justification bitfield indices # 11*0. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) - c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) + c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xdd' * 32) + c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) state.block_roots[spec.get_epoch_start_slot(c4.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c4.root state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root @@ -117,7 +117,7 @@ def finalize_on_23(spec, state, epoch, sufficient_support): # 3210x -- justification bitfield indices (post shift) # 01*0. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) + c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root @@ -155,10 +155,10 @@ def finalize_on_123(spec, state, epoch, sufficient_support): # 3210x -- justification bitfield indices (post shift) # 011*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32) - c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32) + c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xdd' * 32) + c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32) c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xaa' * 32) state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root @@ -197,7 +197,7 @@ def finalize_on_12(spec, state, epoch, sufficient_support): # 001*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32) + c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xaa' * 32) state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root From afb33ddc5bff4a8d2ad4b456fd33587838054ba4 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 21:39:10 +0200 Subject: [PATCH 094/112] fix typo in justification wording --- test_libs/pyspec/eth2spec/test/sanity/test_blocks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py index 019563978..b2eb19244 100644 --- a/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py +++ b/test_libs/pyspec/eth2spec/test/sanity/test_blocks.py @@ -127,7 +127,7 @@ def test_empty_epoch_transition(spec, state): @spec_state_test def test_empty_epoch_transition_not_finalizing(spec, state): # Don't run for non-minimal configs, it takes very long, and the effect - # of calling finalization/justifcation is just the same as with the minimal configuration. + # of calling finalization/justification is just the same as with the minimal configuration. if spec.SLOTS_PER_EPOCH > 8: return From 12dff5349df00d22af0f8897bca1bd114f65cdbd Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 03:42:00 +0800 Subject: [PATCH 095/112] Renames: 1. `Deposit` log -> `DepositEvent` log 2. `get_deposit_root` -> `get_hash_tree_root` --- .../contracts/validator_registration.json | 2 +- .../contracts/validator_registration.v.py | 12 ++++++------ deposit_contract/tests/contracts/test_deposit.py | 8 ++++---- specs/core/0_beacon-chain.md | 2 +- specs/core/0_deposit-contract.md | 6 +++--- specs/validator/0_beacon-chain-validator.md | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/deposit_contract/contracts/validator_registration.json b/deposit_contract/contracts/validator_registration.json index a3d309269..527ce6087 100644 --- a/deposit_contract/contracts/validator_registration.json +++ b/deposit_contract/contracts/validator_registration.json @@ -1 +1 @@ -{"abi": [{"name": "Deposit", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_deposit_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 91674}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 10433}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}], "constant": false, "payable": true, "type": "function", "gas": 1334417}], "bytecode": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b50506112ff56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63c5f2892f600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527fdc5fc95703516abd38fa03c3737ff3b52dc52347055c8028460fdf5bbe2f12ce61064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b6101856112ff036101856000396101856112ff036000f3"} \ No newline at end of file +{"abi": [{"name": "DepositEvent", "inputs": [{"type": "bytes", "name": "pubkey", "indexed": false}, {"type": "bytes", "name": "withdrawal_credentials", "indexed": false}, {"type": "bytes", "name": "amount", "indexed": false}, {"type": "bytes", "name": "signature", "indexed": false}, {"type": "bytes", "name": "index", "indexed": false}], "anonymous": false, "type": "event"}, {"outputs": [], "inputs": [], "constant": false, "payable": false, "type": "constructor"}, {"name": "get_hash_tree_root", "outputs": [{"type": "bytes32", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 91674}, {"name": "get_deposit_count", "outputs": [{"type": "bytes", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 10433}, {"name": "deposit", "outputs": [], "inputs": [{"type": "bytes", "name": "pubkey"}, {"type": "bytes", "name": "withdrawal_credentials"}, {"type": "bytes", "name": "signature"}], "constant": false, "payable": true, "type": "function", "gas": 1334417}], "bytecode": "0x600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052341561009e57600080fd5b6101406000601f818352015b600061014051602081106100bd57600080fd5b600260c052602060c020015460208261016001015260208101905061014051602081106100e957600080fd5b600260c052602060c020015460208261016001015260208101905080610160526101609050602060c0825160208401600060025af161012757600080fd5b60c0519050606051600161014051018060405190131561014657600080fd5b809190121561015457600080fd5b6020811061016157600080fd5b600260c052602060c02001555b81516001018083528114156100aa575b50506112ff56600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a052600015610277575b6101605261014052600061018052610140516101a0526101c060006008818352015b61018051600860008112156100da578060000360020a82046100e1565b8060020a82025b905090506101805260ff6101a051166101e052610180516101e0516101805101101561010c57600080fd5b6101e0516101805101610180526101a0517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86000811215610155578060000360020a820461015c565b8060020a82025b905090506101a0525b81516001018083528114156100bd575b50506018600860208206610200016020828401111561019357600080fd5b60208061022082610180600060046015f15050818152809050905090508051602001806102c0828460006004600a8704601201f16101d057600080fd5b50506102c05160206001820306601f82010390506103206102c0516008818352015b826103205111156102025761021e565b6000610320516102e001535b81516001018083528114156101f2575b50505060206102a05260406102c0510160206001820306601f8201039050610280525b6000610280511115156102535761026f565b602061028051036102a001516020610280510361028052610241565b610160515650005b63863a311b600051141561050857341561029057600080fd5b6000610140526101405161016052600154610180526101a060006020818352015b60016001610180511614156103325760006101a051602081106102d357600080fd5b600060c052602060c02001546020826102400101526020810190506101605160208261024001015260208101905080610240526102409050602060c0825160208401600060025af161032457600080fd5b60c0519050610160526103a0565b6000610160516020826101c00101526020810190506101a0516020811061035857600080fd5b600260c052602060c02001546020826101c0010152602081019050806101c0526101c09050602060c0825160208401600060025af161039657600080fd5b60c0519050610160525b61018060026103ae57600080fd5b60028151048152505b81516001018083528114156102b1575b505060006101605160208261044001015260208101905061014051610160516101805163806732896102c0526001546102e0526102e0516006580161009b565b506103405260006103a0525b6103405160206001820306601f82010390506103a0511015156104355761044e565b6103a05161036001526103a0516020016103a052610413565b61018052610160526101405261034060088060208461044001018260208501600060046012f150508051820191505060006018602082066103c0016020828401111561049957600080fd5b6020806103e082610140600060046015f150508181528090509050905060188060208461044001018260208501600060046014f150508051820191505080610440526104409050602060c0825160208401600060025af16104f957600080fd5b60c051905060005260206000f3005b63621fd130600051141561061a57341561052157600080fd5b63806732896101405260015461016052610160516006580161009b565b506101c0526000610220525b6101c05160206001820306601f82010390506102205110151561056c57610585565b610220516101e00152610220516020016102205261054a565b6101c0805160200180610280828460006004600a8704601201f16105a857600080fd5b50506102805160206001820306601f82010390506102e0610280516008818352015b826102e05111156105da576105f6565b60006102e0516102a001535b81516001018083528114156105ca575b5050506020610260526040610280510160206001820306601f8201039050610260f3005b63c47e300d600051141561117457606060046101403760506004356004016101a037603060043560040135111561065057600080fd5b604060243560040161022037602060243560040135111561067057600080fd5b608060443560040161028037606060443560040135111561069057600080fd5b63ffffffff600154106106a257600080fd5b633b9aca0061034052610340516106b857600080fd5b61034051340461032052633b9aca006103205110156106d657600080fd5b60306101a051146106e657600080fd5b602061022051146106f657600080fd5b6060610280511461070657600080fd5b6101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a05163806732896103c052610320516103e0526103e0516006580161009b565b506104405260006104a0525b6104405160206001820306601f82010390506104a051101515610796576107af565b6104a05161046001526104a0516020016104a052610774565b6103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a052610440805160200180610360828460006004600a8704601201f161081657600080fd5b50506101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e05161040051610420516104405161046051610480516104a05163806732896104c0526001546104e0526104e0516006580161009b565b506105405260006105a0525b6105405160206001820306601f82010390506105a0511015156108c7576108e0565b6105a05161056001526105a0516020016105a0526108a5565b6104a05261048052610460526104405261042052610400526103e0526103c0526103a05261038052610360526103405261032052610300526102e0526102c0526102a05261028052610260526102405261022052610200526101e0526101c0526101a0526105408051602001806105c0828460006004600a8704601201f161096757600080fd5b505060a06106405261064051610680526101a08051602001806106405161068001828460006004600a8704601201f161099f57600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516040818352015b83610620511015156109dd576109fa565b6000610620516020850101535b81516001018083528114156109cc575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106a0526102208051602001806106405161068001828460006004600a8704601201f1610a5157600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610a8f57610aac565b6000610620516020850101535b8151600101808352811415610a7e575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106c0526103608051602001806106405161068001828460006004600a8704601201f1610b0357600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610b4157610b5e565b6000610620516020850101535b8151600101808352811415610b30575b50505050602061064051610680015160206001820306601f820103905061064051010161064052610640516106e0526102808051602001806106405161068001828460006004600a8704601201f1610bb557600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516060818352015b8361062051101515610bf357610c10565b6000610620516020850101535b8151600101808352811415610be2575b50505050602061064051610680015160206001820306601f82010390506106405101016106405261064051610700526105c08051602001806106405161068001828460006004600a8704601201f1610c6757600080fd5b505061064051610680015160206001820306601f8201039050610640516106800161062081516020818352015b8361062051101515610ca557610cc2565b6000610620516020850101535b8151600101808352811415610c94575b50505050602061064051610680015160206001820306601f8201039050610640510101610640527f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c561064051610680a160006107205260006101a06030806020846107e001018260208501600060046016f150508051820191505060006010602082066107600160208284011115610d5957600080fd5b60208061078082610720600060046015f15050818152809050905090506010806020846107e001018260208501600060046013f1505080518201915050806107e0526107e09050602060c0825160208401600060025af1610db957600080fd5b60c0519050610740526000600060406020820661088001610280518284011115610de257600080fd5b6060806108a0826020602088068803016102800160006004601bf1505081815280905090509050602060c0825160208401600060025af1610e2257600080fd5b60c0519050602082610a800101526020810190506000604060206020820661094001610280518284011115610e5657600080fd5b606080610960826020602088068803016102800160006004601bf1505081815280905090509050602080602084610a0001018260208501600060046015f150508051820191505061072051602082610a0001015260208101905080610a0052610a009050602060c0825160208401600060025af1610ed357600080fd5b60c0519050602082610a8001015260208101905080610a8052610a809050602060c0825160208401600060025af1610f0a57600080fd5b60c0519050610860526000600061074051602082610b20010152602081019050610220602080602084610b2001018260208501600060046015f150508051820191505080610b2052610b209050602060c0825160208401600060025af1610f7057600080fd5b60c0519050602082610ca00101526020810190506000610360600880602084610c2001018260208501600060046012f15050805182019150506000601860208206610ba00160208284011115610fc557600080fd5b602080610bc082610720600060046015f1505081815280905090509050601880602084610c2001018260208501600060046014f150508051820191505061086051602082610c2001015260208101905080610c2052610c209050602060c0825160208401600060025af161103857600080fd5b60c0519050602082610ca001015260208101905080610ca052610ca09050602060c0825160208401600060025af161106f57600080fd5b60c0519050610b0052600180546001825401101561108c57600080fd5b6001815401815550600154610d2052610d4060006020818352015b60016001610d20511614156110dc57610b0051610d4051602081106110cb57600080fd5b600060c052602060c0200155611170565b6000610d4051602081106110ef57600080fd5b600060c052602060c0200154602082610d60010152602081019050610b0051602082610d6001015260208101905080610d6052610d609050602060c0825160208401600060025af161114057600080fd5b60c0519050610b0052610d20600261115757600080fd5b60028151048152505b81516001018083528114156110a7575b5050005b60006000fd5b6101856112ff036101856000396101856112ff036000f3"} \ No newline at end of file diff --git a/deposit_contract/contracts/validator_registration.v.py b/deposit_contract/contracts/validator_registration.v.py index b49cc45e1..bad619b07 100644 --- a/deposit_contract/contracts/validator_registration.v.py +++ b/deposit_contract/contracts/validator_registration.v.py @@ -6,7 +6,7 @@ WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32 # bytes AMOUNT_LENGTH: constant(uint256) = 8 # bytes SIGNATURE_LENGTH: constant(uint256) = 96 # bytes -Deposit: event({ +DepositEvent: event({ pubkey: bytes[48], withdrawal_credentials: bytes[32], amount: bytes[8], @@ -42,7 +42,7 @@ def to_little_endian_64(value: uint256) -> bytes[8]: @public @constant -def get_deposit_root() -> bytes32: +def get_hash_tree_root() -> bytes32: zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 node: bytes32 = zero_bytes32 size: uint256 = self.deposit_count @@ -76,11 +76,11 @@ def deposit(pubkey: bytes[PUBKEY_LENGTH], assert len(withdrawal_credentials) == WITHDRAWAL_CREDENTIALS_LENGTH assert len(signature) == SIGNATURE_LENGTH - # Emit `Deposit` log + # Emit `DepositEvent` log amount: bytes[8] = self.to_little_endian_64(deposit_amount) - log.Deposit(pubkey, withdrawal_credentials, amount, signature, self.to_little_endian_64(self.deposit_count)) + log.DepositEvent(pubkey, withdrawal_credentials, amount, signature, self.to_little_endian_64(self.deposit_count)) - # Compute `DepositData` root + # Compute `DepositData` hash tree root zero_bytes32: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000 pubkey_root: bytes32 = sha256(concat(pubkey, slice(zero_bytes32, start=0, len=64 - PUBKEY_LENGTH))) signature_root: bytes32 = sha256(concat( @@ -92,7 +92,7 @@ def deposit(pubkey: bytes[PUBKEY_LENGTH], sha256(concat(amount, slice(zero_bytes32, start=0, len=32 - AMOUNT_LENGTH), signature_root)), )) - # Add `DepositData` root to Merkle tree (update a single `branch` node) + # Add `DepositData` hash tree root to Merkle tree (update a single `branch` node) self.deposit_count += 1 size: uint256 = self.deposit_count for height in range(DEPOSIT_CONTRACT_TREE_DEPTH): diff --git a/deposit_contract/tests/contracts/test_deposit.py b/deposit_contract/tests/contracts/test_deposit.py index 8c165f0f9..1c96d074e 100644 --- a/deposit_contract/tests/contracts/test_deposit.py +++ b/deposit_contract/tests/contracts/test_deposit.py @@ -96,8 +96,8 @@ def test_deposit_inputs(registration_contract, ) -def test_deposit_log(registration_contract, a0, w3, deposit_input): - log_filter = registration_contract.events.Deposit.createFilter( +def test_deposit_event_log(registration_contract, a0, w3, deposit_input): + log_filter = registration_contract.events.DepositEvent.createFilter( fromBlock='latest', ) @@ -119,7 +119,7 @@ def test_deposit_log(registration_contract, a0, w3, deposit_input): def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input): - log_filter = registration_contract.events.Deposit.createFilter( + log_filter = registration_contract.events.DepositEvent.createFilter( fromBlock='latest', ) @@ -146,4 +146,4 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input )) root = hash_tree_root(List[DepositData, 2**32](*deposit_data_list)) - assert root == registration_contract.functions.get_deposit_root().call() + assert root == registration_contract.functions.get_hash_tree_root().call() diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index c70fc006e..088619202 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -438,7 +438,7 @@ class Attestation(Container): ```python class Deposit(Container): - proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit root + proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to SSZ deposit data list hash tree root data: DepositData ``` diff --git a/specs/core/0_deposit-contract.md b/specs/core/0_deposit-contract.md index d06dbaea1..0efc15f25 100644 --- a/specs/core/0_deposit-contract.md +++ b/specs/core/0_deposit-contract.md @@ -14,7 +14,7 @@ - [`deposit` function](#deposit-function) - [Deposit amount](#deposit-amount) - [Withdrawal credentials](#withdrawal-credentials) - - [`Deposit` log](#deposit-log) + - [`DepositEvent` log](#depositevent-log) - [Vyper code](#vyper-code) @@ -53,9 +53,9 @@ One of the `DepositData` fields is `withdrawal_credentials`. It is a commitment The private key corresponding to `withdrawal_pubkey` will be required to initiate a withdrawal. It can be stored separately until a withdrawal is required, e.g. in cold storage. -#### `Deposit` log +#### `DepositEvent` log -Every Ethereum 1.0 deposit emits a `Deposit` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract. +Every Ethereum 1.0 deposit emits a `DepositEvent` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract. ## Vyper code diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index 7d5630c7b..1b103b218 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -221,7 +221,7 @@ epoch_signature = bls_sign( ##### Eth1 Data -The `block.eth1_data` field is for block proposers to vote on recent Eth 1.0 data. This recent data contains an Eth 1.0 block hash as well as the associated deposit root (as calculated by the `get_deposit_root()` method of the deposit contract) and deposit count after execution of the corresponding Eth 1.0 block. If over half of the block proposers in the current Eth 1.0 voting period vote for the same `eth1_data` then `state.eth1_data` updates at the end of the voting period. Each deposit in `block.body.deposits` must verify against `state.eth1_data.eth1_deposit_root`. +The `block.eth1_data` field is for block proposers to vote on recent Eth 1.0 data. This recent data contains an Eth 1.0 block hash as well as the associated deposit root (as calculated by the `get_hash_tree_root()` method of the deposit contract) and deposit count after execution of the corresponding Eth 1.0 block. If over half of the block proposers in the current Eth 1.0 voting period vote for the same `eth1_data` then `state.eth1_data` updates at the end of the voting period. Each deposit in `block.body.deposits` must verify against `state.eth1_data.eth1_deposit_root`. Let `get_eth1_data(distance: int) -> Eth1Data` be the (subjective) function that returns the Eth 1.0 data at distance `distance` relative to the Eth 1.0 head at the start of the current Eth 1.0 voting period. Let `previous_eth1_distance` be the distance relative to the Eth 1.0 block corresponding to `state.eth1_data.block_hash` at the start of the current Eth 1.0 voting period. An honest block proposer sets `block.eth1_data = get_eth1_vote(state, previous_eth1_distance)` where: From 22476420f3922f741dd24294eafb5cd181cad4a7 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 21:03:15 +0100 Subject: [PATCH 096/112] Cleanups; think about merging is_genesis_trigger into get_genesis_state --- specs/core/0_beacon-chain.md | 47 ++++++++++++++---------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 088619202..f8768935b 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -174,6 +174,7 @@ The following values are (non-configurable) constants used throughout the specif | `ZERO_HASH` | `Hash(b'\x00' * 32)` | | `BASE_REWARDS_PER_EPOCH` | `5` | | `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) | +| `SECONDS_PER_DAY` | `86400` | ## Configuration @@ -438,7 +439,7 @@ class Attestation(Container): ```python class Deposit(Container): - proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to SSZ deposit data list hash tree root + proof: Vector[Hash, DEPOSIT_CONTRACT_TREE_DEPTH + 1] # Merkle path to deposit data list root data: DepositData ``` @@ -1093,43 +1094,45 @@ def slash_validator(state: BeaconState, ### Genesis trigger Before genesis has been triggered and for every Ethereum 1.0 block call `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where: -* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log + +* `deposits` is the sequence of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log * `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: * `genesis_deposits = deposits` -* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400` +* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` * `genesis_eth1_block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` *Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder: ```python def is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool: - SECONDS_PER_DAY = 86400 # Do not deploy too early if timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: return False - - # Process deposits + # Process genesis deposits state = BeaconState() + process_genesis_deposits(state, deposits) + # Check active validator count + return len(get_active_validator_indices(state, GENESIS_EPOCH)) >= GENESIS_ACTIVE_VALIDATOR_COUNT +``` + +```python +def process_genesis_deposits(state: BeaconState, deposits: Sequence[Deposit]) -> None: leaves = list(map(lambda deposit: deposit.data, deposits)) for deposit_index, deposit in enumerate(deposits): state.eth1_data.deposit_root = hash_tree_root( List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:deposit_index + 1]) ) state.eth1_data.deposit_count = deposit_index + 1 - state.eth1_deposit_index = deposit_index process_deposit(state, deposit) - # Count active validators at genesis - active_validator_count = 0 + # Process genesis activations for validator in state.validators: if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - active_validator_count += 1 - - # Check effective balance to trigger genesis - return active_validator_count >= GENESIS_ACTIVE_VALIDATOR_COUNT + validator.activation_eligibility_epoch = GENESIS_EPOCH + validator.activation_epoch = GENESIS_EPOCH ``` ### Genesis state @@ -1140,27 +1143,13 @@ Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, ge def get_genesis_beacon_state(deposits: Sequence[Deposit], genesis_time: int, genesis_eth1_block_hash: Hash) -> BeaconState: + # Process genesis deposits state = BeaconState( genesis_time=genesis_time, eth1_data=Eth1Data(block_hash=genesis_eth1_block_hash), latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) - - # Process genesis deposits - leaves = list(map(lambda deposit: deposit.data, deposits)) - for deposit_index, deposit in enumerate(deposits): - state.eth1_data.deposit_root = hash_tree_root( - List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:deposit_index + 1]) - ) - state.eth1_data.deposit_count = deposit_index + 1 - state.eth1_deposit_index = deposit_index - process_deposit(state, deposit) - - # Process genesis activations - for validator in state.validators: - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: - validator.activation_eligibility_epoch = GENESIS_EPOCH - validator.activation_epoch = GENESIS_EPOCH + process_genesis_deposits(state, deposits) # Populate active_index_roots genesis_active_index_root = hash_tree_root( From d00b5b9ea0d3f22a8a58a7db45c9879cf99c0736 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 21:18:18 +0100 Subject: [PATCH 097/112] Merge is_genesis_trigger into get_genesis_state --- specs/core/0_beacon-chain.md | 58 +++++++++++------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index f8768935b..ba7f1d06d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -94,7 +94,6 @@ - [`initiate_validator_exit`](#initiate_validator_exit) - [`slash_validator`](#slash_validator) - [Genesis](#genesis) - - [Genesis trigger](#genesis-trigger) - [Genesis state](#genesis-state) - [Genesis block](#genesis-block) - [Beacon chain state transition function](#beacon-chain-state-transition-function) @@ -190,7 +189,7 @@ The following values are (non-configurable) constants used throughout the specif | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `90` | -| `GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | +| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | | `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | | `JUSTIFICATION_BITS_LENGTH` | `4` | @@ -1091,35 +1090,28 @@ def slash_validator(state: BeaconState, ## Genesis -### Genesis trigger +### Genesis state -Before genesis has been triggered and for every Ethereum 1.0 block call `is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool` where: +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: -* `deposits` is the sequence of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log -* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log +* `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` -When `is_genesis_trigger(deposits, timestamp) is True` for the first time, let: +The genesis state `genesis_state` is defined as the return value of the first call to `get_genesis_beacon_state` that does not trigger an `assert`. -* `genesis_deposits = deposits` -* `genesis_time = timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` -* `genesis_eth1_block_hash` is the Ethereum 1.0 block hash that emitted the log for the last deposit in `deposits` - -*Note*: The function `is_genesis_trigger` has yet to be agreed upon by the community, and can be updated as necessary. We define the following testing placeholder: +*Note*: The two constants `MIN_GENESIS_TIME` and `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` in `get_genesis_beacon_state` have yet to be agreed upon by the community, and can be updated as necessary. ```python -def is_genesis_trigger(deposits: Sequence[Deposit], timestamp: uint64) -> bool: - # Do not deploy too early - if timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY < MIN_GENESIS_TIME: - return False - # Process genesis deposits - state = BeaconState() - process_genesis_deposits(state, deposits) - # Check active validator count - return len(get_active_validator_indices(state, GENESIS_EPOCH)) >= GENESIS_ACTIVE_VALIDATOR_COUNT -``` +def get_genesis_beacon_state(eth1_block_hash: Hash, eth1_timestamp: int, deposits: Sequence[Deposit]) -> BeaconState: + state = BeaconState( + genesis_time=timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY, + eth1_data=Eth1Data(block_hash=genesis_eth1_block_hash), + latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), + ) + assert state.genesis_time >= MIN_GENESIS_TIME -```python -def process_genesis_deposits(state: BeaconState, deposits: Sequence[Deposit]) -> None: + # Process deposits leaves = list(map(lambda deposit: deposit.data, deposits)) for deposit_index, deposit in enumerate(deposits): state.eth1_data.deposit_root = hash_tree_root( @@ -1133,23 +1125,7 @@ def process_genesis_deposits(state: BeaconState, deposits: Sequence[Deposit]) -> if validator.effective_balance == MAX_EFFECTIVE_BALANCE: validator.activation_eligibility_epoch = GENESIS_EPOCH validator.activation_epoch = GENESIS_EPOCH -``` - -### Genesis state - -Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_block_hash)`. - -```python -def get_genesis_beacon_state(deposits: Sequence[Deposit], - genesis_time: int, - genesis_eth1_block_hash: Hash) -> BeaconState: - # Process genesis deposits - state = BeaconState( - genesis_time=genesis_time, - eth1_data=Eth1Data(block_hash=genesis_eth1_block_hash), - latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), - ) - process_genesis_deposits(state, deposits) + 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( From 36dd977b85ef1c21e35f691cd071b30900709759 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sat, 29 Jun 2019 22:27:05 +0200 Subject: [PATCH 098/112] fix finalize on double justification in 123 rule --- ..._process_justification_and_finalization.py | 71 ++++++++++--------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py index c76692a95..1744d388c 100644 --- a/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py +++ b/test_libs/pyspec/eth2spec/test/phase_0/epoch_processing/test_process_justification_and_finalization.py @@ -60,7 +60,7 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support attestations.append(spec.PendingAttestation( aggregation_bits=aggregation_bits, data=spec.AttestationData( - beacon_block_root=b'\xaa' * 32, + beacon_block_root=b'\xff' * 32, # irrelevant to testing source=source, target=target, crosslink=spec.Crosslink(shard=shard) @@ -69,6 +69,20 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support )) +def get_checkpoints(spec, epoch): + c1 = None if epoch < 1 else spec.Checkpoint(epoch=epoch - 1, root=b'\xaa' * 32) + c2 = None if epoch < 2 else spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) + c3 = None if epoch < 3 else spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32) + c4 = None if epoch < 4 else spec.Checkpoint(epoch=epoch - 4, root=b'\xdd' * 32) + c5 = None if epoch < 5 else spec.Checkpoint(epoch=epoch - 5, root=b'\xee' * 32) + return c1, c2, c3, c4, c5 + + +def put_checkpoints_in_block_roots(spec, state, checkpoints): + for c in checkpoints: + state.block_roots[spec.get_epoch_start_slot(c.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c.root + + def finalize_on_234(spec, state, epoch, sufficient_support): assert epoch > 4 state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch @@ -77,12 +91,8 @@ def finalize_on_234(spec, state, epoch, sufficient_support): # 3210x -- justification bitfield indices # 11*0. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xdd' * 32) - c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32) - c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - state.block_roots[spec.get_epoch_start_slot(c4.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c4.root - state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root - state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root + c1, c2, c3, c4, _ = get_checkpoints(spec, epoch) + put_checkpoints_in_block_roots(spec, state, [c1, c2, c3, c4]) old_finalized = state.finalized_checkpoint state.previous_justified_checkpoint = c4 @@ -117,16 +127,14 @@ def finalize_on_23(spec, state, epoch, sufficient_support): # 3210x -- justification bitfield indices (post shift) # 01*0. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32) - c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root - state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root + c1, c2, c3, _, _ = get_checkpoints(spec, epoch) + put_checkpoints_in_block_roots(spec, state, [c1, c2, c3]) old_finalized = state.finalized_checkpoint state.previous_justified_checkpoint = c3 state.current_justified_checkpoint = c3 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - state.justification_bits[1] = 1 # mock 3rd latest epoch as justified (indices are pre-shift) + state.justification_bits[1] = 1 # mock 3rd latest epoch as justified (index is pre-shift) # mock the 2nd latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 2, @@ -147,7 +155,7 @@ def finalize_on_23(spec, state, epoch, sufficient_support): def finalize_on_123(spec, state, epoch, sufficient_support): - assert epoch > 3 + assert epoch > 5 state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch # 43210 -- epochs ago @@ -155,19 +163,20 @@ def finalize_on_123(spec, state, epoch, sufficient_support): # 3210x -- justification bitfield indices (post shift) # 011*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xdd' * 32) - c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xcc' * 32) - c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xaa' * 32) - state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root - state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root - state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root + c1, c2, c3, c4, c5 = get_checkpoints(spec, epoch) + put_checkpoints_in_block_roots(spec, state, [c1, c2, c3, c4, c5]) old_finalized = state.finalized_checkpoint - state.previous_justified_checkpoint = c4 # not c3, otherwise finalize 23 would trigger. - state.current_justified_checkpoint = c2 + state.previous_justified_checkpoint = c5 + state.current_justified_checkpoint = c3 state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]() - state.justification_bits[0:2] = [1, 1] # mock 2nd and 3rd latest epochs as justified (indices are pre-shift) + state.justification_bits[1] = 1 # mock 3rd latest epochs as justified (index is pre-shift) + # mock the 2nd latest epoch as justifiable, with 5th as source + add_mock_attestations(spec, state, + epoch=epoch - 2, + source=c5, + target=c2, + sufficient_support=sufficient_support) # mock the 1st latest epoch as justifiable, with 3rd as source add_mock_attestations(spec, state, epoch=epoch - 1, @@ -178,12 +187,12 @@ def finalize_on_123(spec, state, epoch, sufficient_support): # process! yield from run_process_just_and_fin(spec, state) - assert state.previous_justified_checkpoint == c2 # changed to old current + assert state.previous_justified_checkpoint == c3 # changed to old current if sufficient_support: assert state.current_justified_checkpoint == c1 # changed to 1st latest - assert state.finalized_checkpoint == c2 # finalized old current + assert state.finalized_checkpoint == c3 # finalized old current else: - assert state.current_justified_checkpoint == c2 # still old current + assert state.current_justified_checkpoint == c3 # still old current assert state.finalized_checkpoint == old_finalized # no new finalized @@ -196,10 +205,8 @@ def finalize_on_12(spec, state, epoch, sufficient_support): # 3210x -- justification bitfield indices (post shift) # 001*. -- justification bitfield contents, . = this epoch, * is being justified now # checkpoints for the epochs ago: - c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32) - c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xaa' * 32) - state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root - state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root + c1, c2, _, _, _ = get_checkpoints(spec, epoch) + put_checkpoints_in_block_roots(spec, state, [c1, c2]) old_finalized = state.finalized_checkpoint state.previous_justified_checkpoint = c2 @@ -252,13 +259,13 @@ def test_23_poor_support(spec, state): @with_all_phases @spec_state_test def test_123_ok_support(spec, state): - yield from finalize_on_123(spec, state, 4, True) + yield from finalize_on_123(spec, state, 6, True) @with_all_phases @spec_state_test def test_123_poor_support(spec, state): - yield from finalize_on_123(spec, state, 4, False) + yield from finalize_on_123(spec, state, 6, False) @with_all_phases From 3a5872f8e45ba2c23790007071a711ff322a379c Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 21:29:10 +0100 Subject: [PATCH 099/112] Cleanups and fixes --- configs/constant_presets/mainnet.yaml | 2 +- configs/constant_presets/minimal.yaml | 2 +- specs/core/0_beacon-chain.md | 19 +++++++++---------- .../eth2spec/test/genesis/test_genesis.py | 2 +- .../test/genesis/test_genesis_trigger.py | 4 ++-- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/configs/constant_presets/mainnet.yaml b/configs/constant_presets/mainnet.yaml index d7a3b5efe..1ebae3c87 100644 --- a/configs/constant_presets/mainnet.yaml +++ b/configs/constant_presets/mainnet.yaml @@ -18,7 +18,7 @@ CHURN_LIMIT_QUOTIENT: 65536 # See issue 563 SHUFFLE_ROUND_COUNT: 90 # `2**16` (= 65,536) -GENESIS_ACTIVE_VALIDATOR_COUNT: 65536 +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 65536 # Deposit contract diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index e8dc370be..c17c5806f 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -17,7 +17,7 @@ CHURN_LIMIT_QUOTIENT: 65536 # [customized] Faster, but unsecure. SHUFFLE_ROUND_COUNT: 10 # [customized] -GENESIS_ACTIVE_VALIDATOR_COUNT: 100 +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 100 # Deposit contract diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index ba7f1d06d..9df0e2f5a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -189,7 +189,7 @@ The following values are (non-configurable) constants used throughout the specif | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `90` | -| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | +| `MIN_MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | | `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | | `JUSTIFICATION_BITS_LENGTH` | `4` | @@ -1092,40 +1092,39 @@ 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 `get_genesis_beacon_state(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 defined as 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 the first call to `get_genesis_beacon_state` that does not trigger an `assert`. -*Note*: The two constants `MIN_GENESIS_TIME` and `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` in `get_genesis_beacon_state` have yet to be agreed upon by the community, and can be updated as necessary. +*Note*: The two constants `MIN_GENESIS_TIME` and `MIN_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: int, deposits: Sequence[Deposit]) -> BeaconState: state = BeaconState( genesis_time=timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY, - eth1_data=Eth1Data(block_hash=genesis_eth1_block_hash), + eth1_data=Eth1Data(block_hash=genesis_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)) - for deposit_index, deposit in enumerate(deposits): + for index, deposit in enumerate(deposits): state.eth1_data.deposit_root = hash_tree_root( - List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:deposit_index + 1]) + List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1]) ) - state.eth1_data.deposit_count = deposit_index + 1 process_deposit(state, deposit) - # Process genesis activations + # Process activations for validator in state.validators: if validator.effective_balance == 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 + assert len(get_active_validator_indices(state, GENESIS_EPOCH)) >= MIN_MIN_GENESIS_ACTIVE_VALIDATOR_COUNT # Populate active_index_roots genesis_active_index_root = hash_tree_root( diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py index 0d2b4fbac..21fcaca40 100644 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py @@ -7,7 +7,7 @@ from eth2spec.test.helpers.deposits import ( @with_phases(['phase0']) @spectest_with_bls_switch def test_genesis(spec): - deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT + deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) genesis_time = 1546300800 genesis_eth1_block_hash = b'\x12' * 32 diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py index 783def3ba..998189e15 100644 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis_trigger.py @@ -23,7 +23,7 @@ def test_is_genesis_trigger_false(spec): @with_phases(['phase0']) @spectest_with_bls_switch def test_is_genesis_trigger_true(spec): - deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT + 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 @@ -40,7 +40,7 @@ def test_is_genesis_trigger_true(spec): @with_phases(['phase0']) @spectest_with_bls_switch def test_is_genesis_trigger_not_enough_balance(spec): - deposit_count = spec.GENESIS_ACTIVE_VALIDATOR_COUNT + 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 From ada3cb2ae126653ce64d240b78a55e7eff46ac96 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 21:36:27 +0100 Subject: [PATCH 100/112] Fix genesis balance bug (git add -u) --- specs/core/0_beacon-chain.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 9df0e2f5a..7a79dde01 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1120,8 +1120,8 @@ def get_genesis_beacon_state(eth1_block_hash: Hash, eth1_timestamp: int, deposit process_deposit(state, deposit) # Process activations - for validator in state.validators: - if validator.effective_balance == MAX_EFFECTIVE_BALANCE: + for index, validator in enumerate(state.validators): + if 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_MIN_GENESIS_ACTIVE_VALIDATOR_COUNT From 43beb743e6bc7eab133bcf07fdfb8313fdd1b20d Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 21:39:55 +0100 Subject: [PATCH 101/112] typo --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 7a79dde01..a0c3d85c0 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1121,7 +1121,7 @@ def get_genesis_beacon_state(eth1_block_hash: Hash, eth1_timestamp: int, deposit # Process activations for index, validator in enumerate(state.validators): - if balances[index] >= MAX_EFFECTIVE_BALANCE: + 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_MIN_GENESIS_ACTIVE_VALIDATOR_COUNT From a356fc9fc8073794ec2d7ea7fa71689e2d8e5a79 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 21:53:04 +0100 Subject: [PATCH 102/112] Fixes --- specs/core/0_beacon-chain.md | 8 ++++---- test_libs/pyspec/eth2spec/test/genesis/test_genesis.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index a0c3d85c0..3de90a87c 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -189,7 +189,7 @@ The following values are (non-configurable) constants used throughout the specif | `MIN_PER_EPOCH_CHURN_LIMIT` | `2**2` (= 4) | | `CHURN_LIMIT_QUOTIENT` | `2**16` (= 65,536) | | `SHUFFLE_ROUND_COUNT` | `90` | -| `MIN_MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | +| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) | | `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) | | `JUSTIFICATION_BITS_LENGTH` | `4` | @@ -1100,12 +1100,12 @@ Before the Ethereum 2.0 genesis has been triggered, and for every Ethereum 1.0 b The genesis state `genesis_state` is the return value of the first call to `get_genesis_beacon_state` that does not trigger an `assert`. -*Note*: The two constants `MIN_GENESIS_TIME` and `MIN_MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` have yet to be agreed upon by the community, and can be updated as necessary. +*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: int, deposits: Sequence[Deposit]) -> BeaconState: state = BeaconState( - genesis_time=timestamp - timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY, + genesis_time=eth1_timestamp - eth1_timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY, eth1_data=Eth1Data(block_hash=genesis_eth1_block_hash, deposit_count=len(deposits)), latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())), ) @@ -1124,7 +1124,7 @@ def get_genesis_beacon_state(eth1_block_hash: Hash, eth1_timestamp: int, deposit 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_MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 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( diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py index 21fcaca40..0023fbf5e 100644 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py @@ -17,9 +17,9 @@ def test_genesis(spec): yield "genesis_eth1_block_hash", genesis_eth1_block_hash genesis_state = spec.get_genesis_beacon_state( - genesis_deposits, - genesis_time, genesis_eth1_block_hash, + genesis_time, + genesis_deposits, ) assert genesis_state.genesis_time == genesis_time From 6d455136059f2c92a650ab3567dcaf52333bdd25 Mon Sep 17 00:00:00 2001 From: Justin Drake Date: Sat, 29 Jun 2019 21:56:07 +0100 Subject: [PATCH 103/112] Make timestamp a uint64 --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3de90a87c..4d8f6332e 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1103,7 +1103,7 @@ The genesis state `genesis_state` is the return value of the first call to `get_ *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: int, deposits: Sequence[Deposit]) -> BeaconState: +def get_genesis_beacon_state(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=genesis_eth1_block_hash, deposit_count=len(deposits)), From 03a243e96cbfa77c67d6a3ccb2c630ea7405b549 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 05:06:17 +0800 Subject: [PATCH 104/112] fix basic test --- specs/core/0_beacon-chain.md | 2 +- .../eth2spec/test/genesis/test_genesis.py | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 4d8f6332e..7e39a5284 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1106,7 +1106,7 @@ The genesis state `genesis_state` is the return value of the first call to `get_ def get_genesis_beacon_state(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=genesis_eth1_block_hash, deposit_count=len(deposits)), + 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 diff --git a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py index 0023fbf5e..9c546b172 100644 --- a/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py +++ b/test_libs/pyspec/eth2spec/test/genesis/test_genesis.py @@ -6,26 +6,26 @@ from eth2spec.test.helpers.deposits import ( @with_phases(['phase0']) @spectest_with_bls_switch -def test_genesis(spec): +def test_get_genesis_beacon_state_success(spec): deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - genesis_deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - genesis_time = 1546300800 - genesis_eth1_block_hash = b'\x12' * 32 + deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE) - yield "deposits", genesis_deposits - yield "genesis_time", genesis_time + eth1_block_hash = b'\x12' * 32 + eth1_timestamp = spec.MIN_GENESIS_TIME - yield "genesis_eth1_block_hash", genesis_eth1_block_hash + yield "eth1_block_hash", eth1_block_hash + yield "eth1_timestamp", eth1_timestamp + yield "deposits", deposits genesis_state = spec.get_genesis_beacon_state( - genesis_eth1_block_hash, - genesis_time, - genesis_deposits, + eth1_block_hash, + eth1_timestamp, + deposits, ) - assert genesis_state.genesis_time == genesis_time + 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 == genesis_eth1_block_hash + assert genesis_state.eth1_data.block_hash == eth1_block_hash yield "state", genesis_state From ded936ebad1e2486a6918ada4a955d06b3e50e55 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sat, 29 Jun 2019 15:49:11 -0600 Subject: [PATCH 105/112] quick comment on avoiding underflow --- specs/core/0_beacon-chain.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 6f7a7a059..007079555 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -737,8 +737,7 @@ def get_randao_mix(state: BeaconState, epoch: Epoch) -> Hash: """ Return the randao mix at a recent ``epoch``. - ``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch], unless - otherwise noted at a call site. + ``epoch`` expected to be between (current_epoch - EPOCHS_PER_HISTORICAL_VECTOR, current_epoch]. """ return state.randao_mixes[epoch % EPOCHS_PER_HISTORICAL_VECTOR] ``` @@ -763,12 +762,9 @@ def generate_seed(state: BeaconState, epoch: Epoch) -> Hash: """ Generate a seed for the given ``epoch``. - - Note that avoiding the underflow on ``get_randao_mix`` here violates - the epoch validity condition given in that function's comment. """ return hash( - get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + + get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + #avoid underflow get_active_index_root(state, epoch) + int_to_bytes(epoch, length=32) ) From 2a2bd72425f564bff9dde87a6071228c9841fe65 Mon Sep 17 00:00:00 2001 From: Justin Date: Sat, 29 Jun 2019 22:52:01 +0100 Subject: [PATCH 106/112] Update 0_beacon-chain.md --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 77e9055ff..f372c457a 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -786,7 +786,7 @@ def generate_seed(state: BeaconState, Generate a seed for the given ``epoch``. """ return hash( - get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + # avoid underflow + get_randao_mix(state, Epoch(epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD)) + # Avoid underflow hash_tree_root(List[ValidatorIndex, VALIDATOR_REGISTRY_LIMIT](get_active_validator_indices(state, epoch))) + int_to_bytes(epoch, length=32) ) From 47cdae42926fc87084805c2e89b153e4f2f0b58a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Sun, 30 Jun 2019 06:38:30 +0800 Subject: [PATCH 107/112] 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) From 8d2cbc9722bbb264ced4bae1c67d940acc86e217 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sun, 30 Jun 2019 02:08:34 +0200 Subject: [PATCH 108/112] add comments to make variations in genesis initialization clear, and about the mix-in in verification --- specs/core/0_beacon-chain.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 1009da909..957239f58 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1100,6 +1100,10 @@ Before the Ethereum 2.0 genesis has been triggered, and for every Ethereum 1.0 b 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`. +Implementations can choose to support different (more optimized) variations of the below initialization approach: + - Build the `genesis_state` from a stream of deposits by incrementally updating the `state.eth1_data.deposit_root`. + - Compute deposit proofs for the final `state.eth1_data.deposit_root`, and process as a pre-determined collection. + *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 @@ -1671,7 +1675,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, - depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, + depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # add 1 for the SSZ length mix-in index=state.eth1_deposit_index, root=state.eth1_data.deposit_root, ) From 4d5d5971e2b6fef4dba37c4854feec77e1411a05 Mon Sep 17 00:00:00 2001 From: protolambda Date: Sun, 30 Jun 2019 02:10:18 +0200 Subject: [PATCH 109/112] fix genesis tests; sign deposit-datas, and lower min validator count for testing --- configs/constant_presets/minimal.yaml | 2 +- .../genesis/test_initialize_beacon_state_from_eth1.py | 11 +---------- .../test/genesis/test_is_valid_genesis_state.py | 6 +++--- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/configs/constant_presets/minimal.yaml b/configs/constant_presets/minimal.yaml index c17c5806f..50339cd92 100644 --- a/configs/constant_presets/minimal.yaml +++ b/configs/constant_presets/minimal.yaml @@ -17,7 +17,7 @@ CHURN_LIMIT_QUOTIENT: 65536 # [customized] Faster, but unsecure. SHUFFLE_ROUND_COUNT: 10 # [customized] -MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 100 +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 64 # Deposit contract 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 index 86f845f74..b95b70fef 100644 --- 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 @@ -4,20 +4,11 @@ from eth2spec.test.helpers.deposits import ( ) -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) + deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME 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 index 8b41e5ac4..828c62e90 100644 --- 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 @@ -6,7 +6,7 @@ from eth2spec.test.helpers.deposits import ( 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) + deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME @@ -64,7 +64,7 @@ def test_is_valid_genesis_state_false_not_enough_balance(spec): @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) + deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME @@ -77,7 +77,7 @@ def test_is_valid_genesis_state_true_one_more_validator(spec): @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) + deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True) eth1_block_hash = b'\x12' * 32 eth1_timestamp = spec.MIN_GENESIS_TIME From f1749df58723214f4a2440974a1b8fe3eaed2278 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Sat, 29 Jun 2019 22:25:51 -0600 Subject: [PATCH 110/112] minor typo --- .../pyspec/eth2spec/test/genesis/test_is_valid_genesis_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 828c62e90..4ad509200 100644 --- 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 @@ -75,7 +75,7 @@ def test_is_valid_genesis_state_true_one_more_validator(spec): @with_phases(['phase0']) @spectest_with_bls_switch -def test_is_valid_genesis_state_flase_not_enough_validator(spec): +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) From 6cfd3b5047ec54e0a4250a2b262d71a87e99830c Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 30 Jun 2019 08:10:23 +0100 Subject: [PATCH 111/112] Fix typo Thanks @NIC619 https://github.com/ethereum/eth2.0-specs/pull/1219#discussion_r298818138 --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3f834c19c..6ee3fd801 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1485,7 +1485,7 @@ def process_slashings(state: BeaconState) -> None: ```python def process_final_updates(state: BeaconState) -> None: current_epoch = get_current_epoch(state) - next_epoch = Shard(current_epoch + 1) + next_epoch = Epoch(current_epoch + 1) # Reset eth1 data votes if (state.slot + 1) % SLOTS_PER_ETH1_VOTING_PERIOD == 0: state.eth1_data_votes = [] From ae888e148c57c471f916f45f0696717f54699b2a Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 30 Jun 2019 08:13:07 +0100 Subject: [PATCH 112/112] Minor copyedit Can the linter catch non-capitalised comments? --- specs/core/0_beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 3f834c19c..2e1b5d138 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1688,7 +1688,7 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None: assert verify_merkle_branch( leaf=hash_tree_root(deposit.data), proof=deposit.proof, - depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # add 1 for the SSZ length mix-in + depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the `List` length mix-in index=state.eth1_deposit_index, root=state.eth1_data.deposit_root, )