From 649dbfdf6c3a088ea0c8e444c7e8e18fd6e8357a Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 26 Apr 2019 14:43:05 +0800 Subject: [PATCH 1/4] bugfix: missing validator --- specs/core/0_beacon-chain.md | 1 + 1 file changed, 1 insertion(+) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 55791e25f..f7d4f8288 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1562,6 +1562,7 @@ def process_registry_updates(state: BeaconState) -> None: ], key=lambda index: state.validator_registry[index].activation_eligibility_epoch) # Dequeued validators for activation up to churn limit (without resetting activation epoch) for index in activation_queue[:get_churn_limit(state)]: + validator = state.validator_registry[index] if validator.activation_epoch == FAR_FUTURE_EPOCH: validator.activation_epoch = get_delayed_activation_exit_epoch(get_current_epoch(state)) ``` From 0de772fc1c27ea9a0d2c37ae55bf08faab4a1226 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 26 Apr 2019 14:43:21 +0800 Subject: [PATCH 2/4] Add tests/epoch_processing/test_process_registry_updates.py --- .../test_process_registry_updates.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py diff --git a/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py new file mode 100644 index 000000000..9bc70335b --- /dev/null +++ b/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py @@ -0,0 +1,35 @@ +from copy import deepcopy + +import eth2spec.phase0.spec as spec + +from eth2spec.phase0.spec import ( + get_current_epoch, + is_active_validator, +) +from tests.helpers import ( + next_epoch, +) + + +def test_activation(state): + # Mock a new deposit + index = 0 + state.validator_registry[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH + state.validator_registry[index].activation_epoch = spec.FAR_FUTURE_EPOCH + state.validator_registry[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE + + assert not is_active_validator(state.validator_registry[index], get_current_epoch(state)) + + pre_state = deepcopy(state) + + for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): + next_epoch(state) + + assert state.validator_registry[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH + assert state.validator_registry[index].activation_epoch != spec.FAR_FUTURE_EPOCH + assert is_active_validator( + state.validator_registry[index], + get_current_epoch(state), + ) + + return pre_state, state From 70cd3d2253e3ae40b10f62d5824e4b025eae92fd Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Fri, 26 Apr 2019 14:53:58 +0800 Subject: [PATCH 3/4] Add `test_ejection` --- .../test_process_registry_updates.py | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py index 9bc70335b..6a3f156c4 100644 --- a/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py @@ -12,12 +12,13 @@ from tests.helpers import ( def test_activation(state): - # Mock a new deposit index = 0 + assert is_active_validator(state.validator_registry[index], get_current_epoch(state)) + + # Mock a new deposit state.validator_registry[index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH state.validator_registry[index].activation_epoch = spec.FAR_FUTURE_EPOCH state.validator_registry[index].effective_balance = spec.MAX_EFFECTIVE_BALANCE - assert not is_active_validator(state.validator_registry[index], get_current_epoch(state)) pre_state = deepcopy(state) @@ -33,3 +34,25 @@ def test_activation(state): ) return pre_state, state + + +def test_ejection(state): + index = 0 + assert is_active_validator(state.validator_registry[index], get_current_epoch(state)) + assert state.validator_registry[index].exit_epoch == spec.FAR_FUTURE_EPOCH + + # Mock an ejection + state.validator_registry[index].effective_balance = spec.EJECTION_BALANCE + + pre_state = deepcopy(state) + + for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): + next_epoch(state) + + assert state.validator_registry[index].exit_epoch != spec.FAR_FUTURE_EPOCH + assert not is_active_validator( + state.validator_registry[index], + get_current_epoch(state), + ) + + return pre_state, state From f76ade93d8a689db107b0ff05e54dce3d3a5d82f Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 26 Apr 2019 08:27:07 -0600 Subject: [PATCH 4/4] update registry tests to return the blocks that transiiton the pre_state to post_state --- specs/validator/0_beacon-chain-validator.md | 2 +- .../test_process_registry_updates.py | 17 +++++++++++++---- test_libs/pyspec/tests/helpers.py | 10 ++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/specs/validator/0_beacon-chain-validator.md b/specs/validator/0_beacon-chain-validator.md index dab02b773..2d0728e7c 100644 --- a/specs/validator/0_beacon-chain-validator.md +++ b/specs/validator/0_beacon-chain-validator.md @@ -224,7 +224,7 @@ Up to `MAX_ATTESTATIONS` aggregate attestations can be included in the `block`. ##### Deposits -If there are any unprocessed deposits for the existing `state.latest_eth1_data` (i.e. `state.latest_eth1_data.deposit_count > state.deposit_index`), then pending deposits _must_ be added to the block. The expected number of deposits is exactly `min(MAX_DEPOSITS, latest_eth1_data.deposit_count - state.deposit_index)`. These [`deposits`](../core/0_beacon-chain.md#deposit) are constructed from the `Deposit` logs from the [Eth1.0 deposit contract](../core/0_deposit-contract.md) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](../core/0_beacon-chain.md#deposits). +If there are any unprocessed deposits for the existing `state.latest_eth1_data` (i.e. `state.latest_eth1_data.deposit_count > state.deposit_index`), then pending deposits _must_ be added to the block. The expected number of deposits is exactly `min(MAX_DEPOSITS, latest_eth1_data.deposit_count - state.deposit_index)`. These [`deposits`](../core/0_beacon-chain.md#deposit) are constructed from the `Deposit` logs from the [Eth1.0 deposit contract](../core/0_deposit-contract) and must be processed in sequential order. The deposits included in the `block` must satisfy the verification conditions found in [deposits processing](../core/0_beacon-chain.md#deposits). The `proof` for each deposit must be constructed against the deposit root contained in `state.latest_eth1_data` rather than the deposit root at the time the deposit was initially logged from the 1.0 chain. This entails storing a full deposit merkle tree locally and computing updated proofs against the `latest_eth1_data.deposit_root` as needed. See [`minimal_merkle.py`](https://github.com/ethereum/research/blob/master/spec_pythonizer/utils/merkle_minimal.py) for a sample implementation. diff --git a/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py b/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py index 6a3f156c4..11f5de2ad 100644 --- a/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py +++ b/test_libs/pyspec/tests/epoch_processing/test_process_registry_updates.py @@ -1,5 +1,7 @@ from copy import deepcopy +import pytest + import eth2spec.phase0.spec as spec from eth2spec.phase0.spec import ( @@ -10,6 +12,9 @@ from tests.helpers import ( next_epoch, ) +# mark entire file as 'state' +pytestmark = pytest.mark.state + def test_activation(state): index = 0 @@ -23,8 +28,10 @@ def test_activation(state): pre_state = deepcopy(state) + blocks = [] for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): - next_epoch(state) + block = next_epoch(state) + blocks.append(block) assert state.validator_registry[index].activation_eligibility_epoch != spec.FAR_FUTURE_EPOCH assert state.validator_registry[index].activation_epoch != spec.FAR_FUTURE_EPOCH @@ -33,7 +40,7 @@ def test_activation(state): get_current_epoch(state), ) - return pre_state, state + return pre_state, blocks, state def test_ejection(state): @@ -46,8 +53,10 @@ def test_ejection(state): pre_state = deepcopy(state) + blocks = [] for _ in range(spec.ACTIVATION_EXIT_DELAY + 1): - next_epoch(state) + block = next_epoch(state) + blocks.append(block) assert state.validator_registry[index].exit_epoch != spec.FAR_FUTURE_EPOCH assert not is_active_validator( @@ -55,4 +64,4 @@ def test_ejection(state): get_current_epoch(state), ) - return pre_state, state + return pre_state, blocks, state diff --git a/test_libs/pyspec/tests/helpers.py b/test_libs/pyspec/tests/helpers.py index 63e4cd710..19df560ac 100644 --- a/test_libs/pyspec/tests/helpers.py +++ b/test_libs/pyspec/tests/helpers.py @@ -402,11 +402,21 @@ def add_attestation_to_state(state, attestation, slot): def next_slot(state): + """ + Transition to the next slot via an empty block. + Return the empty block that triggered the transition. + """ block = build_empty_block_for_next_slot(state) state_transition(state, block) + return block def next_epoch(state): + """ + Transition to the start slot of the next epoch via an empty block. + Return the empty block that triggered the transition. + """ block = build_empty_block_for_next_slot(state) block.slot += spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH) state_transition(state, block) + return block