def _mk_resolved_attestation_duty(slot, public_key): return ( AttestationDuty(public_key, Tick(0, slot, 0, 1), Tick(0, 0, 0, 1), committee_index=22), Attestation.create(data=AttestationData.create(slot=slot)), )
def duty_fetcher(current_tick, _public_keys, target_epoch, _slots_per_epoch, _seconds_per_slot): duties = () if target_epoch < 0: return duties some_slot = current_tick.slot if current_tick.epoch >= 0: block_proposal_duty = BlockProposalDuty( public_key, Tick(0, some_slot, target_epoch, 0), current_tick) duties += (block_proposal_duty, ) attestation_duty = AttestationDuty( public_key, Tick(0, some_slot + slots_per_epoch, target_epoch, 1), current_tick, CommitteeIndex(22), ) duties += (attestation_duty, ) return duties
def _fetch_some_random_duties( current_tick: Tick, public_keys: Collection[BLSPubkey], target_epoch: Epoch, slots_per_epoch: Slot, seconds_per_slot: int, ) -> Tuple[Duty, ...]: if not public_keys: return () if target_epoch < 0: return () some_slot = Slot( random.randint(0, slots_per_epoch) + target_epoch * slots_per_epoch) execution_time = seconds_per_slot * (some_slot - current_tick.slot) + current_tick.t is_attestation = bool(random.getrandbits(1)) # NOTE: use of ``tuple`` here is satisfy ``mypy``. some_validator = random.choice(tuple(public_keys)) if is_attestation: committee_index = random.randint(0, 64) some_tick_count = 1 attestation_duty = AttestationDuty( some_validator, Tick(execution_time, some_slot, target_epoch, some_tick_count), current_tick, CommitteeIndex(committee_index), ) return (attestation_duty, ) else: some_tick_count = 0 block_proposal_duty = BlockProposalDuty( some_validator, Tick(execution_time, some_slot, target_epoch, some_tick_count), current_tick, ) return (block_proposal_duty, )
def _parse_block_proposal_duty( duty_data: Dict[str, Any], validator_public_key: BLSPubkey, current_tick: Tick, target_epoch: Epoch, genesis_time: int, seconds_per_slot: int, ticks_per_slot: int, ) -> BlockProposalDuty: target_tick = Tick.computing_t_from( Slot(duty_data["block_proposal_slot"]), target_epoch, BlockProposalDuty.tick_count, genesis_time, seconds_per_slot, ticks_per_slot, ) return BlockProposalDuty( validator_public_key=validator_public_key, tick_for_execution=target_tick, discovered_at_tick=current_tick, )
def _parse_attestation_duty( duty_data: Dict[str, Any], validator_public_key: BLSPubkey, current_tick: Tick, target_epoch: Epoch, genesis_time: int, seconds_per_slot: int, ticks_per_slot: int, ) -> AttestationDuty: target_tick = Tick.computing_t_from( Slot(duty_data["attestation_slot"]), target_epoch, AttestationDuty.tick_count, genesis_time, seconds_per_slot, ticks_per_slot, ) return AttestationDuty( validator_public_key=validator_public_key, tick_for_execution=target_tick, discovered_at_tick=current_tick, committee_index=CommitteeIndex(duty_data["committee_index"]), )
def on_tick(self, tick: Tick) -> None: if tick.is_first_in_slot(): fork_choice = self._get_fork_choice(tick.slot) head = fork_choice.find_head() self._update_head_if_new(head)
def test_chain_can_reorg_with_attestations(base_db, genesis_state, genesis_block, config, keymap): chain = BeaconChain.from_genesis(base_db, genesis_state) genesis_head = chain.get_canonical_head() assert genesis_head == genesis_block.message some_epochs = 5 some_slots = some_epochs * config.SLOTS_PER_EPOCH blocks, states = _build_chain_of_blocks_with_states( chain, genesis_state, genesis_block.message, some_slots, config, keymap, attestation_participation=0.01, ) for block in blocks: chain.on_block(block) head = chain.get_canonical_head() assert head == blocks[-1].message # NOTE: ideally we can randomly pick a reorg slot and successfully execute a reorg... # however, it becomes tricky to do reliably at low validator count as the numbers # may be too low to easily get enough stake one way or the other... # The following numbers are somewhat handcrafted and it would greatly improve this test # if it were made more resilient to these parameters. However, the big thing blocking # that is performance work so that the test runs in a short time at high validator count. some_reorg_slot = 12 # NOTE: this block hash is selected so that # we do not re-org in the chain import due to the tie breaker... some_block_hash = b"\x12" * 32 blocks, states = _build_chain_of_blocks_with_states( chain, states[some_reorg_slot - 1], blocks[some_reorg_slot - 1].message, 25, config, keymap, attestation_participation=0, eth1_block_hash=some_block_hash, ) for block in blocks: with pytest.raises(SlashableBlockError): chain.on_block(block) existing_head = head head = chain.get_canonical_head() assert head == existing_head attestations = _mk_attestations_from(blocks, states, chain, config, keymap) for attestation in attestations: chain.on_attestation(attestation) # NOTE: we have not updated the fork choice yet... # This is essentially to prevent what would otherwise be a DoS # vector according to this test... head = chain.get_canonical_head() assert head == existing_head # NOTE: simulate a tick to run the fork choice # in this case, we do not care which tick it is, # as long as it is the first tick in the slot chain.on_tick(Tick(0, Slot(0), Epoch(0), 0)) head = chain.get_canonical_head() assert head != existing_head assert head == blocks[-1].message
def _mk_resolved_block_proposal_duty(slot, public_key): return ( BlockProposalDuty(public_key, Tick(0, slot, 0, 0), Tick(0, 0, 0, 0)), BeaconBlock.create(slot=slot), )