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) # Valid sync committee signature here... block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, ) ) 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_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, invalid_block.slot - 2, committee_indices, ) ) yield from run_sync_committee_processing(spec, state, invalid_block, expect_exception=True)
def test_sync_committee_with_participating_withdrawable_member(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # move forward via some blocks for _ in range(3): next_epoch_via_block(spec, state) committee_indices = compute_committee_indices(spec, state) rng = random.Random(1010) exited_index = _exit_validator_from_committee_and_transition_state( spec, state, committee_indices, rng, lambda v: v.withdrawable_epoch + 1, ) current_epoch = spec.get_current_epoch(state) assert current_epoch > state.validators[exited_index].withdrawable_epoch block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, # full committee signs block_root=block.parent_root, ) ) yield from run_sync_committee_processing(spec, state, block)
def run_successful_sync_committee_test(spec, state, committee_indices, committee_bits): pre_state = state.copy() block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=committee_bits, sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, [ index for index, bit in zip(committee_indices, committee_bits) if bit ], )) yield from run_sync_committee_processing(spec, state, block) validate_sync_committee_rewards( spec, pre_state, state, committee_indices, committee_bits, block.proposer_index, )
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, block_root=block.parent_root, ) ) 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")
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) old_sync_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) # Use the previous sync committee to produce the signature. # Ensure that the pubkey sets are different. assert set(old_sync_committee.pubkeys) != set(state.current_sync_committee.pubkeys) committee_indices = compute_committee_indices(spec, state, old_sync_committee) block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, block_root=block.parent_root, ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def get_random_sync_aggregate(spec, state, slot, block_root=None, fraction_participated=1.0, rng=Random(2099)): committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) participant_count = int(len(committee_indices) * fraction_participated) participant_indices = rng.sample(range(len(committee_indices)), participant_count) participants = [committee_indices[index] for index in participant_indices] signature = compute_aggregate_sync_committee_signature( spec, state, slot, participants, block_root=block_root, ) return spec.SyncAggregate( sync_committee_bits=[ index in participant_indices for index in range(len(committee_indices)) ], sync_committee_signature=signature, )
def get_sync_aggregate(spec, state, block_header, block_root=None, signature_slot=None): if signature_slot is None: signature_slot = block_header.slot all_pubkeys = [v.pubkey for v in state.validators] committee = [ all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys ] sync_committee_bits = [True] * len(committee) sync_committee_signature = compute_aggregate_sync_committee_signature( spec, state, block_header.slot, committee, block_root=block_root, ) return spec.SyncAggregate( sync_committee_bits=sync_committee_bits, sync_committee_signature=sync_committee_signature, )
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) old_current_sync_committee = state.current_sync_committee old_next_sync_committee = state.next_sync_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 next_sync_committee = state.next_sync_committee assert next_sync_committee != sync_committee assert sync_committee != old_current_sync_committee assert sync_committee != old_next_sync_committee committee_indices = compute_committee_indices(spec, state, sync_committee) block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, ) ) yield from run_sync_committee_processing(spec, state, block)
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
def run_sync_committee_sanity_test(spec, state, fraction_full=1.0, rng=Random(454545)): all_pubkeys = [v.pubkey for v in state.validators] committee = [ all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys ] selected_indices = rng.sample(range(len(committee)), int(len(committee) * fraction_full)) sync_committee_bits = [ i in selected_indices for i in range(len(committee)) ] participants = [ validator_index for i, validator_index in enumerate(committee) if sync_committee_bits[i] ] yield 'pre', state block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=sync_committee_bits, sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, participants, )) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state
def test_process_light_client_update_not_updated(spec, state): pre_snapshot = spec.LightClientSnapshot( header=spec.BeaconBlockHeader(), current_sync_committee=state.current_sync_committee, next_sync_committee=state.next_sync_committee, ) store = spec.LightClientStore(snapshot=pre_snapshot, valid_updates=[]) # Block at slot 1 doesn't increase sync committee period, so it won't update snapshot block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) block_header = spec.BeaconBlockHeader( slot=signed_block.message.slot, proposer_index=signed_block.message.proposer_index, parent_root=signed_block.message.parent_root, state_root=signed_block.message.state_root, body_root=signed_block.message.body.hash_tree_root(), ) # Sync committee signing the header committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) sync_committee_bits = [True] * len(committee) sync_committee_signature = compute_aggregate_sync_committee_signature( spec, state, block.slot, committee, ) next_sync_committee_branch = [ spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX)) ] # Ensure that finality checkpoint is genesis assert state.finalized_checkpoint.epoch == 0 # Finality is unchanged finality_header = spec.BeaconBlockHeader() finality_branch = [ spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX)) ] update = spec.LightClientUpdate( header=block_header, next_sync_committee=state.next_sync_committee, next_sync_committee_branch=next_sync_committee_branch, finality_header=finality_header, finality_branch=finality_branch, sync_committee_bits=sync_committee_bits, sync_committee_signature=sync_committee_signature, fork_version=state.fork.current_version, ) spec.process_light_client_update(store, update, state.slot, state.genesis_validators_root) assert len(store.valid_updates) == 1 assert store.valid_updates[0] == update assert store.snapshot == pre_snapshot
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
def test_invalid_signature_bad_domain(spec, state): committee_indices = compute_committee_indices(spec, state) block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, # full committee signs block_root=block.parent_root, domain_type=spec.DOMAIN_BEACON_ATTESTER, # Incorrect domain ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_invalid_signature_missing_participant(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 ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_invalid_signature_extra_participant(spec, state): committee_indices = compute_committee_indices(spec, state, state.current_sync_committee) rng = random.Random(3030) random_participant = rng.choice(committee_indices) block = build_empty_block_for_next_slot(spec, state) # Exclude one signature even though the block claims the entire committee participated. block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[True] * len(committee_indices), sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, [index for index in committee_indices if index != random_participant], ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
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) 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, # full committee signs ) yield 'blocks', [block] expect_assertion_error(lambda: spec.process_sync_committee(state, block.body)) yield 'post', None
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) 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
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)) yield 'pre', state block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[index in participants for index in committee], sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, participants, ) ) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state
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
def test_sync_committee_with_nonparticipating_exited_member(spec, state): # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH # move forward via some blocks for _ in range(3): next_epoch_via_block(spec, state) committee_indices = compute_committee_indices(spec, state) rng = random.Random(1010) exited_index = _exit_validator_from_committee_and_transition_state( spec, state, committee_indices, rng, lambda v: v.exit_epoch, ) exited_pubkey = state.validators[exited_index].pubkey current_epoch = spec.get_current_epoch(state) assert current_epoch < state.validators[exited_index].withdrawable_epoch exited_committee_index = state.current_sync_committee.pubkeys.index(exited_pubkey) block = build_empty_block_for_next_slot(spec, state) committee_bits = [i != exited_committee_index for i in committee_indices] committee_indices = [index for index in committee_indices if index != exited_committee_index] block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=committee_bits, sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, committee_indices, # with exited validator removed block_root=block.parent_root, ) ) yield from run_sync_committee_processing(spec, state, block)
def run_sync_committee_sanity_test(spec, state, fraction_full=1.0): all_pubkeys = [v.pubkey for v in state.validators] committee = [ all_pubkeys.index(pubkey) for pubkey in state.current_sync_committee.pubkeys ] participants = random.sample(committee, int(len(committee) * fraction_full)) yield 'pre', state block = build_empty_block_for_next_slot(spec, state) block.body.sync_aggregate = spec.SyncAggregate( sync_committee_bits=[index in participants for index in committee], sync_committee_signature=compute_aggregate_sync_committee_signature( spec, state, block.slot - 1, participants, )) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state
def test_process_light_client_update_timeout(spec, state): pre_snapshot = spec.LightClientSnapshot( header=spec.BeaconBlockHeader(), current_sync_committee=state.current_sync_committee, next_sync_committee=state.next_sync_committee, ) store = spec.LightClientStore(snapshot=pre_snapshot, valid_updates=[]) # Forward to next sync committee period next_slots(spec, state, spec.SLOTS_PER_EPOCH * (spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD)) snapshot_period = spec.compute_epoch_at_slot( pre_snapshot.header.slot) // spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD update_period = spec.compute_epoch_at_slot( state.slot) // spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD assert snapshot_period + 1 == update_period block = build_empty_block_for_next_slot(spec, state) signed_block = state_transition_and_sign_block(spec, state, block) block_header = spec.BeaconBlockHeader( slot=signed_block.message.slot, proposer_index=signed_block.message.proposer_index, parent_root=signed_block.message.parent_root, state_root=signed_block.message.state_root, body_root=signed_block.message.body.hash_tree_root(), ) # Sync committee signing the finalized_block_header committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) sync_committee_bits = [True] * len(committee) sync_committee_signature = compute_aggregate_sync_committee_signature( spec, state, block_header.slot, committee, block_root=spec.Root(block_header.hash_tree_root()), ) # Sync committee is updated next_sync_committee_branch = build_proof(state.get_backing(), spec.NEXT_SYNC_COMMITTEE_INDEX) # Finality is unchanged finality_header = spec.BeaconBlockHeader() finality_branch = [ spec.Bytes32() for _ in range(spec.floorlog2(spec.FINALIZED_ROOT_INDEX)) ] update = spec.LightClientUpdate( header=block_header, next_sync_committee=state.next_sync_committee, next_sync_committee_branch=next_sync_committee_branch, finality_header=finality_header, finality_branch=finality_branch, sync_committee_bits=sync_committee_bits, sync_committee_signature=sync_committee_signature, fork_version=state.fork.current_version, ) spec.process_light_client_update(store, update, state.slot, state.genesis_validators_root) # snapshot has been updated assert len(store.valid_updates) == 0 assert store.snapshot.header == update.header
def test_process_light_client_update_finality_updated(spec, state): pre_snapshot = spec.LightClientSnapshot( header=spec.BeaconBlockHeader(), current_sync_committee=state.current_sync_committee, next_sync_committee=state.next_sync_committee, ) store = spec.LightClientStore(snapshot=pre_snapshot, valid_updates=[]) # Change finality blocks = [] next_slots(spec, state, spec.SLOTS_PER_EPOCH * 2) for epoch in range(3): prev_state, new_blocks, state = next_epoch_with_attestations( spec, state, True, True) blocks += new_blocks # Ensure that finality checkpoint has changed assert state.finalized_checkpoint.epoch == 3 # Ensure that it's same period snapshot_period = spec.compute_epoch_at_slot( pre_snapshot.header.slot) // spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD update_period = spec.compute_epoch_at_slot( state.slot) // spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD assert snapshot_period == update_period # Updated sync_committee and finality next_sync_committee_branch = [ spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX)) ] finalized_block_header = blocks[spec.SLOTS_PER_EPOCH - 1].message assert finalized_block_header.slot == spec.compute_start_slot_at_epoch( state.finalized_checkpoint.epoch) assert finalized_block_header.hash_tree_root( ) == state.finalized_checkpoint.root finality_branch = build_proof(state.get_backing(), spec.FINALIZED_ROOT_INDEX) # Build block header block = build_empty_block(spec, state) block_header = spec.BeaconBlockHeader( slot=block.slot, proposer_index=block.proposer_index, parent_root=block.parent_root, state_root=state.hash_tree_root(), body_root=block.body.hash_tree_root(), ) # Sync committee signing the finalized_block_header committee = spec.get_sync_committee_indices(state, spec.get_current_epoch(state)) sync_committee_bits = [True] * len(committee) sync_committee_signature = compute_aggregate_sync_committee_signature( spec, state, block_header.slot, committee, block_root=spec.Root(block_header.hash_tree_root()), ) update = spec.LightClientUpdate( header=finalized_block_header, next_sync_committee=state.next_sync_committee, next_sync_committee_branch=next_sync_committee_branch, finality_header=block_header, # block_header is the signed header finality_branch=finality_branch, sync_committee_bits=sync_committee_bits, sync_committee_signature=sync_committee_signature, fork_version=state.fork.current_version, ) spec.process_light_client_update(store, update, state.slot, state.genesis_validators_root) # snapshot has been updated assert len(store.valid_updates) == 0 assert store.snapshot.header == update.header