From 2aa5bf8384228b7d448e3e2c8e2e0b2ad63e318d Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 1 Jul 2021 16:35:03 -0700 Subject: [PATCH 1/8] assert active validator set is larger than sync committee size ensure set is larger, rather than just equal to --- .../test/altair/block_processing/test_process_sync_aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index fa7f89fdc..1dbe435b9 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -170,7 +170,7 @@ def test_sync_committee_rewards_nonduplicate_committee(spec, state): active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) # Preconditions of this test case - assert active_validator_count >= spec.SYNC_COMMITTEE_SIZE + assert active_validator_count > spec.SYNC_COMMITTEE_SIZE assert committee_size == len(set(committee_indices)) yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits) From 21aaab5a1e7c5c1b21c302ce24418e628dac03f0 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 1 Jul 2021 16:36:54 -0700 Subject: [PATCH 2/8] add test for sync aggregate with bad domain in signature --- .../test_process_sync_aggregate.py | 23 +++++++++++++++++++ .../eth2spec/test/helpers/sync_committee.py | 9 +++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index 1dbe435b9..4b2f6f738 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -63,6 +63,29 @@ def get_committee_indices(spec, state, duplicates=False): state.randao_mixes[randao_index] = hash(state.randao_mixes[randao_index]) +@with_altair_and_later +@spec_state_test +@always_bls +def test_invalid_signature_bad_domain(spec, state): + committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) + rng = random.Random(2020) + random_participant = rng.choice(committee_indices) + + block = build_empty_block_for_next_slot(spec, state) + # Exclude one participant whose signature was included. + block.body.sync_aggregate = spec.SyncAggregate( + sync_committee_bits=[index != random_participant for index in committee_indices], + sync_committee_signature=compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + committee_indices, # full committee signs + domain_type=spec.DOMAIN_BEACON_ATTESTER, + ) + ) + yield from run_sync_committee_processing(spec, state, block, expect_exception=True) + + @with_altair_and_later @spec_state_test @always_bls diff --git a/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py b/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py index fa753db52..71be65044 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sync_committee.py @@ -7,8 +7,10 @@ from eth2spec.test.helpers.block import ( from eth2spec.utils import bls -def compute_sync_committee_signature(spec, state, slot, privkey, block_root=None): - domain = spec.get_domain(state, spec.DOMAIN_SYNC_COMMITTEE, spec.compute_epoch_at_slot(slot)) +def compute_sync_committee_signature(spec, state, slot, privkey, block_root=None, domain_type=None): + if not domain_type: + domain_type = spec.DOMAIN_SYNC_COMMITTEE + domain = spec.get_domain(state, domain_type, spec.compute_epoch_at_slot(slot)) if block_root is None: if slot == state.slot: block_root = build_empty_block_for_next_slot(spec, state).parent_root @@ -18,7 +20,7 @@ def compute_sync_committee_signature(spec, state, slot, privkey, block_root=None return bls.Sign(privkey, signing_root) -def compute_aggregate_sync_committee_signature(spec, state, slot, participants, block_root=None): +def compute_aggregate_sync_committee_signature(spec, state, slot, participants, block_root=None, domain_type=None): if len(participants) == 0: return spec.G2_POINT_AT_INFINITY @@ -32,6 +34,7 @@ def compute_aggregate_sync_committee_signature(spec, state, slot, participants, slot, privkey, block_root=block_root, + domain_type=domain_type, ) ) return bls.Aggregate(signatures) From b3a879c990e4f4148d899461e09e30b4f65ce98d Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 1 Jul 2021 16:40:21 -0700 Subject: [PATCH 3/8] add tests for duplicated sync committee members with various amounts of participation --- .../test_process_sync_aggregate.py | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index 4b2f6f738..7e607afcf 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -202,7 +202,41 @@ def test_sync_committee_rewards_nonduplicate_committee(spec, state): @with_altair_and_later @with_presets([MAINNET], reason="to create duplicate committee") @spec_state_test -def test_sync_committee_rewards_duplicate_committee(spec, state): +def test_sync_committee_rewards_duplicate_committee_no_participation(spec, state): + committee_indices = get_committee_indices(spec, state, duplicates=True) + committee_size = len(committee_indices) + committee_bits = [False] * committee_size + assert len(committee_bits) == committee_size + active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) + + # Preconditions of this test case + assert active_validator_count < spec.SYNC_COMMITTEE_SIZE + assert committee_size > len(set(committee_indices)) + + yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits) + + +@with_altair_and_later +@with_presets([MAINNET], reason="to create duplicate committee") +@spec_state_test +def test_sync_committee_rewards_duplicate_committee_half_participation(spec, state): + committee_indices = get_committee_indices(spec, state, duplicates=True) + committee_size = len(committee_indices) + committee_bits = [True] * (committee_size // 2) + [False] * (committee_size // 2) + assert len(committee_bits) == committee_size + active_validator_count = len(spec.get_active_validator_indices(state, spec.get_current_epoch(state))) + + # Preconditions of this test case + assert active_validator_count < spec.SYNC_COMMITTEE_SIZE + assert committee_size > len(set(committee_indices)) + + yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits) + + +@with_altair_and_later +@with_presets([MAINNET], reason="to create duplicate committee") +@spec_state_test +def test_sync_committee_rewards_duplicate_committee_full_participation(spec, state): committee_indices = get_committee_indices(spec, state, duplicates=True) committee_size = len(committee_indices) committee_bits = [True] * committee_size From faf1ba1f4f3a735a3bc20edcf1a15a7f99b3bb95 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 1 Jul 2021 17:29:09 -0700 Subject: [PATCH 4/8] clean up test this test does not need to collect the intermediate blocks it produces --- .../altair/block_processing/test_process_sync_aggregate.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index 7e607afcf..e765658b3 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -276,7 +276,6 @@ def test_sync_committee_rewards_empty_participants(spec, state): def test_invalid_signature_past_block(spec, state): committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) - 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) @@ -291,8 +290,7 @@ def test_invalid_signature_past_block(spec, state): ) ) - signed_block = state_transition_and_sign_block(spec, state, block) - blocks.append(signed_block) + state_transition_and_sign_block(spec, state, block) invalid_block = build_empty_block_for_next_slot(spec, state) # Invalid signature from a slot other than the previous From 49c433746d3237e189819b326a0169b4224f9ac5 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 1 Jul 2021 17:29:33 -0700 Subject: [PATCH 5/8] sync aggregate test with proposer in the committee --- .../test_process_sync_aggregate.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index e765658b3..1b9495dc7 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -382,3 +382,41 @@ def test_valid_signature_future_committee(spec, state): ) yield from run_sync_committee_processing(spec, state, block) + + +@with_altair_and_later +@spec_state_test +@always_bls +@with_presets([MINIMAL], reason="prefer short search to find matching proposer") +def test_proposer_in_committee_without_participation(spec, state): + committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) + + # NOTE: seem to reliably be getting a matching proposer in the first epoch w/ ``MINIMAL`` preset. + for _ in range(spec.SLOTS_PER_EPOCH): + block = build_empty_block_for_next_slot(spec, state) + proposer_index = block.proposer_index + proposer_pubkey = state.validators[proposer_index].pubkey + proposer_is_in_sync_committee = proposer_pubkey in state.current_sync_committee.pubkeys + if proposer_is_in_sync_committee: + participation = [index != proposer_index for index in committee_indices] + participants = [index for index in committee_indices if index != proposer_index] + else: + participation = [True for _ in committee_indices] + participants = committee_indices + # Valid sync committee signature here... + block.body.sync_aggregate = spec.SyncAggregate( + sync_committee_bits=participation, + sync_committee_signature=compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + participants, + ) + ) + + if proposer_is_in_sync_committee: + yield from run_sync_committee_processing(spec, state, block) + return + else: + state_transition_and_sign_block(spec, state, block) + raise AssertionError("failed to find a proposer in the sync committee set; check test setup") From f9b4d7f28719f9e62dadb62c32a32e7d89bd7fbd Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 1 Jul 2021 17:36:30 -0700 Subject: [PATCH 6/8] add test for sync aggregate with proposer in sync committee --- .../test_process_sync_aggregate.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index 1b9495dc7..55bbafd6f 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -415,6 +415,42 @@ def test_proposer_in_committee_without_participation(spec, state): ) if proposer_is_in_sync_committee: + assert state.validators[block.proposer_index].pubkey in state.current_sync_committee.pubkeys + yield from run_sync_committee_processing(spec, state, block) + return + else: + state_transition_and_sign_block(spec, state, block) + raise AssertionError("failed to find a proposer in the sync committee set; check test setup") + + +@with_altair_and_later +@spec_state_test +@always_bls +@with_presets([MINIMAL], reason="prefer short search to find matching proposer") +def test_proposer_in_committee_with_participation(spec, state): + committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) + participation = [True for _ in committee_indices] + + # NOTE: seem to reliably be getting a matching proposer in the first epoch w/ ``MINIMAL`` preset. + for _ in range(spec.SLOTS_PER_EPOCH): + block = build_empty_block_for_next_slot(spec, state) + proposer_index = block.proposer_index + proposer_pubkey = state.validators[proposer_index].pubkey + proposer_is_in_sync_committee = proposer_pubkey in state.current_sync_committee.pubkeys + + # Valid sync committee signature here... + block.body.sync_aggregate = spec.SyncAggregate( + sync_committee_bits=participation, + sync_committee_signature=compute_aggregate_sync_committee_signature( + spec, + state, + block.slot - 1, + committee_indices, + ) + ) + + if proposer_is_in_sync_committee: + assert state.validators[block.proposer_index].pubkey in state.current_sync_committee.pubkeys yield from run_sync_committee_processing(spec, state, block) return else: From 2d4ff72b2dccd8ec900681b621d4313a48b87099 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Fri, 2 Jul 2021 08:38:03 -0700 Subject: [PATCH 7/8] Update tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py Co-authored-by: Hsiao-Wei Wang --- .../altair/block_processing/test_process_sync_aggregate.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index 55bbafd6f..fe847b741 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -417,10 +417,11 @@ def test_proposer_in_committee_without_participation(spec, state): if proposer_is_in_sync_committee: assert state.validators[block.proposer_index].pubkey in state.current_sync_committee.pubkeys yield from run_sync_committee_processing(spec, state, block) - return + break else: state_transition_and_sign_block(spec, state, block) - raise AssertionError("failed to find a proposer in the sync committee set; check test setup") + else: + raise AssertionError("failed to find a proposer in the sync committee set; check test setup") @with_altair_and_later From 1865cdb4fc157ad3dc9f04a07bc1550518dd1ef1 Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Fri, 2 Jul 2021 15:28:05 -0600 Subject: [PATCH 8/8] add comment --- .../test/altair/block_processing/test_process_sync_aggregate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py index fe847b741..1228136ac 100644 --- a/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py +++ b/tests/core/pyspec/eth2spec/test/altair/block_processing/test_process_sync_aggregate.py @@ -80,7 +80,7 @@ def test_invalid_signature_bad_domain(spec, state): state, block.slot - 1, committee_indices, # full committee signs - domain_type=spec.DOMAIN_BEACON_ATTESTER, + domain_type=spec.DOMAIN_BEACON_ATTESTER, # Incorrect domain ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)