示例#1
0
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()}"
        )
示例#2
0
async def process_metrics(chain: BaseBeaconChain,
                          event_bus: EndpointAPI) -> None:
    # Networking
    libp2p_peers = await event_bus.request(Libp2pPeersRequest())
    metrics.libp2p_peers.set(len(libp2p_peers.result))

    # Per slot info
    beacon_slot = chain.get_head_state_slot()
    metrics.beacon_slot.set(beacon_slot)

    # Per block info
    head_block = chain.get_canonical_head()
    metrics.beacon_head_slot.set(head_block.slot)
    metrics.beacon_head_root.set(root_to_int(head_block.hash_tree_root))

    # Per epoch info
    epoch_info = chain.get_canonical_epoch_info()
    metrics.beacon_previous_justified_epoch.set(
        epoch_info.previous_justified_checkpoint.epoch)
    metrics.beacon_previous_justified_root.set(
        root_to_int(epoch_info.previous_justified_checkpoint.root), )
    metrics.beacon_current_justified_epoch.set(
        epoch_info.current_justified_checkpoint.epoch)
    metrics.beacon_current_justified_root.set(
        root_to_int(epoch_info.current_justified_checkpoint.root), )
    metrics.beacon_finalized_epoch.set(epoch_info.finalized_checkpoint.epoch)
    metrics.beacon_finalized_root.set(
        root_to_int(epoch_info.finalized_checkpoint.root))
示例#3
0
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))
示例#4
0
def validate_voting_beacon_block(chain: BaseBeaconChain,
                                 attestation: Attestation) -> None:
    # Check that beacon blocks attested to by the attestation are validated
    try:
        chain.get_block_by_root(attestation.data.beacon_block_root)
    except BlockNotFound:
        raise InvalidGossipMessage(
            f"Failed to validate attestation={attestation},"
            f" attested block={encode_hex(attestation.data.beacon_block_root)}"
            " has not been not validated yet")
示例#5
0
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})")
示例#6
0
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,
    )
示例#7
0
def get_blocks(
    chain: BaseBeaconChain,
    parent_block: SerenityBeaconBlock = None,
    num_blocks: int = 3,
) -> Tuple[SerenityBeaconBlock, ...]:
    if parent_block is None:
        parent_block = chain.get_canonical_head()
    blocks = []
    for _ in range(num_blocks):
        block = chain.create_block_from_parent(parent_block=parent_block,
                                               block_params=FromBlockParams())
        blocks.append(block)
        parent_block = block
    return tuple(blocks)
示例#8
0
文件: utils.py 项目: veox/trinity
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
示例#9
0
def get_blocks_from_fork_chain_by_root(
    chain: BaseBeaconChain,
    start_slot: Slot,
    peer_head_block: BaseBeaconBlock,
    slot_of_requested_blocks: Sequence[Slot],
) -> Iterable[BaseBeaconBlock]:
    # Peer's head block is on a fork chain,
    # start getting the requested blocks by
    # traversing the history from the head.

    # `slot_of_requested_blocks` starts with earliest slot
    # and end with most recent slot, so we start traversing
    # from the most recent slot.
    cur_index = len(slot_of_requested_blocks) - 1
    block = peer_head_block
    if block.slot == slot_of_requested_blocks[cur_index]:
        yield block
        cur_index -= 1
    while block.slot > start_slot and cur_index >= 0:
        try:
            block = chain.get_block_by_root(block.parent_root)
        except (BlockNotFound, ValidationError):
            # This should not happen as we only persist block if its
            # ancestors are also in the database.
            break
        else:
            while block.slot < slot_of_requested_blocks[cur_index]:
                if cur_index > 0:
                    cur_index -= 1
                else:
                    break
            if block.slot == slot_of_requested_blocks[cur_index]:
                yield block
示例#10
0
def get_requested_beacon_blocks(
    chain: BaseBeaconChain,
    request: BeaconBlocksByRangeRequest
) -> Tuple[BaseBeaconBlock, ...]:
    try:
        requested_head = chain.get_block_by_root(
            request.head_block_root
        )
    except (BlockNotFound, ValidationError) as error:
        logger.info("Sending empty blocks, reason: %s", error)
        return tuple()

    # Check if slot of specified head block is greater than specified start slot
    if requested_head.slot < request.start_slot:
        raise InvalidRequest(
            f"head block slot({requested_head.slot}) lower than `start_slot`({request.start_slot})"
        )

    try:
        requested_beacon_blocks = _get_requested_beacon_blocks(
            chain, request, requested_head
        )
        return requested_beacon_blocks
    except ValidationError as val_error:
        raise InvalidRequest(str(val_error))
 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
示例#12
0
def get_beacon_blocks_by_root(
    chain: BaseBeaconChain,
    request: BeaconBlocksByRootRequest,
) -> Iterable[BaseBeaconBlock]:
    for block_root in request.block_roots:
        try:
            block = chain.get_block_by_root(block_root)
        except (BlockNotFound, ValidationError):
            pass
        else:
            yield block
示例#13
0
    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
示例#14
0
def get_blocks_from_canonical_chain_by_slot(
    chain: BaseBeaconChain,
    slot_of_requested_blocks: Sequence[Slot],
) -> Iterable[BaseBeaconBlock]:
    # If peer's head block is on our canonical chain,
    # start getting the requested blocks by slots.
    for slot in slot_of_requested_blocks:
        try:
            block = chain.get_canonical_block_by_slot(slot)
        except BlockNotFound:
            pass
        else:
            yield block
示例#15
0
    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
示例#16
0
def _get_requested_beacon_blocks(
    chain: BaseBeaconChain,
    beacon_blocks_request: BeaconBlocksByRangeRequest,
    requested_head_block: BaseBeaconBlock,
) -> Tuple[BaseBeaconBlock, ...]:
    slot_of_requested_blocks = tuple(
        beacon_blocks_request.start_slot + i * beacon_blocks_request.step
        for i in range(beacon_blocks_request.count)
    )
    logger.info("slot_of_requested_blocks: %s", slot_of_requested_blocks)
    slot_of_requested_blocks = tuple(
        filter(lambda slot: slot <= requested_head_block.slot, slot_of_requested_blocks)
    )

    if len(slot_of_requested_blocks) == 0:
        return tuple()

    # We have the peer's head block in our database,
    # next check if the head block is on our canonical chain.
    try:
        canonical_block_at_slot = chain.get_canonical_block_by_slot(
            requested_head_block.slot
        )
        block_match = canonical_block_at_slot == requested_head_block
    except BlockNotFound:
        logger.debug(
            (
                "The requested head block is not on our canonical chain  "
                "requested_head_block: %s"
            ),
            requested_head_block,
        )
        block_match = False
    finally:
        if block_match:
            # Peer's head block is on our canonical chain
            return get_blocks_from_canonical_chain_by_slot(
                chain,
                slot_of_requested_blocks,
            )
        else:
            # Peer's head block is not on our canonical chain
            # Validate `start_slot` is greater than our latest finalized slot
            validate_start_slot(chain, beacon_blocks_request.start_slot)
            return get_blocks_from_fork_chain_by_root(
                chain,
                beacon_blocks_request.start_slot,
                requested_head_block,
                slot_of_requested_blocks,
            )