예제 #1
0
 def enodeToMultiAddress(_node):
     u = urllib.parse.urlparse(_node)
     pubkey = bytearray.fromhex(u.username)
     xpub = keys.PublicKey(pubkey)
     nn = Node.from_pubkey_and_addr(xpub, Address(u.hostname, u.port,
                                                  u.port))
     nodeid = base58.b58encode(nn.id)
     return multiaddr.Multiaddr("/ip4/" + u.hostname + "/tcp/" +
                                str(u.port) + "/p2p/" +
                                nodeid.decode("utf-8"))
예제 #2
0
async def test_request_enr(nursery, manually_driven_discovery_pair):
    alice, bob = manually_driven_discovery_pair
    # Pretend that bob and alice have already bonded, otherwise bob will ignore alice's ENR
    # request.
    bob._last_pong_at[alice.this_node.id] = int(time.monotonic())

    # Add a copy of Bob's node with a stub ENR to alice's RT as later we're going to check that it
    # gets updated with the received ENR.
    bobs_node_with_stub_enr = Node.from_pubkey_and_addr(
        bob.this_node.pubkey, bob.this_node.address)
    alice._last_pong_at[bob.this_node.id] = int(time.monotonic())
    alice.enr_db.delete_enr(bobs_node_with_stub_enr.id)
    alice.enr_db.set_enr(bobs_node_with_stub_enr.enr)
    assert alice.enr_db.get_enr(bobs_node_with_stub_enr.id).sequence_number == 0

    received_enr = None
    got_enr = trio.Event()

    async def fetch_enr(event):
        nonlocal received_enr
        received_enr = await alice.request_enr(bobs_node_with_stub_enr)
        event.set()

    # Start a task in the background that requests an ENR to bob and then waits for it.
    nursery.start_soon(fetch_enr, got_enr)

    # Bob will now consume one datagram containing the ENR_REQUEST from alice, and as part of that
    # will send an ENR_RESPONSE, which will then be consumed by alice, and as part of that it will
    # be fed into the request_enr() task we're running the background.
    with trio.fail_after(0.5):
        await bob.consume_datagram()
        await alice.consume_datagram()

    with trio.fail_after(1):
        await got_enr.wait()

    validate_node_enr(bob.this_node, received_enr, sequence_number=1)
    assert alice.enr_db.get_enr(bob.this_node.id) == received_enr

    # Now, if Bob later sends us a new ENR with no endpoint information, we'll evict him from both
    # our DB and RT.
    sequence_number = bob.this_node.enr.sequence_number + 1
    new_unsigned_enr = UnsignedENR(
        sequence_number,
        kv_pairs={
            IDENTITY_SCHEME_ENR_KEY: V4IdentityScheme.id,
            V4IdentityScheme.public_key_enr_key: bob.pubkey.to_compressed_bytes(),
        }
    )
    bob.this_node = Node(new_unsigned_enr.to_signed_enr(bob.privkey.to_bytes()))

    received_enr = None
    got_new_enr = trio.Event()
    nursery.start_soon(fetch_enr, got_new_enr)
    with trio.fail_after(0.5):
        await bob.consume_datagram()
        await alice.consume_datagram()

    with trio.fail_after(1):
        await got_new_enr.wait()

    assert Node(received_enr).address is None
    assert not alice.routing._contains(bob.this_node.id, include_replacement_cache=True)
    with pytest.raises(KeyError):
        alice.enr_db.get_enr(bob.this_node.id)
예제 #3
0
NETWORKING_EVENTBUS_ENDPOINT = 'networking'
UPNP_EVENTBUS_ENDPOINT = 'upnp'
TO_NETWORKING_BROADCAST_CONFIG = BroadcastConfig(
    filter_endpoint=NETWORKING_EVENTBUS_ENDPOINT)

# Network IDs: https://ethereum.stackexchange.com/questions/17051/how-to-select-a-network-id-or-is-there-a-list-of-network-ids/17101#17101  # noqa: E501
MAINNET_NETWORK_ID = 1
ROPSTEN_NETWORK_ID = 3
GOERLI_NETWORK_ID = 5

