def test_get_block_root_at_slot(sample_beacon_state_params, current_slot, target_slot, success, slots_per_epoch, slots_per_historical_root, sample_block): blocks, block_roots = generate_mock_latest_historical_roots( sample_block, current_slot, slots_per_epoch, slots_per_historical_root, ) state = BeaconState(**sample_beacon_state_params).copy( slot=current_slot, block_roots=block_roots, ) if success: block_root = get_block_root_at_slot( state, target_slot, slots_per_historical_root, ) assert block_root == blocks[target_slot].signing_root else: with pytest.raises(ValidationError): get_block_root_at_slot( state, target_slot, slots_per_historical_root, )
def create_mock_slashable_attestation( state: BeaconState, config: Eth2Config, keymap: Dict[BLSPubkey, int], attestation_slot: Slot, ) -> IndexedAttestation: """ Create an `IndexedAttestation` that is signed by one attester. """ attester_index = ValidatorIndex(0) committee = (attester_index, ) shard = Shard(0) # Use genesis block root as `beacon_block_root`, only for tests. beacon_block_root = get_block_root_at_slot( state, attestation_slot, config.SLOTS_PER_HISTORICAL_ROOT) # Get `target_root` target_root = _get_target_root(state, config, beacon_block_root) # Get `source_root` source_root = get_block_root_at_slot( state, compute_start_slot_of_epoch(state.current_justified_checkpoint.epoch, config.SLOTS_PER_EPOCH), config.SLOTS_PER_HISTORICAL_ROOT, ) previous_crosslink = state.current_crosslinks[shard] attestation_data = AttestationData( beacon_block_root=beacon_block_root, source=Checkpoint(epoch=state.current_justified_checkpoint.epoch, root=source_root), target=Checkpoint( epoch=compute_epoch_of_slot(attestation_slot, config.SLOTS_PER_EPOCH), root=target_root, ), crosslink=previous_crosslink, ) message_hash = _get_mock_message(attestation_data) attesting_indices = _get_mock_attesting_indices(committee, num_voted_attesters=1) signature = sign_transaction( message_hash=message_hash, privkey=keymap[state.validators[attesting_indices[0]].pubkey], state=state, slot=attestation_slot, signature_domain=SignatureDomain.DOMAIN_ATTESTATION, slots_per_epoch=config.SLOTS_PER_EPOCH, ) validator_indices = tuple(committee[i] for i in attesting_indices) return IndexedAttestation( custody_bit_0_indices=validator_indices, custody_bit_1_indices=tuple(), data=attestation_data, signature=signature, )
def get_matching_head_attestations( state: BeaconState, epoch: Epoch, config: Eth2Config) -> Iterable[PendingAttestation]: for a in get_matching_source_attestations(state, epoch, config): beacon_block_root = get_block_root_at_slot( state, a.data.slot, config.SLOTS_PER_HISTORICAL_ROOT) if a.data.beacon_block_root == beacon_block_root: yield a
def _get_target_checkpoint(state: BeaconState, head_root: Root, config: Eth2Config) -> Checkpoint: epoch = state.current_epoch(config.SLOTS_PER_EPOCH) start_slot = compute_start_slot_at_epoch(epoch, config.SLOTS_PER_EPOCH) if start_slot == state.slot: root = head_root else: root = get_block_root_at_slot(state, start_slot, config.SLOTS_PER_HISTORICAL_ROOT) return Checkpoint.create(epoch=epoch, root=root)
def test_get_block_root_at_slot( sample_beacon_state_params, current_slot, target_slot, success, slots_per_epoch, slots_per_historical_root, genesis_block, ): blocks, block_roots, _ = generate_mock_latest_historical_roots( genesis_block, current_slot, slots_per_epoch, slots_per_historical_root) state = BeaconState.create(**sample_beacon_state_params).mset( "slot", current_slot, "block_roots", block_roots) if success: block_root = get_block_root_at_slot(state, target_slot, slots_per_historical_root) assert block_root == blocks[target_slot].message.hash_tree_root else: with pytest.raises(ValidationError): get_block_root_at_slot(state, target_slot, slots_per_historical_root)
def create_mock_slashable_attestation( state: BeaconState, config: Eth2Config, keymap: Dict[BLSPubkey, int], attestation_slot: Slot, ) -> IndexedAttestation: """ Create an `IndexedAttestation` that is signed by one attester. """ attester_index = ValidatorIndex(0) committee = (attester_index, ) # Use genesis block root as `beacon_block_root`, only for tests. beacon_block_root = get_block_root_at_slot( state, attestation_slot, config.SLOTS_PER_HISTORICAL_ROOT) # Get `target_root` target_root = _get_target_root(state, config, beacon_block_root) # Get `source_root` source_root = get_block_root_at_slot( state, compute_start_slot_at_epoch(state.current_justified_checkpoint.epoch, config.SLOTS_PER_EPOCH), config.SLOTS_PER_HISTORICAL_ROOT, ) committees_per_slot = get_committee_count_at_slot( state, Slot(attestation_slot), config.MAX_COMMITTEES_PER_SLOT, config.SLOTS_PER_EPOCH, config.TARGET_COMMITTEE_SIZE, ) # Use the first committee assert committees_per_slot > 0 committee_index = CommitteeIndex(0) attestation_data = AttestationData.create( slot=attestation_slot, index=committee_index, beacon_block_root=beacon_block_root, source=Checkpoint.create( epoch=state.current_justified_checkpoint.epoch, root=source_root), target=Checkpoint.create( epoch=compute_epoch_at_slot(attestation_slot, config.SLOTS_PER_EPOCH), root=target_root, ), ) message_hash = attestation_data.hash_tree_root attesting_indices = _get_mock_attesting_indices(committee, num_voted_attesters=1) signature = sign_transaction( message_hash=message_hash, privkey=keymap[state.validators[attesting_indices[0]].pubkey], state=state, slot=attestation_slot, signature_domain=SignatureDomain.DOMAIN_BEACON_ATTESTER, slots_per_epoch=config.SLOTS_PER_EPOCH, ) validator_indices = tuple(committee[i] for i in attesting_indices) return IndexedAttestation.create(attesting_indices=validator_indices, data=attestation_data, signature=signature)
def test_get_attestation_deltas(genesis_state, config, slots_per_epoch, target_committee_size, shard_count, min_attestation_inclusion_delay, inactivity_penalty_quotient, finalized_epoch, current_slot, sample_pending_attestation_record_params, sample_attestation_data_params): state = genesis_state.copy(slot=current_slot, finalized_checkpoint=Checkpoint( epoch=finalized_epoch, )) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) epoch_start_shard = get_start_shard( state, previous_epoch, CommitteeConfig(config), ) shard_delta = get_shard_delta( state, previous_epoch, CommitteeConfig(config), ) a = epoch_start_shard b = epoch_start_shard + shard_delta if a > b: valid_shards_for_epoch = range(b, a) else: valid_shards_for_epoch = range(a, b) indices_to_check = set() prev_epoch_start_slot = compute_start_slot_of_epoch( previous_epoch, slots_per_epoch) prev_epoch_attestations = tuple() for slot in range(prev_epoch_start_slot, prev_epoch_start_slot + slots_per_epoch): committee, shard = get_crosslink_committees_at_slot( state, slot, CommitteeConfig(config), )[0] if not committee: continue if shard not in valid_shards_for_epoch: continue participants_bitfield = get_empty_bitfield(len(committee)) for i, index in enumerate(committee): indices_to_check.add(index) participants_bitfield = set_voted(participants_bitfield, i) prev_epoch_attestations += (PendingAttestation( **sample_pending_attestation_record_params).copy( aggregation_bits=participants_bitfield, inclusion_delay=min_attestation_inclusion_delay, proposer_index=get_beacon_proposer_index( state.copy(slot=slot, ), CommitteeConfig(config), ), data=AttestationData(**sample_attestation_data_params).copy( crosslink=Crosslink(shard=shard, ), target=Checkpoint( epoch=previous_epoch, root=get_block_root( state, previous_epoch, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ), ), beacon_block_root=get_block_root_at_slot( state, slot, config.SLOTS_PER_HISTORICAL_ROOT, ), ), ), ) state = state.copy(previous_epoch_attestations=prev_epoch_attestations, ) rewards_received, penalties_received = get_attestation_deltas( state, config, ) # everyone attested, no penalties assert (sum(penalties_received) == 0) the_reward = rewards_received[0] # everyone performed the same, equal rewards assert (sum(rewards_received) // len(rewards_received) == the_reward)
def test_get_attestation_deltas( genesis_state, config, slots_per_epoch, target_committee_size, max_committees_per_slot, min_attestation_inclusion_delay, inactivity_penalty_quotient, finalized_epoch, current_slot, sample_pending_attestation_record_params, sample_attestation_data_params, ): state = genesis_state.mset( "slot", current_slot, "finalized_checkpoint", Checkpoint.create(epoch=finalized_epoch), ) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) has_inactivity_penalty = (previous_epoch - finalized_epoch > config.MIN_EPOCHS_TO_INACTIVITY_PENALTY) indices_to_check = set() prev_epoch_attestations = tuple() for committee, committee_index, slot in iterate_committees_at_epoch( state, previous_epoch, config): participants_bitfield = get_empty_bitfield(len(committee)) for i, index in enumerate(committee): indices_to_check.add(index) participants_bitfield = set_voted(participants_bitfield, i) prev_epoch_attestations += (PendingAttestation.create( **sample_pending_attestation_record_params).mset( "aggregation_bits", participants_bitfield, "inclusion_delay", min_attestation_inclusion_delay, "proposer_index", get_beacon_proposer_index(state.set("slot", slot), CommitteeConfig(config)), "data", AttestationData.create(**sample_attestation_data_params).mset( "slot", slot, "index", committee_index, "beacon_block_root", get_block_root_at_slot(state, slot, config.SLOTS_PER_HISTORICAL_ROOT), "target", Checkpoint.create( epoch=previous_epoch, root=get_block_root( state, previous_epoch, config.SLOTS_PER_EPOCH, config.SLOTS_PER_HISTORICAL_ROOT, ), ), ), ), ) state = state.set("previous_epoch_attestations", prev_epoch_attestations) rewards_received, penalties_received = get_attestation_deltas( state, config) if has_inactivity_penalty: assert sum(penalties_received) > 0 else: assert sum(penalties_received) == 0 assert all(reward > 0 for reward in rewards_received)