def test_invalid_signature_past_block(spec, state): committee_indices = compute_committee_indices(spec, state) 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, block_root=block.parent_root, ) ) 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 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 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 check_proposer_slashing_effect(spec, pre_state, state, slashed_index, block=None): slashed_validator = state.validators[slashed_index] assert slashed_validator.slashed assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH proposer_index = spec.get_beacon_proposer_index(state) slash_penalty = state.validators[ slashed_index].effective_balance // get_min_slashing_penalty_quotient( spec) whistleblower_reward = state.validators[ slashed_index].effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT # Altair introduces sync committee (SC) reward and penalty sc_reward_for_slashed = sc_penalty_for_slashed = sc_reward_for_proposer = sc_penalty_for_proposer = 0 if is_post_altair(spec) and block is not None: committee_indices = compute_committee_indices( spec, state, state.current_sync_committee) committee_bits = block.body.sync_aggregate.sync_committee_bits sc_reward_for_slashed, sc_penalty_for_slashed = compute_sync_committee_participant_reward_and_penalty( spec, pre_state, slashed_index, committee_indices, committee_bits, ) sc_reward_for_proposer, sc_penalty_for_proposer = compute_sync_committee_participant_reward_and_penalty( spec, pre_state, proposer_index, committee_indices, committee_bits, ) if proposer_index != slashed_index: # slashed validator lost initial slash penalty assert (get_balance( state, slashed_index) == get_balance(pre_state, slashed_index) - slash_penalty + sc_reward_for_slashed - sc_penalty_for_slashed) # block proposer gained whistleblower reward # >= because proposer could have reported multiple assert ( get_balance(state, proposer_index) >= (get_balance(pre_state, proposer_index) + whistleblower_reward + sc_reward_for_proposer - sc_penalty_for_proposer)) else: # proposer reported themself so get penalty and reward # >= because proposer could have reported multiple assert (get_balance(state, slashed_index) >= (get_balance(pre_state, slashed_index) - slash_penalty + whistleblower_reward + sc_reward_for_slashed - sc_penalty_for_slashed))
def test_sync_committee_rewards_duplicate_committee_full_participation(spec, state): committee_indices = compute_committee_indices(spec, state) committee_size = len(committee_indices) committee_bits = [True] * 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)
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) 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 block_root=block.parent_root, ) ) 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) 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], block_root=block.parent_root, ) ) yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_deposit_top_up(spec, state): validator_index = 0 amount = spec.MAX_EFFECTIVE_BALANCE // 4 deposit = prepare_state_and_deposit(spec, state, validator_index, amount) initial_registry_len = len(state.validators) initial_balances_len = len(state.balances) validator_pre_balance = get_balance(state, validator_index) pre_state = state.copy() yield 'pre', pre_state block = build_empty_block_for_next_slot(spec, state) block.body.deposits.append(deposit) signed_block = state_transition_and_sign_block(spec, state, block) yield 'blocks', [signed_block] yield 'post', state assert len(state.validators) == initial_registry_len assert len(state.balances) == initial_balances_len # Altair introduces sync committee (sm) reward and penalty sync_committee_reward = sync_committee_penalty = 0 if is_post_altair(spec): committee_indices = compute_committee_indices( spec, state, state.current_sync_committee) committee_bits = block.body.sync_aggregate.sync_committee_bits sync_committee_reward, sync_committee_penalty = compute_sync_committee_participant_reward_and_penalty( spec, pre_state, validator_index, committee_indices, committee_bits, ) assert get_balance(state, validator_index) == (validator_pre_balance + amount + sync_committee_reward - sync_committee_penalty)
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 _test_harness_for_randomized_test_case(spec, state, expect_duplicates=False, participation_fn=None): committee_indices = compute_committee_indices(spec, state) if participation_fn: participating_indices = participation_fn(committee_indices) else: participating_indices = committee_indices committee_bits = [ index in participating_indices for index in committee_indices ] committee_size = len(committee_indices) if expect_duplicates: assert committee_size > len(set(committee_indices)) else: assert committee_size == len(set(committee_indices)) yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)
def test_sync_committee_rewards_empty_participants(spec, state): committee_indices = compute_committee_indices(spec, state) committee_bits = [False for _ in committee_indices] yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)
def test_sync_committee_rewards_not_full_participants(spec, state): committee_indices = compute_committee_indices(spec, state) rng = random.Random(1010) committee_bits = [rng.choice([True, False]) for _ in committee_indices] yield from run_successful_sync_committee_test(spec, state, committee_indices, committee_bits)