Exemple #1
0
def skip_candidate_if_on_list_or_fork_mismatch(genesis_hash: Hash32,
                                               head: BlockNumber,
                                               fork_blocks: Tuple[BlockNumber,
                                                                  ...],
                                               skip_list: Container[NodeID],
                                               candidate: NodeAPI) -> bool:
    if skip_candidate_if_on_list(skip_list, candidate):
        return True

    # For now we accept candidates which don't specify a ForkID in their ENR, but we may want to
    # change that if we realize we're getting too many chain-mismatch errors when connecting.
    candidate_forkid = extract_forkid(candidate.enr)
    if candidate_forkid is None:
        p2p_logger.debug("Accepting connection candidate (%s) with no ForkID",
                         candidate)
        return False

    try:
        validate_forkid(candidate_forkid, genesis_hash, head, fork_blocks)
    except BaseForkIDValidationError as e:
        p2p_logger.debug(
            "Skipping forkid-incompatible connection candidate (%s): %s",
            candidate, e)
        return True

    p2p_logger.debug("Accepting forkid-compatible connection candidate (%s)",
                     candidate)
    return False
Exemple #2
0
def test_forkid_validation(local_head, remote_forkid, expected_error):
    fork_blocks = extract_fork_blocks(MAINNET_VM_CONFIGURATION)
    if expected_error:
        with pytest.raises(expected_error):
            validate_forkid(remote_forkid, MAINNET_GENESIS_HASH, local_head, fork_blocks)
    else:
        validate_forkid(remote_forkid, MAINNET_GENESIS_HASH, local_head, fork_blocks)
Exemple #3
0
def test_skip_candidate_if_on_list_or_fork_mismatch():
    mainnet_fork_blocks = forkid.extract_fork_blocks(MAINNET_VM_CONFIGURATION)
    should_skip_fn = functools.partial(
        skip_candidate_if_on_list_or_fork_mismatch,
        MAINNET_GENESIS_HEADER.hash,
        MAINNET_GENESIS_HEADER.block_number,
        mainnet_fork_blocks,
    )
    no_forkid_nodes = NodeFactory.create_batch(10)
    compatible_node = _make_node_with_enr_and_forkid(
        MAINNET_GENESIS_HEADER.hash, MAINNET_GENESIS_HEADER.block_number,
        MAINNET_VM_CONFIGURATION)
    # Ensure compatible_node's forkid is compatible with our current chain state.
    forkid.validate_forkid(
        forkid.extract_forkid(compatible_node.enr),
        MAINNET_GENESIS_HEADER.hash,
        MAINNET_GENESIS_HEADER.block_number,
        mainnet_fork_blocks,
    )

    # It returns True for candidates on the skip list, even if they are fork-id compatible.
    skip_list = [no_forkid_nodes[1].id, compatible_node.id]
    assert functools.partial(should_skip_fn,
                             skip_list)(compatible_node) is True
    assert functools.partial(should_skip_fn, skip_list)(
        no_forkid_nodes[1]) is True

    # It returns False for candidates with no fork-id that are not on the skip list.
    with pytest.raises(ENRMissingForkID):
        forkid.extract_forkid(no_forkid_nodes[0].enr)
    assert functools.partial(should_skip_fn, skip_list)(
        no_forkid_nodes[0]) is False

    # It returns False for candidates with compatible fork-ids that are not on the skip list
    assert functools.partial(should_skip_fn, [])(compatible_node) is False

    # It returns True for candidates with incompatible fork-ids
    incompatible_node = _make_node_with_enr_and_forkid(
        ROPSTEN_GENESIS_HEADER.hash, ROPSTEN_GENESIS_HEADER.block_number,
        ROPSTEN_VM_CONFIGURATION)
    with pytest.raises(BaseForkIDValidationError):
        forkid.validate_forkid(
            forkid.extract_forkid(incompatible_node.enr),
            MAINNET_GENESIS_HEADER.hash,
            MAINNET_GENESIS_HEADER.block_number,
            mainnet_fork_blocks,
        )
    assert functools.partial(should_skip_fn, [])(incompatible_node) is True
Exemple #4
0
def skip_candidate_if_on_list_or_fork_mismatch(genesis_hash: Hash32,
                                               head: BlockNumber,
                                               fork_blocks: Tuple[BlockNumber,
                                                                  ...],
                                               skip_list: Container[NodeID],
                                               candidate: NodeAPI) -> bool:
    if skip_candidate_if_on_list(skip_list, candidate):
        return True

    # For now we accept candidates which don't specify a ForkID in their ENR, but we may want to
    # change that if we realize we're getting too many chain-mismatch errors when connecting.
    try:
        candidate_forkid = extract_forkid(candidate.enr)
    except ENRMissingForkID:
        p2p_logger.debug("Accepting connection candidate (%s) with no ForkID",
                         candidate)
        return False
    except MalformedMessage as e:
        # Logging as a warning just in case there's a bug in our code that fails to deserialize
        # valid ForkIDs. If this becomes too noisy, we should consider reducing the severity.
        p2p_logger.warning(
            "Unable to extract ForkID from ENR of %s (%s), accepting as connection candidate "
            "anyway",
            candidate,
            e,
        )
        return False

    try:
        validate_forkid(candidate_forkid, genesis_hash, head, fork_blocks)
    except BaseForkIDValidationError as e:
        p2p_logger.debug(
            "Skipping forkid-incompatible connection candidate (%s): %s",
            candidate, e)
        return True

    p2p_logger.debug("Accepting forkid-compatible connection candidate (%s)",
                     candidate)
    return False