From b94af435dab7c97e137f83bbfb99d824159b5f81 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 5 Jan 2021 12:38:50 -0800 Subject: [PATCH 01/12] Refactor helpers into separate module --- .../test/lightclient_patch/__init__.py | 0 .../test/lightclient_patch/helpers.py | 33 +++++++++++++++++++ .../lightclient_patch/sanity/test_blocks.py | 33 ++----------------- 3 files changed, 36 insertions(+), 30 deletions(-) create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/helpers.py diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/__init__.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/helpers.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/helpers.py new file mode 100644 index 000000000..b7b2381e3 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/helpers.py @@ -0,0 +1,33 @@ +from eth2spec.test.helpers.keys import privkeys +from eth2spec.test.helpers.block import ( + build_empty_block_for_next_slot, +) +from eth2spec.utils import bls + + +def compute_sync_committee_signature(spec, state, slot, privkey): + domain = spec.get_domain(state, spec.DOMAIN_SYNC_COMMITTEE, spec.compute_epoch_at_slot(slot)) + if slot == state.slot: + block_root = build_empty_block_for_next_slot(spec, state).parent_root + else: + block_root = spec.get_block_root_at_slot(state, slot) + signing_root = spec.compute_signing_root(block_root, domain) + return bls.Sign(privkey, signing_root) + + +def compute_aggregate_sync_committee_signature(spec, state, slot, participants): + if len(participants) == 0: + return spec.G2_POINT_AT_INFINITY + + signatures = [] + for validator_index in participants: + privkey = privkeys[validator_index] + signatures.append( + compute_sync_committee_signature( + spec, + state, + slot, + privkey, + ) + ) + return bls.Aggregate(signatures) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py index 4fbdfc371..1698ecce1 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py @@ -1,6 +1,4 @@ import random -from eth2spec.test.helpers.keys import privkeys -from eth2spec.utils import bls from eth2spec.test.helpers.state import ( state_transition_and_sign_block, next_epoch, @@ -8,6 +6,9 @@ from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, ) +from eth2spec.test.lightclient_patch.helpers import ( + compute_aggregate_sync_committee_signature, +) from eth2spec.test.context import ( PHASE0, PHASE1, with_all_phases_except, @@ -15,34 +16,6 @@ from eth2spec.test.context import ( ) -def compute_sync_committee_signature(spec, state, slot, privkey): - domain = spec.get_domain(state, spec.DOMAIN_SYNC_COMMITTEE, spec.compute_epoch_at_slot(slot)) - if slot == state.slot: - block_root = build_empty_block_for_next_slot(spec, state).parent_root - else: - block_root = spec.get_block_root_at_slot(state, slot) - signing_root = spec.compute_signing_root(block_root, domain) - return bls.Sign(privkey, signing_root) - - -def compute_aggregate_sync_committee_signature(spec, state, slot, participants): - if len(participants) == 0: - return spec.G2_POINT_AT_INFINITY - - signatures = [] - for validator_index in participants: - privkey = privkeys[validator_index] - signatures.append( - compute_sync_committee_signature( - spec, - state, - slot, - privkey, - ) - ) - return bls.Aggregate(signatures) - - def run_sync_committee_sanity_test(spec, state, fraction_full=1.0): committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) participants = random.sample(committee, int(len(committee) * fraction_full)) From 955a01c49bc816642523ce772210bae5dcbe8b08 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 5 Jan 2021 12:39:13 -0800 Subject: [PATCH 02/12] Add basic test for invalid sync committee bits --- .../block_processing/__init__.py | 0 .../test_process_sync_committee.py | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/__init__.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py new file mode 100644 index 000000000..578c1a1c6 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -0,0 +1,36 @@ +import random +from eth2spec.test.helpers.block import ( + build_empty_block_for_next_slot, +) +from eth2spec.test.lightclient_patch.helpers import ( + compute_aggregate_sync_committee_signature, +) +from eth2spec.test.context import ( + PHASE0, PHASE1, + expect_assertion_error, + with_all_phases_except, + spec_state_test, +) + + +@with_all_phases_except([PHASE0, PHASE1]) +@spec_state_test +def test_invalid_sync_committee_bits(spec, state): + committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) + random_participant = random.choice(committee) + + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + # Exclude one participant whose signature was included. + block.body.sync_committee_bits = [index != random_participant for index in committee] + block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + committee, + ) + + yield 'blocks', [block] + expect_assertion_error(lambda: spec.process_sync_committee(state, block.body)) + yield 'post', None From 781f3444098eceda820436d440228a60af6751eb Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 5 Jan 2021 15:18:56 -0800 Subject: [PATCH 03/12] Add test for invalid sync committee signature --- .../test_process_sync_committee.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index 578c1a1c6..90d4af3cc 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -34,3 +34,26 @@ def test_invalid_sync_committee_bits(spec, state): yield 'blocks', [block] expect_assertion_error(lambda: spec.process_sync_committee(state, block.body)) yield 'post', None + + +@with_all_phases_except([PHASE0, PHASE1]) +@spec_state_test +def test_invalid_sync_committee_signature(spec, state): + committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) + random_participant = random.choice(committee) + + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + # Exclude one signature even though the block claims the entire committee participated. + block.body.sync_committee_bits = [True] * len(committee) + block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + [index for index in committee if index != random_participant], + ) + + yield 'blocks', [block] + expect_assertion_error(lambda: spec.process_sync_committee(state, block.body)) + yield 'post', None From 547cb0f38f78e490760e544ac549feb0c48bd622 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 5 Jan 2021 17:04:40 -0800 Subject: [PATCH 04/12] Add epoch processing test for sync committee updates --- .../epoch_processing/__init__.py | 0 .../test_process_final_updates.py | 37 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/__init__.py create mode 100644 tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/__init__.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py new file mode 100644 index 000000000..227b2461d --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py @@ -0,0 +1,37 @@ +from eth2spec.test.context import ( + PHASE0, PHASE1, + with_all_phases_except, + spec_state_test, +) +from eth2spec.test.helpers.state import transition_to +from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import ( + run_epoch_processing_with, +) + + +@with_all_phases_except([PHASE0, PHASE1]) +@spec_state_test +def test_sync_committees_progress(spec, state): + current_epoch = spec.get_current_epoch(state) + # NOTE: if not in the genesis epoch, period math below needs to be + # adjusted relative to the current epoch + assert current_epoch == 0 + + first_sync_committee = state.current_sync_committee + second_sync_committee = state.next_sync_committee + + slot_at_end_of_current_period = spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH - 1 + transition_to(spec, state, slot_at_end_of_current_period) + + # Ensure assignments have not changed: + assert state.current_sync_committee == first_sync_committee + assert state.next_sync_committee == second_sync_committee + + yield from run_epoch_processing_with(spec, state, 'process_final_updates') + + # Can compute the third committee having computed final balances in the last epoch + # of this `EPOCHS_PER_SYNC_COMMITTEE_PERIOD` + third_sync_committee = spec.get_sync_committee(state, 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD) + + assert state.current_sync_committee == second_sync_committee + assert state.next_sync_committee == third_sync_committee From cc7ae4abd0551f72c22b0493755f41a2349a4563 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Wed, 6 Jan 2021 09:44:17 -0800 Subject: [PATCH 05/12] Add test for sync committee block rewards --- .../test_process_sync_committee.py | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index 90d4af3cc..1a3b41fa4 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -2,6 +2,9 @@ import random from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, ) +from eth2spec.test.helpers.state import ( + state_transition_and_sign_block, +) from eth2spec.test.lightclient_patch.helpers import ( compute_aggregate_sync_committee_signature, ) @@ -57,3 +60,53 @@ def test_invalid_sync_committee_signature(spec, state): yield 'blocks', [block] expect_assertion_error(lambda: spec.process_sync_committee(state, block.body)) yield 'post', None + + +def compute_sync_committee_participant_reward(spec, state, participant_index, active_validator_count, committee_size): + base_reward = spec.get_base_reward(state, participant_index) + proposer_reward = spec.get_proposer_reward(state, participant_index) + max_participant_reward = base_reward - proposer_reward + return max_participant_reward * active_validator_count // committee_size // spec.SLOTS_PER_EPOCH + + +@with_all_phases_except([PHASE0, PHASE1]) +@spec_state_test +def test_sync_committee_rewards(spec, state): + committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) + committee_size = len(committee) + active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) + + yield 'pre', state + + pre_balances = state.balances.copy() + + block = build_empty_block_for_next_slot(spec, state) + block.body.sync_committee_bits = [True] * committee_size + block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + committee, + ) + + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state + + for index in range(len(state.validators)): + expected_reward = 0 + + if index == block.proposer_index: + expected_reward += sum([spec.get_proposer_reward(state, index) for index in committee]) + + if index in committee: + expected_reward += compute_sync_committee_participant_reward( + spec, + state, + index, + active_validator_count, + committee_size + ) + + assert state.balances[index] == pre_balances[index] + expected_reward From 7e82b54131ad2252c0b8749128297da1b1633753 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 7 Jan 2021 09:45:20 -0800 Subject: [PATCH 06/12] Update tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py Add clarifying comment Co-authored-by: Danny Ryan --- .../block_processing/test_process_sync_committee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index 1a3b41fa4..a4e31335a 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -31,7 +31,7 @@ def test_invalid_sync_committee_bits(spec, state): spec, state, block.slot - 1, - committee, + committee, # full committee signs ) yield 'blocks', [block] From 049075b44a3bd7d2ebc363d29ecddf471b03ef3a Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 7 Jan 2021 10:42:21 -0800 Subject: [PATCH 07/12] Refactor sync committee helpers --- .../{lightclient_patch/helpers.py => helpers/sync_committee.py} | 0 .../block_processing/test_process_sync_committee.py | 2 +- .../eth2spec/test/lightclient_patch/sanity/test_blocks.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/core/pyspec/eth2spec/test/{lightclient_patch/helpers.py => helpers/sync_committee.py} (100%) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/helpers.py b/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/lightclient_patch/helpers.py rename to tests/core/pyspec/eth2spec/test/helpers/sync_committee.py diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index a4e31335a..f29d1ef2b 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -5,7 +5,7 @@ from eth2spec.test.helpers.block import ( from eth2spec.test.helpers.state import ( state_transition_and_sign_block, ) -from eth2spec.test.lightclient_patch.helpers import ( +from eth2spec.test.helpers.sync_committee import ( compute_aggregate_sync_committee_signature, ) from eth2spec.test.context import ( diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py index 1698ecce1..9033a0f15 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/sanity/test_blocks.py @@ -6,7 +6,7 @@ from eth2spec.test.helpers.state import ( from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, ) -from eth2spec.test.lightclient_patch.helpers import ( +from eth2spec.test.helpers.sync_committee import ( compute_aggregate_sync_committee_signature, ) from eth2spec.test.context import ( From 1a3fefcc931d6961a099e30afa5f8d282fc2c4eb Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 7 Jan 2021 10:55:51 -0800 Subject: [PATCH 08/12] Refactor epoch processing test helpers --- .../run_epoch_process_base.py => helpers/epoch_processing.py} | 0 .../epoch_processing/test_process_final_updates.py | 2 +- .../test/phase0/epoch_processing/test_process_final_updates.py | 2 +- .../test_process_justification_and_finalization.py | 2 +- .../phase0/epoch_processing/test_process_registry_updates.py | 2 +- .../epoch_processing/test_process_rewards_and_penalties.py | 2 +- .../test/phase0/epoch_processing/test_process_slashings.py | 2 +- .../phase1/epoch_processing/test_process_challenge_deadlines.py | 2 +- .../epoch_processing/test_process_custody_final_updates.py | 2 +- .../phase1/epoch_processing/test_process_reveal_deadlines.py | 2 +- 10 files changed, 9 insertions(+), 9 deletions(-) rename tests/core/pyspec/eth2spec/test/{phase0/epoch_processing/run_epoch_process_base.py => helpers/epoch_processing.py} (100%) diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/run_epoch_process_base.py b/tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py similarity index 100% rename from tests/core/pyspec/eth2spec/test/phase0/epoch_processing/run_epoch_process_base.py rename to tests/core/pyspec/eth2spec/test/helpers/epoch_processing.py diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py index 227b2461d..012438cd8 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/epoch_processing/test_process_final_updates.py @@ -4,7 +4,7 @@ from eth2spec.test.context import ( spec_state_test, ) from eth2spec.test.helpers.state import transition_to -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import ( +from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_with, ) diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_final_updates.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_final_updates.py index 27676a59a..f9b5c872b 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_final_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_final_updates.py @@ -1,5 +1,5 @@ from eth2spec.test.context import spec_state_test, with_all_phases -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import ( +from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_with, run_epoch_processing_to ) from eth2spec.test.helpers.state import transition_to diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py index f8504fc4f..921289f5b 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_justification_and_finalization.py @@ -1,5 +1,5 @@ from eth2spec.test.context import spec_state_test, with_all_phases -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import ( +from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_with ) from eth2spec.test.helpers.state import transition_to diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py index c734010f3..ee40984a6 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_registry_updates.py @@ -1,7 +1,7 @@ from eth2spec.test.helpers.deposits import mock_deposit from eth2spec.test.helpers.state import next_epoch, next_slots from eth2spec.test.context import spec_state_test, with_all_phases -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import run_epoch_processing_with +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with def run_process_registry_updates(spec, state): diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py index dd3cbb791..8560b66a8 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_rewards_and_penalties.py @@ -19,7 +19,7 @@ from eth2spec.test.helpers.attestations import ( ) from eth2spec.test.helpers.rewards import leaking from eth2spec.test.helpers.attester_slashings import get_indexed_attestation_participants -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import run_epoch_processing_with +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with from random import Random diff --git a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py index 3e96f8b58..2e09f5c8a 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py +++ b/tests/core/pyspec/eth2spec/test/phase0/epoch_processing/test_process_slashings.py @@ -1,5 +1,5 @@ from eth2spec.test.context import spec_state_test, with_all_phases -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import ( +from eth2spec.test.helpers.epoch_processing import ( run_epoch_processing_with, run_epoch_processing_to ) from eth2spec.test.helpers.state import next_epoch diff --git a/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_challenge_deadlines.py b/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_challenge_deadlines.py index 0350324a5..1d8adecbc 100644 --- a/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_challenge_deadlines.py +++ b/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_challenge_deadlines.py @@ -15,7 +15,7 @@ from eth2spec.test.context import ( with_configs, ) from eth2spec.test.phase0.block_processing.test_process_attestation import run_attestation_processing -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import run_epoch_processing_with +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with from eth2spec.test.phase1.block_processing.test_process_chunk_challenge import ( run_chunk_challenge_processing, diff --git a/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_custody_final_updates.py b/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_custody_final_updates.py index 5994306d9..82ecde7ab 100644 --- a/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_custody_final_updates.py +++ b/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_custody_final_updates.py @@ -17,7 +17,7 @@ from eth2spec.test.context import ( spec_state_test, ) from eth2spec.test.phase0.block_processing.test_process_attestation import run_attestation_processing -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import run_epoch_processing_with +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with from eth2spec.test.phase1.block_processing.test_process_chunk_challenge import ( run_chunk_challenge_processing, diff --git a/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_reveal_deadlines.py b/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_reveal_deadlines.py index 3c2060ba5..b95082491 100644 --- a/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_reveal_deadlines.py +++ b/tests/core/pyspec/eth2spec/test/phase1/epoch_processing/test_process_reveal_deadlines.py @@ -10,7 +10,7 @@ from eth2spec.test.context import ( with_configs, spec_state_test, ) -from eth2spec.test.phase0.epoch_processing.run_epoch_process_base import run_epoch_processing_with +from eth2spec.test.helpers.epoch_processing import run_epoch_processing_with from eth2spec.test.phase1.block_processing.test_process_custody_key_reveal import run_custody_key_reveal_processing From 61d141b4db8978d6e3b825b6f7ccdc37ea559ab6 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 7 Jan 2021 10:57:54 -0800 Subject: [PATCH 09/12] Use more clear names for tests --- .../block_processing/test_process_sync_committee.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index f29d1ef2b..e36500918 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -18,7 +18,7 @@ from eth2spec.test.context import ( @with_all_phases_except([PHASE0, PHASE1]) @spec_state_test -def test_invalid_sync_committee_bits(spec, state): +def test_invalid_signature_missing_participant(spec, state): committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) random_participant = random.choice(committee) @@ -31,7 +31,7 @@ def test_invalid_sync_committee_bits(spec, state): spec, state, block.slot - 1, - committee, # full committee signs + committee, # full committee signs ) yield 'blocks', [block] @@ -41,7 +41,7 @@ def test_invalid_sync_committee_bits(spec, state): @with_all_phases_except([PHASE0, PHASE1]) @spec_state_test -def test_invalid_sync_committee_signature(spec, state): +def test_invalid_signature_extra_participant(spec, state): committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) random_participant = random.choice(committee) From ac6dbd1c3531c24cd2d0f07d3a5cda180ca26dbb Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 7 Jan 2021 11:28:21 -0800 Subject: [PATCH 10/12] Add sync committee test for signature over incorrect block --- .../test_process_sync_committee.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index e36500918..5f49e2131 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -1,6 +1,7 @@ import random from eth2spec.test.helpers.block import ( build_empty_block_for_next_slot, + transition_unsigned_block, ) from eth2spec.test.helpers.state import ( state_transition_and_sign_block, @@ -110,3 +111,42 @@ def test_sync_committee_rewards(spec, state): ) assert state.balances[index] == pre_balances[index] + expected_reward + +@with_all_phases_except([PHASE0, PHASE1]) +@spec_state_test +def test_invalid_signature_past_block(spec, state): + committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) + + yield 'pre', state + + blocks = [] + for _ in range(2): + # NOTE: need to transition twice to move beyond the degenerate case at genesis + block = build_empty_block_for_next_slot(spec, state) + # Valid sync committee signature here... + block.body.sync_committee_bits = [True] * len(committee) + block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + committee, + ) + + signed_block = state_transition_and_sign_block(spec, state, block) + blocks.append(signed_block) + + invalid_block = build_empty_block_for_next_slot(spec, state) + # Invalid signature from a slot other than the previous + invalid_block.body.sync_committee_bits = [True] * len(committee) + invalid_block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( + spec, + state, + invalid_block.slot - 2, + committee, + ) + blocks.append(invalid_block) + + expect_assertion_error(lambda: transition_unsigned_block(spec, state, invalid_block)) + + yield 'blocks', blocks + yield 'post', None From 500158828502bafb980a48ade5285d384bd9a183 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 7 Jan 2021 12:27:24 -0800 Subject: [PATCH 11/12] Add additional sync committee tests --- .../test_process_sync_committee.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index 5f49e2131..522e248fb 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -5,6 +5,7 @@ from eth2spec.test.helpers.block import ( ) from eth2spec.test.helpers.state import ( state_transition_and_sign_block, + transition_to, ) from eth2spec.test.helpers.sync_committee import ( compute_aggregate_sync_committee_signature, @@ -112,6 +113,7 @@ def test_sync_committee_rewards(spec, state): assert state.balances[index] == pre_balances[index] + expected_reward + @with_all_phases_except([PHASE0, PHASE1]) @spec_state_test def test_invalid_signature_past_block(spec, state): @@ -150,3 +152,68 @@ def test_invalid_signature_past_block(spec, state): yield 'blocks', blocks yield 'post', None + + +@with_all_phases_except([PHASE0, PHASE1]) +@spec_state_test +def test_invalid_signature_previous_committee(spec, state): + # NOTE: the `state` provided is at genesis and the process to select + # sync committees currently returns the same committee for the first and second + # periods at genesis. + # To get a distinct committee so we can generate an "old" signature, we need to advance + # 2 EPOCHS_PER_SYNC_COMMITTEE_PERIOD periods. + current_epoch = spec.get_current_epoch(state) + previous_committee = state.next_sync_committee + + epoch_in_future_sync_commitee_period = current_epoch + 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD + slot_in_future_sync_committee_period = epoch_in_future_sync_commitee_period * spec.SLOTS_PER_EPOCH + transition_to(spec, state, slot_in_future_sync_committee_period) + + pubkeys = [validator.pubkey for validator in state.validators] + committee = [pubkeys.index(pubkey) for pubkey in previous_committee.pubkeys] + + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + block.body.sync_committee_bits = [True] * len(committee) + block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + committee, + ) + + yield 'blocks', [block] + expect_assertion_error(lambda: spec.process_sync_committee(state, block.body)) + yield 'post', None + + +@with_all_phases_except([PHASE0, PHASE1]) +@spec_state_test +def test_valid_signature_next_committee(spec, state): + current_epoch = spec.get_current_epoch(state) + next_committee = state.next_sync_committee + epoch_in_next_sync_committee_period = current_epoch + spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD + slot_in_next_sync_committee_period = epoch_in_next_sync_committee_period * spec.SLOTS_PER_EPOCH + transition_to(spec, state, slot_in_next_sync_committee_period) + + assert state.current_sync_committee == next_committee + + pubkeys = [validator.pubkey for validator in state.validators] + committee = [pubkeys.index(pubkey) for pubkey in next_committee.pubkeys] + + yield 'pre', state + + block = build_empty_block_for_next_slot(spec, state) + block.body.sync_committee_bits = [True] * len(committee) + block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + committee, + ) + + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state From e518c4d04d1fb741d4b22a71d48a6f4b38582b6d Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 12 Jan 2021 09:31:07 -0800 Subject: [PATCH 12/12] update test to use fresh sync committees the way the test infra is built we end up with two identical sync committees at epoch 0. --- .../test_process_sync_committee.py | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py index 522e248fb..37cd0992b 100644 --- a/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/lightclient_patch/block_processing/test_process_sync_committee.py @@ -190,27 +190,40 @@ def test_invalid_signature_previous_committee(spec, state): @with_all_phases_except([PHASE0, PHASE1]) @spec_state_test -def test_valid_signature_next_committee(spec, state): +def test_valid_signature_future_committee(spec, state): + # NOTE: the `state` provided is at genesis and the process to select + # sync committees currently returns the same committee for the first and second + # periods at genesis. + # To get a distinct committee so we can generate an "old" signature, we need to advance + # 2 EPOCHS_PER_SYNC_COMMITTEE_PERIOD periods. current_epoch = spec.get_current_epoch(state) - next_committee = state.next_sync_committee - epoch_in_next_sync_committee_period = current_epoch + spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD - slot_in_next_sync_committee_period = epoch_in_next_sync_committee_period * spec.SLOTS_PER_EPOCH - transition_to(spec, state, slot_in_next_sync_committee_period) + old_current_sync_committee = state.current_sync_committee + old_next_sync_committee = state.next_sync_committee - assert state.current_sync_committee == next_committee + epoch_in_future_sync_committee_period = current_epoch + 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD + slot_in_future_sync_committee_period = epoch_in_future_sync_committee_period * spec.SLOTS_PER_EPOCH + transition_to(spec, state, slot_in_future_sync_committee_period) + + sync_committee = state.current_sync_committee + + expected_sync_committee = spec.get_sync_committee(state, epoch_in_future_sync_committee_period) + + assert sync_committee == expected_sync_committee + assert sync_committee != old_current_sync_committee + assert sync_committee != old_next_sync_committee pubkeys = [validator.pubkey for validator in state.validators] - committee = [pubkeys.index(pubkey) for pubkey in next_committee.pubkeys] + committee_indices = [pubkeys.index(pubkey) for pubkey in sync_committee.pubkeys] yield 'pre', state block = build_empty_block_for_next_slot(spec, state) - block.body.sync_committee_bits = [True] * len(committee) + block.body.sync_committee_bits = [True] * len(committee_indices) block.body.sync_committee_signature = compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, - committee, + committee_indices, ) signed_block = state_transition_and_sign_block(spec, state, block)