# Default preferred enodes
DEFAULT_PREFERRED_NODES: Dict[int, Tuple[Node, ...]] = {
    MAINNET_NETWORK_ID: (
        Node.from_pubkey_and_addr(
            keys.PublicKey(
                decode_hex(
                    "1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082"
                )),  # noqa: E501
            Address("52.74.57.123", 30303, 30303)),
        Node.from_pubkey_and_addr(
            keys.PublicKey(
                decode_hex(
                    "78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d"
                )),  # noqa: E501
            Address("191.235.84.50", 30303, 30303)),
        Node.from_pubkey_and_addr(
            keys.PublicKey(
                decode_hex(
                    "ddd81193df80128880232fc1deb45f72746019839589eeb642d3d44efbb8b2dda2c1a46a348349964a6066f8afb016eb2a8c0f3c66f32fadf4370a236a4b5286"
                )),  # noqa: E501
            Address("52.231.202.145", 30303, 30303)),
        Node.from_pubkey_and_addr(
예제 #4
0
    async def receive_connection(
            cls, reader: asyncio.StreamReader, writer: asyncio.StreamWriter,
            private_key: datatypes.PrivateKey) -> TransportAPI:
        try:
            msg = await asyncio.wait_for(
                reader.readexactly(ENCRYPTED_AUTH_MSG_LEN),
                timeout=REPLY_TIMEOUT,
            )
        except asyncio.IncompleteReadError as err:
            raise HandshakeFailure(*err.args) from err

        try:
            ephem_pubkey, initiator_nonce, initiator_pubkey = decode_authentication(
                msg,
                private_key,
            )
        except DecryptionError as non_eip8_err:
            # Try to decode as EIP8
            msg_size = big_endian_to_int(msg[:2])
            remaining_bytes = msg_size - ENCRYPTED_AUTH_MSG_LEN + 2

            try:
                msg += await asyncio.wait_for(
                    reader.readexactly(remaining_bytes),
                    timeout=REPLY_TIMEOUT,
                )
            except asyncio.IncompleteReadError as err:
                raise HandshakeFailure(*err.args) from err

            try:
                ephem_pubkey, initiator_nonce, initiator_pubkey = decode_authentication(
                    msg,
                    private_key,
                )
            except DecryptionError as eip8_err:
                raise HandshakeFailure(
                    f"Failed to decrypt both EIP8 handshake: {eip8_err}  and "
                    f"non-EIP8 handshake: {non_eip8_err}")
            else:
                got_eip8 = True
        else:
            got_eip8 = False

        peername = writer.get_extra_info("peername")
        if peername is None:
            socket = writer.get_extra_info("socket")
            sockname = writer.get_extra_info("sockname")
            raise HandshakeFailure(
                "Received incoming connection with no remote information:"
                f"socket={repr(socket)}  sockname={sockname}")

        ip, socket, *_ = peername
        remote_address = Address(ip, socket, socket)

        cls.logger.debug("Receiving auth handshake from %s", remote_address)

        initiator_remote = Node.from_pubkey_and_addr(initiator_pubkey,
                                                     remote_address)

        responder = HandshakeResponder(initiator_remote, private_key, got_eip8)

        responder_nonce = secrets.token_bytes(HASH_LEN)

        auth_ack_msg = responder.create_auth_ack_message(responder_nonce)
        auth_ack_ciphertext = responder.encrypt_auth_ack_message(auth_ack_msg)

        if writer.transport.is_closing() or reader.at_eof():
            raise HandshakeFailure(
                f"Connection to {initiator_remote} is closing")

        # Use the `writer` to send the reply to the remote
        writer.write(auth_ack_ciphertext)
        await writer.drain()

        # Call `HandshakeResponder.derive_shared_secrets()` and use return values to create `Peer`
        aes_secret, mac_secret, egress_mac, ingress_mac = responder.derive_secrets(
            initiator_nonce=initiator_nonce,
            responder_nonce=responder_nonce,
            remote_ephemeral_pubkey=ephem_pubkey,
            auth_init_ciphertext=msg,
            auth_ack_ciphertext=auth_ack_ciphertext)

        transport = cls(
            remote=initiator_remote,
            private_key=private_key,
            reader=reader,
            writer=writer,
            aes_secret=aes_secret,
            mac_secret=mac_secret,
            egress_mac=egress_mac,
            ingress_mac=ingress_mac,
        )
        return transport