async def validate_peer_status(chain: BaseBeaconChain, peer_status: Status) -> None: state_machine = chain.get_state_machine() state = chain.get_head_state() config = state_machine.config if peer_status.head_fork_version != state.fork.current_version: raise IrrelevantNetwork( "`fork_version` mismatches: " f"peer_status.head_fork_version={peer_status.head_fork_version}, " f"state.fork.current_version={state.fork.current_version}") # Can not validate the checkpoint with `finalized_epoch` higher than ours if peer_status.finalized_epoch > state.finalized_checkpoint.epoch: return # Edge case where nothing is finalized yet if (peer_status.finalized_epoch == 0 and peer_status.finalized_root == ZERO_ROOT): return finalized_epoch_start_slot = compute_start_slot_at_epoch( peer_status.finalized_epoch, config.SLOTS_PER_EPOCH, ) finalized_root = chain.get_canonical_block_root(finalized_epoch_start_slot) if peer_status.finalized_root != finalized_root: raise IrrelevantNetwork( "`finalized_root` mismatches: " f"peer_status.finalized_root={peer_status.finalized_root.hex()}, " f"peer_status.finalized_epoch={peer_status.finalized_epoch}, " f"our `finalized_root` at the same `finalized_epoch`={finalized_root.hex()}" )
def peer_is_ahead(chain: BaseBeaconChain, peer_status: Status) -> bool: checkpoint = chain.get_head_state().finalized_checkpoint head_block = chain.get_canonical_head() peer_has_higher_finalized_epoch = peer_status.finalized_epoch > checkpoint.epoch peer_has_equal_finalized_epoch = peer_status.finalized_epoch == checkpoint.epoch peer_has_higher_head_slot = peer_status.head_slot > head_block.slot return (peer_has_higher_finalized_epoch or (peer_has_equal_finalized_epoch and peer_has_higher_head_slot))
def __init__(self, chain: BaseBeaconChain, event_bus: EndpointAPI, token: CancelToken = None) -> None: super().__init__(token) self.genesis_time = chain.get_head_state().genesis_time self.chain = chain self.event_bus = event_bus config = self.chain.get_state_machine().config self.slots_per_epoch = config.SLOTS_PER_EPOCH
def validate_start_slot(chain: BaseBeaconChain, start_slot: Slot) -> None: config = chain.get_state_machine().config state = chain.get_head_state() finalized_epoch_start_slot = compute_start_slot_at_epoch( epoch=state.finalized_checkpoint.epoch, slots_per_epoch=config.SLOTS_PER_EPOCH, ) if start_slot < finalized_epoch_start_slot: raise ValidationError( f"`start_slot`({start_slot}) lower than our" f" latest finalized slot({finalized_epoch_start_slot})")
def get_my_status(chain: BaseBeaconChain) -> Status: state = chain.get_head_state() head = chain.get_canonical_head() finalized_checkpoint = state.finalized_checkpoint return Status.create( head_fork_version=state.fork.current_version, finalized_root=finalized_checkpoint.root, finalized_epoch=finalized_checkpoint.epoch, head_root=head.message.hash_tree_root, head_slot=head.slot, )
def __init__( self, chain: BaseBeaconChain, p2p_node: Node, event_bus: EndpointAPI, get_ready_attestations_fn: GetReadyAttestationsFn, get_aggregatable_attestations_fn: GetAggregatableAttestationsFn, import_attestation_fn: ImportAttestationFn, token: CancelToken = None) -> None: super().__init__(token) self.genesis_time = chain.get_head_state().genesis_time self.chain = chain self.p2p_node = p2p_node self.event_bus = event_bus self.get_ready_attestations: GetReadyAttestationsFn = get_ready_attestations_fn self.get_aggregatable_attestations: GetAggregatableAttestationsFn = get_aggregatable_attestations_fn # noqa: E501 self.import_attestation: ImportAttestationFn = import_attestation_fn # `state.eth1_data` can be updated in the middle of voting period and thus # the starting `eth1_data.block_hash` must be stored separately. self.starting_eth1_block_hash = chain.get_head_state( ).eth1_data.block_hash
def __init__( self, chain: BaseBeaconChain, p2p_node: Node, validator_privkeys: Dict[ValidatorIndex, int], event_bus: EndpointAPI, get_ready_attestations_fn: GetReadyAttestationsFn, get_aggregatable_attestations_fn: GetAggregatableAttestationsFn, import_attestation_fn: ImportAttestationFn, token: CancelToken = None) -> None: super().__init__(token) self.genesis_time = chain.get_head_state().genesis_time self.chain = chain self.p2p_node = p2p_node self.validator_privkeys = validator_privkeys self.event_bus = event_bus config = self.chain.get_state_machine().config self.slots_per_epoch = config.SLOTS_PER_EPOCH # TODO: `latest_proposed_epoch` and `latest_attested_epoch` should be written # into/read from validator's own db. self.latest_proposed_epoch = {} self.latest_attested_epoch = {} self.local_validator_epoch_assignment = {} for validator_index in validator_privkeys: self.latest_proposed_epoch[validator_index] = Epoch(-1) self.latest_attested_epoch[validator_index] = Epoch(-1) self.local_validator_epoch_assignment[validator_index] = ( Epoch(-1), CommitteeAssignment((), CommitteeIndex(-1), Slot(-1)), ) self.get_ready_attestations: GetReadyAttestationsFn = get_ready_attestations_fn self.get_aggregatable_attestations: GetAggregatableAttestationsFn = get_aggregatable_attestations_fn # noqa: E501 self.import_attestation: ImportAttestationFn = import_attestation_fn # `state.eth1_data` can be updated in the middle of voting period and thus # the starting `eth1_data.block_hash` must be stored separately. self.starting_eth1_block_hash = chain.get_head_state( ).eth1_data.block_hash
def compare_chain_tip_and_finalized_epoch(chain: BaseBeaconChain, peer_status: Status) -> None: checkpoint = chain.get_head_state().finalized_checkpoint head_block = chain.get_canonical_head() peer_has_higher_finalized_epoch = peer_status.finalized_epoch > checkpoint.epoch peer_has_equal_finalized_epoch = peer_status.finalized_epoch == checkpoint.epoch peer_has_higher_head_slot = peer_status.head_slot > head_block.slot if (peer_has_higher_finalized_epoch or (peer_has_equal_finalized_epoch and peer_has_higher_head_slot)): # TODO: kickoff syncing process with this peer logger.debug( "Peer's chain is ahead of us, start syncing with the peer.") pass