From 9f4e59b0bc5c9552e79313ab3dfdeee870b6b4a0 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Thu, 18 Apr 2019 18:33:06 -0600 Subject: [PATCH 1/7] enhance finality testing -- case 1, 2, 4 --- specs/core/0_beacon-chain.md | 4 + test_libs/pyspec/tests/helpers.py | 1 - test_libs/pyspec/tests/test_finality.py | 156 ++++++++++++++++++++++++ test_libs/pyspec/tests/test_sanity.py | 27 ---- 4 files changed, 160 insertions(+), 28 deletions(-) create mode 100644 test_libs/pyspec/tests/test_finality.py diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index eaceec6ac..4cdfa9c4f 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1697,18 +1697,22 @@ def process_justification_and_finalization(state: BeaconState) -> None: current_epoch = get_current_epoch(state) # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source if (bitfield >> 1) % 8 == 0b111 and old_previous_justified_epoch == current_epoch - 3: + print("rule 1") state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source if (bitfield >> 1) % 4 == 0b11 and old_previous_justified_epoch == current_epoch - 2: + print("rule 2") state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source if (bitfield >> 0) % 8 == 0b111 and old_current_justified_epoch == current_epoch - 2: + print("rule 3") state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source if (bitfield >> 0) % 4 == 0b11 and old_current_justified_epoch == current_epoch - 1: + print("rule 4") state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) ``` diff --git a/test_libs/pyspec/tests/helpers.py b/test_libs/pyspec/tests/helpers.py index 44d2dcb4d..387c434a0 100644 --- a/test_libs/pyspec/tests/helpers.py +++ b/test_libs/pyspec/tests/helpers.py @@ -155,7 +155,6 @@ def build_attestation_data(state, slot, shard): current_epoch_start_slot = get_epoch_start_slot(get_current_epoch(state)) if slot < current_epoch_start_slot: - print(slot) epoch_boundary_root = get_block_root(state, get_epoch_start_slot(get_previous_epoch(state))) elif slot == current_epoch_start_slot: epoch_boundary_root = block_root diff --git a/test_libs/pyspec/tests/test_finality.py b/test_libs/pyspec/tests/test_finality.py new file mode 100644 index 000000000..8a429cb6e --- /dev/null +++ b/test_libs/pyspec/tests/test_finality.py @@ -0,0 +1,156 @@ +from copy import deepcopy + +import pytest + +import eth2spec.phase0.spec as spec + +from eth2spec.phase0.state_transition import ( + state_transition, +) +from .helpers import ( + build_empty_block_for_next_slot, + fill_aggregate_attestation, + get_current_epoch, + get_epoch_start_slot, + get_valid_attestation, + next_epoch, +) + +# mark entire file as 'state' +pytestmark = pytest.mark.state + + +def check_finality(state, + prev_state, + current_justified_changed, + previous_justified_changed, + finalized_changed): + if current_justified_changed: + assert state.current_justified_epoch > prev_state.current_justified_epoch + assert state.current_justified_root != prev_state.current_justified_root + else: + assert state.current_justified_epoch == prev_state.current_justified_epoch + assert state.current_justified_root == prev_state.current_justified_root + + if previous_justified_changed: + assert state.previous_justified_epoch > prev_state.previous_justified_epoch + assert state.previous_justified_root != prev_state.previous_justified_root + else: + assert state.previous_justified_epoch == prev_state.previous_justified_epoch + assert state.previous_justified_root == prev_state.previous_justified_root + + if finalized_changed: + assert state.finalized_epoch > prev_state.finalized_epoch + assert state.finalized_root != prev_state.finalized_root + else: + assert state.finalized_epoch == prev_state.finalized_epoch + assert state.finalized_root == prev_state.finalized_root + + +def test_finality_from_genesis_rule_4(state): + test_state = deepcopy(state) + + blocks = [] + for epoch in range(6): + old_current_justified_epoch = test_state.current_justified_epoch + old_current_justified_root = test_state.current_justified_root + for slot in range(spec.SLOTS_PER_EPOCH): + attestation = None + slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 + if slot_to_attest >= spec.GENESIS_SLOT: + attestation = get_valid_attestation(test_state, slot_to_attest) + fill_aggregate_attestation(test_state, attestation) + block = build_empty_block_for_next_slot(test_state) + if attestation: + block.body.attestations.append(attestation) + state_transition(test_state, block) + blocks.append(block) + + if epoch == 0: + check_finality(test_state, state, False, False, False) + elif epoch == 1: + check_finality(test_state, state, False, False, False) + elif epoch == 2: + check_finality(test_state, state, True, False, False) + elif epoch >= 3: + # rule 4 of finaliy + check_finality(test_state, state, True, True, True) + assert test_state.finalized_epoch == old_current_justified_epoch + assert test_state.finalized_root == old_current_justified_root + + return state, blocks, test_state + + +def test_finality_rule_1(state): + # get past first two epochs that finality does not run on + next_epoch(state) + next_epoch(state) + + test_state = deepcopy(state) + + blocks = [] + for epoch in range(3): + old_previous_justified_epoch = test_state.previous_justified_epoch + old_previous_justified_root = test_state.previous_justified_root + for slot in range(spec.SLOTS_PER_EPOCH): + slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 + attestation = get_valid_attestation(test_state, slot_to_attest) + fill_aggregate_attestation(test_state, attestation) + block = build_empty_block_for_next_slot(test_state) + block.body.attestations.append(attestation) + state_transition(test_state, block) + + assert len(test_state.previous_epoch_attestations) >= 0 + assert len(test_state.current_epoch_attestations) == 0 + + blocks.append(block) + + if epoch == 0: + check_finality(test_state, state, True, False, False) + elif epoch == 1: + check_finality(test_state, state, True, True, False) + elif epoch == 2: + # finalized by rule 1 + check_finality(test_state, state, True, True, True) + assert test_state.finalized_epoch == old_previous_justified_epoch + assert test_state.finalized_root == old_previous_justified_root + + +def test_finality_rule_2(state): + # get past first two epochs that finality does not run on + next_epoch(state) + next_epoch(state) + + test_state = deepcopy(state) + + blocks = [] + for epoch in range(3): + old_previous_justified_epoch = test_state.previous_justified_epoch + old_previous_justified_root = test_state.previous_justified_root + for slot in range(spec.SLOTS_PER_EPOCH): + attestation = None + if epoch == 0: + slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 + if slot_to_attest >= get_epoch_start_slot(get_current_epoch(state)): + attestation = get_valid_attestation(test_state, slot_to_attest) + fill_aggregate_attestation(test_state, attestation) + if epoch == 2: + slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 + attestation = get_valid_attestation(test_state, slot_to_attest) + fill_aggregate_attestation(test_state, attestation) + + block = build_empty_block_for_next_slot(test_state) + if attestation: + block.body.attestations.append(attestation) + state_transition(test_state, block) + blocks.append(block) + + if epoch == 0: + check_finality(test_state, state, True, False, False) + elif epoch == 1: + check_finality(test_state, state, True, True, False) + elif epoch == 2: + # finalized by rule 2 + check_finality(test_state, state, True, True, True) + assert test_state.finalized_epoch == old_previous_justified_epoch + assert test_state.finalized_root == old_previous_justified_root diff --git a/test_libs/pyspec/tests/test_sanity.py b/test_libs/pyspec/tests/test_sanity.py index 29333a7ad..e48a6b774 100644 --- a/test_libs/pyspec/tests/test_sanity.py +++ b/test_libs/pyspec/tests/test_sanity.py @@ -145,33 +145,6 @@ def test_empty_epoch_transition_not_finalizing(state): return state, [block], test_state -def test_full_attestations_finalizing(state): - test_state = deepcopy(state) - - for slot in range(spec.MIN_ATTESTATION_INCLUSION_DELAY): - next_slot(test_state) - - for epoch in range(5): - for slot in range(spec.SLOTS_PER_EPOCH): - print(test_state.slot) - attestation = get_valid_attestation(test_state, test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY) - fill_aggregate_attestation(test_state, attestation) - block = build_empty_block_for_next_slot(test_state) - block.body.attestations.append(attestation) - state_transition(test_state, block) - - if epoch == 0: - check_finality(test_state, state, False, False, False) - elif epoch == 1: - check_finality(test_state, state, False, False, False) - elif epoch == 2: - check_finality(test_state, state, True, False, False) - elif epoch == 3: - check_finality(test_state, state, True, True, False) - elif epoch == 4: - check_finality(test_state, state, True, True, True) - - def test_proposer_slashing(state): test_state = deepcopy(state) proposer_slashing = get_valid_proposer_slashing(state) From edb24ce9dda0c54c5cc86520f7ef99091ce7af10 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 22 Apr 2019 09:00:01 -0600 Subject: [PATCH 2/7] test rule 3 --- specs/core/0_beacon-chain.md | 4 + test_libs/pyspec/tests/test_finality.py | 158 +++++++++++++++++++----- 2 files changed, 132 insertions(+), 30 deletions(-) diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 4cdfa9c4f..1df72179d 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1682,12 +1682,16 @@ def process_justification_and_finalization(state: BeaconState) -> None: state.previous_justified_root = state.current_justified_root state.justification_bitfield = (state.justification_bitfield << 1) % 2**64 previous_boundary_attesting_balance = get_attesting_balance(state, get_previous_epoch_boundary_attestations(state)) + print(previous_boundary_attesting_balance) if previous_boundary_attesting_balance * 3 >= get_previous_total_balance(state) * 2: + print("prev success") state.current_justified_epoch = get_previous_epoch(state) state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch)) state.justification_bitfield |= (1 << 1) current_boundary_attesting_balance = get_attesting_balance(state, get_current_epoch_boundary_attestations(state)) + print(current_boundary_attesting_balance) if current_boundary_attesting_balance * 3 >= get_current_total_balance(state) * 2: + print("cur success") state.current_justified_epoch = get_current_epoch(state) state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch)) state.justification_bitfield |= (1 << 0) diff --git a/test_libs/pyspec/tests/test_finality.py b/test_libs/pyspec/tests/test_finality.py index 8a429cb6e..ae8ba13ff 100644 --- a/test_libs/pyspec/tests/test_finality.py +++ b/test_libs/pyspec/tests/test_finality.py @@ -47,11 +47,50 @@ def check_finality(state, assert state.finalized_root == prev_state.finalized_root +def next_epoch_with_attestations(state, + fill_cur_epoch, + fill_prev_epoch): + post_state = deepcopy(state) + blocks = [] + for slot in range(spec.SLOTS_PER_EPOCH): + print("slot: %s", post_state.slot) + block = build_empty_block_for_next_slot(post_state) + if fill_prev_epoch: + print("prev") + slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 + prev_attestation = get_valid_attestation(post_state, slot_to_attest) + block.body.attestations.append(prev_attestation) + + if fill_cur_epoch: + print("cur") + slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 + if slot_to_attest >= get_epoch_start_slot(get_current_epoch(post_state)): + cur_attestation = get_valid_attestation(post_state, slot_to_attest) + fill_aggregate_attestation(post_state, cur_attestation) + block.body.attestations.append(cur_attestation) + + state_transition(post_state, block) + blocks.append(block) + + # if fill_prev_epoch: + # assert len(post_state.previous_epoch_attestations) >= 0 + # else: + # assert len(post_state.previous_epoch_attestations) == 0 + + # if fill_cur_epoch: + # assert len(post_state.current_epoch_attestations) >= 0 + # else: + # assert len(post_state.current_epoch_attestations) == 0 + + return state, blocks, post_state + + def test_finality_from_genesis_rule_4(state): test_state = deepcopy(state) blocks = [] for epoch in range(6): + prev_state = deepcopy(test_state) old_current_justified_epoch = test_state.current_justified_epoch old_current_justified_root = test_state.current_justified_root for slot in range(spec.SLOTS_PER_EPOCH): @@ -67,14 +106,14 @@ def test_finality_from_genesis_rule_4(state): blocks.append(block) if epoch == 0: - check_finality(test_state, state, False, False, False) + check_finality(test_state, prev_state, False, False, False) elif epoch == 1: - check_finality(test_state, state, False, False, False) + check_finality(test_state, prev_state, False, False, False) elif epoch == 2: - check_finality(test_state, state, True, False, False) + check_finality(test_state, prev_state, True, False, False) elif epoch >= 3: # rule 4 of finaliy - check_finality(test_state, state, True, True, True) + check_finality(test_state, prev_state, True, True, True) assert test_state.finalized_epoch == old_current_justified_epoch assert test_state.finalized_root == old_current_justified_root @@ -90,6 +129,7 @@ def test_finality_rule_1(state): blocks = [] for epoch in range(3): + prev_state = deepcopy(test_state) old_previous_justified_epoch = test_state.previous_justified_epoch old_previous_justified_root = test_state.previous_justified_root for slot in range(spec.SLOTS_PER_EPOCH): @@ -106,15 +146,17 @@ def test_finality_rule_1(state): blocks.append(block) if epoch == 0: - check_finality(test_state, state, True, False, False) + check_finality(test_state, prev_state, True, False, False) elif epoch == 1: - check_finality(test_state, state, True, True, False) + check_finality(test_state, prev_state, True, True, False) elif epoch == 2: # finalized by rule 1 - check_finality(test_state, state, True, True, True) + check_finality(test_state, prev_state, True, True, True) assert test_state.finalized_epoch == old_previous_justified_epoch assert test_state.finalized_root == old_previous_justified_root + return state, blocks, test_state + def test_finality_rule_2(state): # get past first two epochs that finality does not run on @@ -127,30 +169,86 @@ def test_finality_rule_2(state): for epoch in range(3): old_previous_justified_epoch = test_state.previous_justified_epoch old_previous_justified_root = test_state.previous_justified_root - for slot in range(spec.SLOTS_PER_EPOCH): - attestation = None - if epoch == 0: - slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 - if slot_to_attest >= get_epoch_start_slot(get_current_epoch(state)): - attestation = get_valid_attestation(test_state, slot_to_attest) - fill_aggregate_attestation(test_state, attestation) - if epoch == 2: - slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 - attestation = get_valid_attestation(test_state, slot_to_attest) - fill_aggregate_attestation(test_state, attestation) - - block = build_empty_block_for_next_slot(test_state) - if attestation: - block.body.attestations.append(attestation) - state_transition(test_state, block) - blocks.append(block) - if epoch == 0: - check_finality(test_state, state, True, False, False) - elif epoch == 1: - check_finality(test_state, state, True, True, False) - elif epoch == 2: + prev_state, blocks, test_state = next_epoch_with_attestations(test_state, True, False) + check_finality(test_state, prev_state, True, False, False) + if epoch == 1: + prev_state, blocks, test_state = next_epoch_with_attestations(test_state, False, False) + check_finality(test_state, prev_state, False, True, False) + if epoch == 2: + prev_state, blocks, test_state = next_epoch_with_attestations(test_state, False, True) # finalized by rule 2 - check_finality(test_state, state, True, True, True) + check_finality(test_state, prev_state, True, False, True) assert test_state.finalized_epoch == old_previous_justified_epoch assert test_state.finalized_root == old_previous_justified_root + return state, blocks, test_state + + +def test_finality_rule_3(state): + # get past first two epochs that finality does not run on + next_epoch(state) + next_epoch(state) + + test_state = deepcopy(state) + + blocks = [] + for epoch in range(2): + prev_state = deepcopy(test_state) + for slot in range(spec.SLOTS_PER_EPOCH): + slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 + attestation = get_valid_attestation(test_state, slot_to_attest) + fill_aggregate_attestation(test_state, attestation) + block = build_empty_block_for_next_slot(test_state) + block.body.attestations.append(attestation) + state_transition(test_state, block) + + blocks.append(block) + if epoch == 0: + check_finality(test_state, prev_state, True, False, False) + if epoch == 1: + check_finality(test_state, prev_state, True, True, True) + + prev_state = deepcopy(test_state) + next_epoch(test_state) + check_finality(test_state, prev_state, False, True, False) + + + prev_state = deepcopy(test_state) + for slot in range(spec.SLOTS_PER_EPOCH): + slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 + attestation = get_valid_attestation(test_state, slot_to_attest) + fill_aggregate_attestation(test_state, attestation) + block = build_empty_block_for_next_slot(test_state) + block.body.attestations.append(attestation) + state_transition(test_state, block) + + assert len(test_state.previous_epoch_attestations) >= 0 + assert len(test_state.current_epoch_attestations) == 0 + + blocks.append(block) + check_finality(test_state, prev_state, True, False, True) + + + prev_state = deepcopy(test_state) + for slot in range(spec.SLOTS_PER_EPOCH): + prev_slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 + prev_attestation = get_valid_attestation(test_state, prev_slot_to_attest) + fill_aggregate_attestation(test_state, prev_attestation) + + cur_slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 + cur_attestation = get_valid_attestation(test_state, cur_slot_to_attest) + fill_aggregate_attestation(test_state, cur_attestation) + + block = build_empty_block_for_next_slot(test_state) + block.body.attestations.append(prev_attestation) + block.body.attestations.append(cur_attestation) + + state_transition(test_state, block) + + assert len(test_state.previous_epoch_attestations) >= 0 + assert len(test_state.current_epoch_attestations) >= 0 + + blocks.append(block) + check_finality(test_state, prev_state, True, True, True) + + return state, blocks, test_state From bd0552c796b903c18c7690415c3391898528e5ae Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 23 Apr 2019 13:32:41 -0600 Subject: [PATCH 3/7] fix finality tests for each rule --- specs/core/0_beacon-chain.md | 8 - test_libs/pyspec/tests/test_finality.py | 165 +++++--------- test_libs/pyspec/tests/test_sanity.py | 27 --- tests/phase0/__init__.py | 0 .../test_process_block_header.py | 60 ------ .../block_processing/test_process_deposit.py | 140 ------------ .../block_processing/test_voluntary_exit.py | 175 --------------- tests/phase0/helpers.py | 203 ------------------ 8 files changed, 52 insertions(+), 726 deletions(-) delete mode 100644 tests/phase0/__init__.py delete mode 100644 tests/phase0/block_processing/test_process_block_header.py delete mode 100644 tests/phase0/block_processing/test_process_deposit.py delete mode 100644 tests/phase0/block_processing/test_voluntary_exit.py delete mode 100644 tests/phase0/helpers.py diff --git a/specs/core/0_beacon-chain.md b/specs/core/0_beacon-chain.md index 171a120d0..084bec844 100644 --- a/specs/core/0_beacon-chain.md +++ b/specs/core/0_beacon-chain.md @@ -1564,16 +1564,12 @@ def process_justification_and_finalization(state: BeaconState) -> None: state.previous_justified_root = state.current_justified_root state.justification_bitfield = (state.justification_bitfield << 1) % 2**64 previous_boundary_attesting_balance = get_attesting_balance(state, get_previous_epoch_boundary_attestations(state)) - print(previous_boundary_attesting_balance) if previous_boundary_attesting_balance * 3 >= get_previous_total_balance(state) * 2: - print("prev success") state.current_justified_epoch = get_previous_epoch(state) state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch)) state.justification_bitfield |= (1 << 1) current_boundary_attesting_balance = get_attesting_balance(state, get_current_epoch_boundary_attestations(state)) - print(current_boundary_attesting_balance) if current_boundary_attesting_balance * 3 >= get_current_total_balance(state) * 2: - print("cur success") state.current_justified_epoch = get_current_epoch(state) state.current_justified_root = get_block_root(state, get_epoch_start_slot(state.current_justified_epoch)) state.justification_bitfield |= (1 << 0) @@ -1583,22 +1579,18 @@ def process_justification_and_finalization(state: BeaconState) -> None: current_epoch = get_current_epoch(state) # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source if (bitfield >> 1) % 8 == 0b111 and old_previous_justified_epoch == current_epoch - 3: - print("rule 1") state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source if (bitfield >> 1) % 4 == 0b11 and old_previous_justified_epoch == current_epoch - 2: - print("rule 2") state.finalized_epoch = old_previous_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source if (bitfield >> 0) % 8 == 0b111 and old_current_justified_epoch == current_epoch - 2: - print("rule 3") state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source if (bitfield >> 0) % 4 == 0b11 and old_current_justified_epoch == current_epoch - 1: - print("rule 4") state.finalized_epoch = old_current_justified_epoch state.finalized_root = get_block_root(state, get_epoch_start_slot(state.finalized_epoch)) ``` diff --git a/test_libs/pyspec/tests/test_finality.py b/test_libs/pyspec/tests/test_finality.py index ae8ba13ff..8c1b4e871 100644 --- a/test_libs/pyspec/tests/test_finality.py +++ b/test_libs/pyspec/tests/test_finality.py @@ -53,35 +53,23 @@ def next_epoch_with_attestations(state, post_state = deepcopy(state) blocks = [] for slot in range(spec.SLOTS_PER_EPOCH): - print("slot: %s", post_state.slot) block = build_empty_block_for_next_slot(post_state) - if fill_prev_epoch: - print("prev") - slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 - prev_attestation = get_valid_attestation(post_state, slot_to_attest) - block.body.attestations.append(prev_attestation) - if fill_cur_epoch: - print("cur") slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 if slot_to_attest >= get_epoch_start_slot(get_current_epoch(post_state)): cur_attestation = get_valid_attestation(post_state, slot_to_attest) fill_aggregate_attestation(post_state, cur_attestation) block.body.attestations.append(cur_attestation) + if fill_prev_epoch: + slot_to_attest = post_state.slot - spec.SLOTS_PER_EPOCH + 1 + prev_attestation = get_valid_attestation(post_state, slot_to_attest) + fill_aggregate_attestation(post_state, prev_attestation) + block.body.attestations.append(prev_attestation) + state_transition(post_state, block) blocks.append(block) - # if fill_prev_epoch: - # assert len(post_state.previous_epoch_attestations) >= 0 - # else: - # assert len(post_state.previous_epoch_attestations) == 0 - - # if fill_cur_epoch: - # assert len(post_state.current_epoch_attestations) >= 0 - # else: - # assert len(post_state.current_epoch_attestations) == 0 - return state, blocks, post_state @@ -90,20 +78,8 @@ def test_finality_from_genesis_rule_4(state): blocks = [] for epoch in range(6): - prev_state = deepcopy(test_state) - old_current_justified_epoch = test_state.current_justified_epoch - old_current_justified_root = test_state.current_justified_root - for slot in range(spec.SLOTS_PER_EPOCH): - attestation = None - slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 - if slot_to_attest >= spec.GENESIS_SLOT: - attestation = get_valid_attestation(test_state, slot_to_attest) - fill_aggregate_attestation(test_state, attestation) - block = build_empty_block_for_next_slot(test_state) - if attestation: - block.body.attestations.append(attestation) - state_transition(test_state, block) - blocks.append(block) + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) + blocks += new_blocks if epoch == 0: check_finality(test_state, prev_state, False, False, False) @@ -114,8 +90,8 @@ def test_finality_from_genesis_rule_4(state): elif epoch >= 3: # rule 4 of finaliy check_finality(test_state, prev_state, True, True, True) - assert test_state.finalized_epoch == old_current_justified_epoch - assert test_state.finalized_root == old_current_justified_root + assert test_state.finalized_epoch == prev_state.current_justified_epoch + assert test_state.finalized_root == prev_state.current_justified_root return state, blocks, test_state @@ -125,25 +101,13 @@ def test_finality_rule_1(state): next_epoch(state) next_epoch(state) + pre_state = deepcopy(state) test_state = deepcopy(state) blocks = [] for epoch in range(3): - prev_state = deepcopy(test_state) - old_previous_justified_epoch = test_state.previous_justified_epoch - old_previous_justified_root = test_state.previous_justified_root - for slot in range(spec.SLOTS_PER_EPOCH): - slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 - attestation = get_valid_attestation(test_state, slot_to_attest) - fill_aggregate_attestation(test_state, attestation) - block = build_empty_block_for_next_slot(test_state) - block.body.attestations.append(attestation) - state_transition(test_state, block) - - assert len(test_state.previous_epoch_attestations) >= 0 - assert len(test_state.current_epoch_attestations) == 0 - - blocks.append(block) + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, True) + blocks += new_blocks if epoch == 0: check_finality(test_state, prev_state, True, False, False) @@ -152,10 +116,10 @@ def test_finality_rule_1(state): elif epoch == 2: # finalized by rule 1 check_finality(test_state, prev_state, True, True, True) - assert test_state.finalized_epoch == old_previous_justified_epoch - assert test_state.finalized_root == old_previous_justified_root + assert test_state.finalized_epoch == prev_state.previous_justified_epoch + assert test_state.finalized_root == prev_state.previous_justified_root - return state, blocks, test_state + return pre_state, blocks, test_state def test_finality_rule_2(state): @@ -163,6 +127,7 @@ def test_finality_rule_2(state): next_epoch(state) next_epoch(state) + pre_state = deepcopy(state) test_state = deepcopy(state) blocks = [] @@ -170,85 +135,59 @@ def test_finality_rule_2(state): old_previous_justified_epoch = test_state.previous_justified_epoch old_previous_justified_root = test_state.previous_justified_root if epoch == 0: - prev_state, blocks, test_state = next_epoch_with_attestations(test_state, True, False) + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) check_finality(test_state, prev_state, True, False, False) if epoch == 1: - prev_state, blocks, test_state = next_epoch_with_attestations(test_state, False, False) + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, False) check_finality(test_state, prev_state, False, True, False) if epoch == 2: - prev_state, blocks, test_state = next_epoch_with_attestations(test_state, False, True) + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, True) # finalized by rule 2 check_finality(test_state, prev_state, True, False, True) assert test_state.finalized_epoch == old_previous_justified_epoch assert test_state.finalized_root == old_previous_justified_root - return state, blocks, test_state + + blocks += new_blocks + + return pre_state, blocks, test_state def test_finality_rule_3(state): + """ + Test scenario described here + https://github.com/ethereum/eth2.0-specs/issues/611#issuecomment-463612892 + """ + # get past first two epochs that finality does not run on next_epoch(state) next_epoch(state) + pre_state = deepcopy(state) test_state = deepcopy(state) blocks = [] - for epoch in range(2): - prev_state = deepcopy(test_state) - for slot in range(spec.SLOTS_PER_EPOCH): - slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 - attestation = get_valid_attestation(test_state, slot_to_attest) - fill_aggregate_attestation(test_state, attestation) - block = build_empty_block_for_next_slot(test_state) - block.body.attestations.append(attestation) - state_transition(test_state, block) + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) + blocks += new_blocks + check_finality(test_state, prev_state, True, False, False) - blocks.append(block) - if epoch == 0: - check_finality(test_state, prev_state, True, False, False) - if epoch == 1: - check_finality(test_state, prev_state, True, True, True) - - prev_state = deepcopy(test_state) - next_epoch(test_state) - check_finality(test_state, prev_state, False, True, False) - - - prev_state = deepcopy(test_state) - for slot in range(spec.SLOTS_PER_EPOCH): - slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 - attestation = get_valid_attestation(test_state, slot_to_attest) - fill_aggregate_attestation(test_state, attestation) - block = build_empty_block_for_next_slot(test_state) - block.body.attestations.append(attestation) - state_transition(test_state, block) - - assert len(test_state.previous_epoch_attestations) >= 0 - assert len(test_state.current_epoch_attestations) == 0 - - blocks.append(block) - check_finality(test_state, prev_state, True, False, True) - - - prev_state = deepcopy(test_state) - for slot in range(spec.SLOTS_PER_EPOCH): - prev_slot_to_attest = test_state.slot - spec.SLOTS_PER_EPOCH + 1 - prev_attestation = get_valid_attestation(test_state, prev_slot_to_attest) - fill_aggregate_attestation(test_state, prev_attestation) - - cur_slot_to_attest = test_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1 - cur_attestation = get_valid_attestation(test_state, cur_slot_to_attest) - fill_aggregate_attestation(test_state, cur_attestation) - - block = build_empty_block_for_next_slot(test_state) - block.body.attestations.append(prev_attestation) - block.body.attestations.append(cur_attestation) - - state_transition(test_state, block) - - assert len(test_state.previous_epoch_attestations) >= 0 - assert len(test_state.current_epoch_attestations) >= 0 - - blocks.append(block) + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) + blocks += new_blocks check_finality(test_state, prev_state, True, True, True) - return state, blocks, test_state + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, False) + blocks += new_blocks + check_finality(test_state, prev_state, False, True, False) + + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, True) + blocks += new_blocks + # rule 2 + check_finality(test_state, prev_state, True, False, True) + + prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, True) + blocks += new_blocks + # rule 3 + check_finality(test_state, prev_state, True, True, True) + assert test_state.finalized_epoch == prev_state.current_justified_epoch + assert test_state.finalized_root == prev_state.current_justified_root + + return pre_state, blocks, test_state diff --git a/test_libs/pyspec/tests/test_sanity.py b/test_libs/pyspec/tests/test_sanity.py index f0476f1c6..f330c2b19 100644 --- a/test_libs/pyspec/tests/test_sanity.py +++ b/test_libs/pyspec/tests/test_sanity.py @@ -53,33 +53,6 @@ from .helpers import ( pytestmark = pytest.mark.sanity -def check_finality(state, - prev_state, - current_justified_changed, - previous_justified_changed, - finalized_changed): - if current_justified_changed: - assert state.current_justified_epoch > prev_state.current_justified_epoch - assert state.current_justified_root != prev_state.current_justified_root - else: - assert state.current_justified_epoch == prev_state.current_justified_epoch - assert state.current_justified_root == prev_state.current_justified_root - - if previous_justified_changed: - assert state.previous_justified_epoch > prev_state.previous_justified_epoch - assert state.previous_justified_root != prev_state.previous_justified_root - else: - assert state.previous_justified_epoch == prev_state.previous_justified_epoch - assert state.previous_justified_root == prev_state.previous_justified_root - - if finalized_changed: - assert state.finalized_epoch > prev_state.finalized_epoch - assert state.finalized_root != prev_state.finalized_root - else: - assert state.finalized_epoch == prev_state.finalized_epoch - assert state.finalized_root == prev_state.finalized_root - - def test_slot_transition(state): test_state = deepcopy(state) cache_state(test_state) diff --git a/tests/phase0/__init__.py b/tests/phase0/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/phase0/block_processing/test_process_block_header.py b/tests/phase0/block_processing/test_process_block_header.py deleted file mode 100644 index 241466437..000000000 --- a/tests/phase0/block_processing/test_process_block_header.py +++ /dev/null @@ -1,60 +0,0 @@ -from copy import deepcopy -import pytest - - -from build.phase0.spec import ( - get_beacon_proposer_index, - cache_state, - advance_slot, - process_block_header, -) -from tests.phase0.helpers import ( - build_empty_block_for_next_slot, -) - -# mark entire file as 'header' -pytestmark = pytest.mark.header - - -def prepare_state_for_header_processing(state): - cache_state(state) - advance_slot(state) - - -def run_block_header_processing(state, block, valid=True): - """ - Run ``process_block_header`` returning the pre and post state. - If ``valid == False``, run expecting ``AssertionError`` - """ - prepare_state_for_header_processing(state) - post_state = deepcopy(state) - - if not valid: - with pytest.raises(AssertionError): - process_block_header(post_state, block) - return state, None - - process_block_header(post_state, block) - return state, post_state - - -def test_success(state): - block = build_empty_block_for_next_slot(state) - pre_state, post_state = run_block_header_processing(state, block) - return state, block, post_state - - -def test_invalid_slot(state): - block = build_empty_block_for_next_slot(state) - block.slot = state.slot + 2 # invalid slot - - pre_state, post_state = run_block_header_processing(state, block, valid=False) - return pre_state, block, None - - -def test_invalid_previous_block_root(state): - block = build_empty_block_for_next_slot(state) - block.previous_block_root = b'\12'*32 # invalid prev root - - pre_state, post_state = run_block_header_processing(state, block, valid=False) - return pre_state, block, None diff --git a/tests/phase0/block_processing/test_process_deposit.py b/tests/phase0/block_processing/test_process_deposit.py deleted file mode 100644 index 0c5770195..000000000 --- a/tests/phase0/block_processing/test_process_deposit.py +++ /dev/null @@ -1,140 +0,0 @@ -from copy import deepcopy -import pytest - -import build.phase0.spec as spec - -from build.phase0.spec import ( - ZERO_HASH, - process_deposit, -) -from tests.phase0.helpers import ( - build_deposit, - privkeys, - pubkeys, -) - - -# mark entire file as 'voluntary_exits' -pytestmark = pytest.mark.voluntary_exits - - -def test_success(state): - pre_state = deepcopy(state) - # fill previous deposits with zero-hash - deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry) - - index = len(deposit_data_leaves) - pubkey = pubkeys[index] - privkey = privkeys[index] - deposit, root, deposit_data_leaves = build_deposit( - pre_state, - deposit_data_leaves, - pubkey, - privkey, - spec.MAX_DEPOSIT_AMOUNT, - ) - - pre_state.latest_eth1_data.deposit_root = root - pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves) - - post_state = deepcopy(pre_state) - - process_deposit(post_state, deposit) - - assert len(post_state.validator_registry) == len(state.validator_registry) + 1 - assert len(post_state.validator_balances) == len(state.validator_balances) + 1 - assert post_state.validator_registry[index].pubkey == pubkeys[index] - assert post_state.deposit_index == post_state.latest_eth1_data.deposit_count - - return pre_state, deposit, post_state - - -def test_success_top_up(state): - pre_state = deepcopy(state) - deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry) - - validator_index = 0 - amount = spec.MAX_DEPOSIT_AMOUNT // 4 - pubkey = pubkeys[validator_index] - privkey = privkeys[validator_index] - deposit, root, deposit_data_leaves = build_deposit( - pre_state, - deposit_data_leaves, - pubkey, - privkey, - amount, - ) - - pre_state.latest_eth1_data.deposit_root = root - pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves) - pre_balance = pre_state.validator_balances[validator_index] - - post_state = deepcopy(pre_state) - - process_deposit(post_state, deposit) - - assert len(post_state.validator_registry) == len(state.validator_registry) - assert len(post_state.validator_balances) == len(state.validator_balances) - assert post_state.deposit_index == post_state.latest_eth1_data.deposit_count - assert post_state.validator_balances[validator_index] == pre_balance + amount - - return pre_state, deposit, post_state - - -def test_wrong_index(state): - pre_state = deepcopy(state) - deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry) - - - index = len(deposit_data_leaves) - pubkey = pubkeys[index] - privkey = privkeys[index] - deposit, root, deposit_data_leaves = build_deposit( - pre_state, - deposit_data_leaves, - pubkey, - privkey, - spec.MAX_DEPOSIT_AMOUNT, - ) - - # mess up deposit_index - deposit.index = pre_state.deposit_index + 1 - - pre_state.latest_eth1_data.deposit_root = root - pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves) - - post_state = deepcopy(pre_state) - - with pytest.raises(AssertionError): - process_deposit(post_state, deposit) - - return pre_state, deposit, None - - -def test_bad_merkle_proof(state): - pre_state = deepcopy(state) - deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry) - - index = len(deposit_data_leaves) - pubkey = pubkeys[index] - privkey = privkeys[index] - deposit, root, deposit_data_leaves = build_deposit( - pre_state, - deposit_data_leaves, - pubkey, - privkey, - spec.MAX_DEPOSIT_AMOUNT, - ) - - # mess up merkle branch - deposit.proof[-1] = spec.ZERO_HASH - - pre_state.latest_eth1_data.deposit_root = root - pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves) - - post_state = deepcopy(pre_state) - - with pytest.raises(AssertionError): - process_deposit(post_state, deposit) - - return pre_state, deposit, None diff --git a/tests/phase0/block_processing/test_voluntary_exit.py b/tests/phase0/block_processing/test_voluntary_exit.py deleted file mode 100644 index 6adc81464..000000000 --- a/tests/phase0/block_processing/test_voluntary_exit.py +++ /dev/null @@ -1,175 +0,0 @@ -from copy import deepcopy -import pytest - -import build.phase0.spec as spec - -from build.phase0.spec import ( - get_active_validator_indices, - get_current_epoch, - process_voluntary_exit, -) -from tests.phase0.helpers import ( - build_voluntary_exit, - pubkey_to_privkey, -) - - -# mark entire file as 'voluntary_exits' -pytestmark = pytest.mark.voluntary_exits - - -def test_success(state): - pre_state = deepcopy(state) - # - # setup pre_state - # - # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow for exit - pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - - # - # build voluntary exit - # - current_epoch = get_current_epoch(pre_state) - validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] - privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey] - - voluntary_exit = build_voluntary_exit( - pre_state, - current_epoch, - validator_index, - privkey, - ) - - post_state = deepcopy(pre_state) - - # - # test valid exit - # - process_voluntary_exit(post_state, voluntary_exit) - - assert not pre_state.validator_registry[validator_index].initiated_exit - assert post_state.validator_registry[validator_index].initiated_exit - - return pre_state, voluntary_exit, post_state - - -def test_validator_not_active(state): - pre_state = deepcopy(state) - current_epoch = get_current_epoch(pre_state) - validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] - privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey] - - # - # setup pre_state - # - pre_state.validator_registry[validator_index].activation_epoch = spec.FAR_FUTURE_EPOCH - - # - # build and test voluntary exit - # - voluntary_exit = build_voluntary_exit( - pre_state, - current_epoch, - validator_index, - privkey, - ) - - with pytest.raises(AssertionError): - process_voluntary_exit(pre_state, voluntary_exit) - - return pre_state, voluntary_exit, None - - -def test_validator_already_exited(state): - pre_state = deepcopy(state) - # - # setup pre_state - # - # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow validator able to exit - pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - - current_epoch = get_current_epoch(pre_state) - validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] - privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey] - - # but validator already has exited - pre_state.validator_registry[validator_index].exit_epoch = current_epoch + 2 - - # - # build voluntary exit - # - voluntary_exit = build_voluntary_exit( - pre_state, - current_epoch, - validator_index, - privkey, - ) - - with pytest.raises(AssertionError): - process_voluntary_exit(pre_state, voluntary_exit) - - return pre_state, voluntary_exit, None - - -def test_validator_already_initiated_exit(state): - pre_state = deepcopy(state) - # - # setup pre_state - # - # move state forward PERSISTENT_COMMITTEE_PERIOD epochs to allow validator able to exit - pre_state.slot += spec.PERSISTENT_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - - current_epoch = get_current_epoch(pre_state) - validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] - privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey] - - # but validator already has initiated exit - pre_state.validator_registry[validator_index].initiated_exit = True - - # - # build voluntary exit - # - voluntary_exit = build_voluntary_exit( - pre_state, - current_epoch, - validator_index, - privkey, - ) - - with pytest.raises(AssertionError): - process_voluntary_exit(pre_state, voluntary_exit) - - return pre_state, voluntary_exit, None - - -def test_validator_not_active_long_enough(state): - pre_state = deepcopy(state) - # - # setup pre_state - # - current_epoch = get_current_epoch(pre_state) - validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] - privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey] - - # but validator already has initiated exit - pre_state.validator_registry[validator_index].initiated_exit = True - - # - # build voluntary exit - # - voluntary_exit = build_voluntary_exit( - pre_state, - current_epoch, - validator_index, - privkey, - ) - - assert ( - current_epoch - pre_state.validator_registry[validator_index].activation_epoch < - spec.PERSISTENT_COMMITTEE_PERIOD - ) - - with pytest.raises(AssertionError): - process_voluntary_exit(pre_state, voluntary_exit) - - return pre_state, voluntary_exit, None diff --git a/tests/phase0/helpers.py b/tests/phase0/helpers.py deleted file mode 100644 index 20054b821..000000000 --- a/tests/phase0/helpers.py +++ /dev/null @@ -1,203 +0,0 @@ -from copy import deepcopy - -from py_ecc import bls - -import build.phase0.spec as spec -from build.phase0.utils.minimal_ssz import signed_root -from build.phase0.spec import ( - # constants - EMPTY_SIGNATURE, - # SSZ - AttestationData, - Deposit, - DepositInput, - DepositData, - Eth1Data, - VoluntaryExit, - # functions - get_block_root, - get_current_epoch, - get_domain, - get_empty_block, - get_epoch_start_slot, - get_genesis_beacon_state, - verify_merkle_branch, - hash, -) -from build.phase0.utils.merkle_minimal import ( - calc_merkle_tree_from_leaves, - get_merkle_proof, - get_merkle_root, -) - - -privkeys = [i + 1 for i in range(1000)] -pubkeys = [bls.privtopub(privkey) for privkey in privkeys] -pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)} - - -def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves=None): - if not deposit_data_leaves: - deposit_data_leaves = [] - deposit_timestamp = 0 - proof_of_possession = b'\x33' * 96 - - deposit_data_list = [] - for i in range(num_validators): - pubkey = pubkeys[i] - deposit_data = DepositData( - amount=spec.MAX_DEPOSIT_AMOUNT, - timestamp=deposit_timestamp, - deposit_input=DepositInput( - pubkey=pubkey, - # insecurely use pubkey as withdrawal key as well - withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(pubkey)[1:], - proof_of_possession=proof_of_possession, - ), - ) - item = hash(deposit_data.serialize()) - 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=i)) - assert verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, i, root) - deposit_data_list.append(deposit_data) - - genesis_validator_deposits = [] - for i in range(num_validators): - genesis_validator_deposits.append(Deposit( - proof=list(get_merkle_proof(tree, item_index=i)), - index=i, - deposit_data=deposit_data_list[i] - )) - return genesis_validator_deposits, root - - -def create_genesis_state(num_validators, deposit_data_leaves=None): - initial_deposits, deposit_root = create_mock_genesis_validator_deposits( - num_validators, - deposit_data_leaves, - ) - return get_genesis_beacon_state( - initial_deposits, - genesis_time=0, - genesis_eth1_data=Eth1Data( - deposit_root=deposit_root, - deposit_count=len(initial_deposits), - block_hash=spec.ZERO_HASH, - ), - ) - - -def force_registry_change_at_next_epoch(state): - # artificially trigger registry update at next epoch transition - state.finalized_epoch = get_current_epoch(state) - 1 - for crosslink in state.latest_crosslinks: - crosslink.epoch = state.finalized_epoch - state.validator_registry_update_epoch = state.finalized_epoch - 1 - - -def build_empty_block_for_next_slot(state): - empty_block = get_empty_block() - empty_block.slot = state.slot + 1 - previous_block_header = deepcopy(state.latest_block_header) - if previous_block_header.state_root == spec.ZERO_HASH: - previous_block_header.state_root = state.hash_tree_root() - empty_block.previous_block_root = signed_root(previous_block_header) - return empty_block - - -def build_deposit_data(state, pubkey, privkey, amount): - deposit_input = DepositInput( - pubkey=pubkey, - # insecurely use pubkey as withdrawal key as well - withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(pubkey)[1:], - proof_of_possession=EMPTY_SIGNATURE, - ) - proof_of_possession = bls.sign( - message_hash=signed_root(deposit_input), - privkey=privkey, - domain=get_domain( - state.fork, - get_current_epoch(state), - spec.DOMAIN_DEPOSIT, - ) - ) - deposit_input.proof_of_possession = proof_of_possession - deposit_data = DepositData( - amount=amount, - timestamp=0, - deposit_input=deposit_input, - ) - return deposit_data - - -def build_attestation_data(state, slot, shard): - assert state.slot >= slot - - block_root = build_empty_block_for_next_slot(state).previous_block_root - - epoch_start_slot = get_epoch_start_slot(get_current_epoch(state)) - if epoch_start_slot == slot: - epoch_boundary_root = block_root - else: - get_block_root(state, epoch_start_slot) - - if slot < epoch_start_slot: - justified_block_root = state.previous_justified_root - else: - justified_block_root = state.current_justified_root - - return AttestationData( - slot=slot, - shard=shard, - beacon_block_root=block_root, - source_epoch=state.current_justified_epoch, - source_root=justified_block_root, - target_root=epoch_boundary_root, - crosslink_data_root=spec.ZERO_HASH, - previous_crosslink=deepcopy(state.latest_crosslinks[shard]), - ) - - -def build_voluntary_exit(state, epoch, validator_index, privkey): - voluntary_exit = VoluntaryExit( - epoch=epoch, - validator_index=validator_index, - signature=EMPTY_SIGNATURE, - ) - voluntary_exit.signature = bls.sign( - message_hash=signed_root(voluntary_exit), - privkey=privkey, - domain=get_domain( - fork=state.fork, - epoch=epoch, - domain_type=spec.DOMAIN_VOLUNTARY_EXIT, - ) - ) - - return voluntary_exit - - -def build_deposit(state, - deposit_data_leaves, - pubkey, - privkey, - amount): - deposit_data = build_deposit_data(state, pubkey, privkey, amount) - - item = hash(deposit_data.serialize()) - 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 verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, index, root) - - deposit = Deposit( - proof=list(proof), - index=index, - deposit_data=deposit_data, - ) - - return deposit, root, deposit_data_leaves From 53eb2d0368cd4df7692250bce88376655e956d43 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Tue, 23 Apr 2019 13:38:35 -0600 Subject: [PATCH 4/7] remove jsonize --- utils/phase0/jsonize.py | 52 ----------------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 utils/phase0/jsonize.py diff --git a/utils/phase0/jsonize.py b/utils/phase0/jsonize.py deleted file mode 100644 index 816192ec6..000000000 --- a/utils/phase0/jsonize.py +++ /dev/null @@ -1,52 +0,0 @@ -from .minimal_ssz import hash_tree_root - - -def jsonize(value, typ, include_hash_tree_roots=False): - if isinstance(typ, str) and typ[:4] == 'uint': - return value - elif typ == 'bool': - assert value in (True, False) - return value - elif isinstance(typ, list): - return [jsonize(element, typ[0], include_hash_tree_roots) for element in value] - elif isinstance(typ, str) and typ[:4] == 'byte': - return '0x' + value.hex() - elif hasattr(typ, 'fields'): - ret = {} - for field, subtype in typ.fields.items(): - ret[field] = jsonize(getattr(value, field), subtype, include_hash_tree_roots) - if include_hash_tree_roots: - ret[field + "_hash_tree_root"] = '0x' + hash_tree_root(getattr(value, field), subtype).hex() - if include_hash_tree_roots: - ret["hash_tree_root"] = '0x' + hash_tree_root(value, typ).hex() - return ret - else: - print(value, typ) - raise Exception("Type not recognized") - - -def dejsonize(json, typ): - if isinstance(typ, str) and typ[:4] == 'uint': - return json - elif typ == 'bool': - assert json in (True, False) - return json - elif isinstance(typ, list): - return [dejsonize(element, typ[0]) for element in json] - elif isinstance(typ, str) and typ[:4] == 'byte': - return bytes.fromhex(json[2:]) - elif hasattr(typ, 'fields'): - temp = {} - for field, subtype in typ.fields.items(): - temp[field] = dejsonize(json[field], subtype) - if field + "_hash_tree_root" in json: - assert(json[field + "_hash_tree_root"][2:] == - hash_tree_root(temp[field], subtype).hex()) - ret = typ(**temp) - if "hash_tree_root" in json: - assert(json["hash_tree_root"][2:] == - hash_tree_root(ret, typ).hex()) - return ret - else: - print(json, typ) - raise Exception("Type not recognized") From 7f720133fab5248623333f08864deb1ac4b432b7 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Wed, 24 Apr 2019 11:38:26 -0600 Subject: [PATCH 5/7] Apply suggestions from code review Co-Authored-By: djrtwo --- test_libs/pyspec/tests/test_finality.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_libs/pyspec/tests/test_finality.py b/test_libs/pyspec/tests/test_finality.py index 8c1b4e871..4aee1c538 100644 --- a/test_libs/pyspec/tests/test_finality.py +++ b/test_libs/pyspec/tests/test_finality.py @@ -77,7 +77,7 @@ def test_finality_from_genesis_rule_4(state): test_state = deepcopy(state) blocks = [] - for epoch in range(6): + for epoch in range(4): prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) blocks += new_blocks @@ -88,7 +88,7 @@ def test_finality_from_genesis_rule_4(state): elif epoch == 2: check_finality(test_state, prev_state, True, False, False) elif epoch >= 3: - # rule 4 of finaliy + # rule 4 of finality check_finality(test_state, prev_state, True, True, True) assert test_state.finalized_epoch == prev_state.current_justified_epoch assert test_state.finalized_root == prev_state.current_justified_root @@ -137,10 +137,10 @@ def test_finality_rule_2(state): if epoch == 0: prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) check_finality(test_state, prev_state, True, False, False) - if epoch == 1: + elif epoch == 1: prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, False) check_finality(test_state, prev_state, False, True, False) - if epoch == 2: + elif epoch == 2: prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, True) # finalized by rule 2 check_finality(test_state, prev_state, True, False, True) From 9e8a9a26fd787550710531a3b9045e2f18cd5860 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 24 Apr 2019 11:44:03 -0600 Subject: [PATCH 6/7] PR feedback --- test_libs/pyspec/tests/test_finality.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/test_libs/pyspec/tests/test_finality.py b/test_libs/pyspec/tests/test_finality.py index 4aee1c538..9992d2a78 100644 --- a/test_libs/pyspec/tests/test_finality.py +++ b/test_libs/pyspec/tests/test_finality.py @@ -73,7 +73,7 @@ def next_epoch_with_attestations(state, return state, blocks, post_state -def test_finality_from_genesis_rule_4(state): +def test_finality_rule_4(state): test_state = deepcopy(state) blocks = [] @@ -81,8 +81,10 @@ def test_finality_from_genesis_rule_4(state): prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) blocks += new_blocks + # justification/finalization skipped at GENESIS_EPOCH if epoch == 0: check_finality(test_state, prev_state, False, False, False) + # justification/finalization skipped at GENESIS_EPOCH + 1 elif epoch == 1: check_finality(test_state, prev_state, False, False, False) elif epoch == 2: @@ -132,8 +134,6 @@ def test_finality_rule_2(state): blocks = [] for epoch in range(3): - old_previous_justified_epoch = test_state.previous_justified_epoch - old_previous_justified_root = test_state.previous_justified_root if epoch == 0: prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) check_finality(test_state, prev_state, True, False, False) @@ -144,8 +144,8 @@ def test_finality_rule_2(state): prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, True) # finalized by rule 2 check_finality(test_state, prev_state, True, False, True) - assert test_state.finalized_epoch == old_previous_justified_epoch - assert test_state.finalized_root == old_previous_justified_root + assert test_state.finalized_epoch == prev_state.previous_justified_epoch + assert test_state.finalized_root == prev_state.previous_justified_root blocks += new_blocks @@ -170,19 +170,24 @@ def test_finality_rule_3(state): blocks += new_blocks check_finality(test_state, prev_state, True, False, False) + # In epoch N, JE is set to N, prev JE is set to N-1 prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, False) blocks += new_blocks check_finality(test_state, prev_state, True, True, True) + # In epoch N+1, JE is N, prev JE is N-1, and not enough messages get in to do anything prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, False) blocks += new_blocks check_finality(test_state, prev_state, False, True, False) + # In epoch N+2, JE is N, prev JE is N, and enough messages from the previous epoch get in to justify N+1. + # N+1 now becomes the JE. Not enough messages from epoch N+2 itself get in to justify N+2 prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, False, True) blocks += new_blocks # rule 2 check_finality(test_state, prev_state, True, False, True) + # In epoch N+3, LJE is N+1, prev LJE is N, and enough messages get in to justify epochs N+2 and N+3. prev_state, new_blocks, test_state = next_epoch_with_attestations(test_state, True, True) blocks += new_blocks # rule 3 From 53b06745330e1b44586008bd9e5cfbe4f51ccea1 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Wed, 24 Apr 2019 11:45:41 -0600 Subject: [PATCH 7/7] remove unnecessary var --- test_libs/pyspec/tests/test_finality.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_libs/pyspec/tests/test_finality.py b/test_libs/pyspec/tests/test_finality.py index 9992d2a78..ca048c2b2 100644 --- a/test_libs/pyspec/tests/test_finality.py +++ b/test_libs/pyspec/tests/test_finality.py @@ -52,7 +52,7 @@ def next_epoch_with_attestations(state, fill_prev_epoch): post_state = deepcopy(state) blocks = [] - for slot in range(spec.SLOTS_PER_EPOCH): + for _ in range(spec.SLOTS_PER_EPOCH): block = build_empty_block_for_next_slot(post_state) if fill_cur_epoch: slot_to_attest = post_state.slot - spec.MIN_ATTESTATION_INCLUSION_DELAY + 1