Example #1
0
def test_equality(identity_scheme_registry):
    base_kwargs = {
        "sequence_number": 0,
        "kv_pairs": {
            b"id": b"mock",
            b"key1": b"value1",
            b"key2": b"value2",
        },
        "signature": b"signature",
        "identity_scheme_registry": identity_scheme_registry,
    }

    base_enr = ENR(**base_kwargs)
    equal_enr = ENR(**base_kwargs)
    enr_different_sequence_number = ENR(
        **assoc(base_kwargs, "sequence_number", 1))
    enr_different_kv_pairs = ENR(
        **assoc_in(base_kwargs, ("kv_pairs", b"key1"), b"value2"), )
    enr_different_signature = ENR(
        **assoc(base_kwargs, "signature", b"different-signature"))

    assert base_enr == base_enr
    assert equal_enr == base_enr
    assert enr_different_sequence_number != base_enr
    assert enr_different_kv_pairs != base_enr
    assert enr_different_signature != base_enr
Example #2
0
def test_signature_scheme_selection(mock_identity_scheme, identity_scheme_registry):
    mock_enr = ENR(0, {b"id": b"mock"}, b"", identity_scheme_registry)
    assert mock_enr.identity_scheme is mock_identity_scheme

    v4_enr = ENR(0, {b"id": b"v4", b"secp256k1": b"\x02" * 33}, b"", identity_scheme_registry)
    assert v4_enr.identity_scheme is V4IdentityScheme

    with pytest.raises(ValidationError):
        ENR(0, {b"id": b"other"}, b"", identity_scheme_registry)
Example #3
0
def test_auth_header_preparation(tag,
                                 auth_tag,
                                 initiator_key,
                                 auth_response_key,
                                 ephemeral_pubkey):
    enr = ENR(
        sequence_number=1,
        signature=b"",
        kv_pairs={
            b"id": b"v4",
        }
    )
    message = PingMessage(
        request_id=5,
        enr_seq=enr.sequence_number,
    )
    id_nonce_signature = b"\x00" * 32

    packet = AuthHeaderPacket.prepare(
        tag=tag,
        auth_tag=auth_tag,
        message=message,
        initiator_key=initiator_key,
        id_nonce_signature=id_nonce_signature,
        auth_response_key=auth_response_key,
        enr=enr,
        ephemeral_pubkey=ephemeral_pubkey
    )

    assert packet.tag == tag
    assert packet.auth_header.auth_tag == auth_tag
    assert packet.auth_header.auth_scheme_name == AUTH_SCHEME_NAME
    assert packet.auth_header.ephemeral_pubkey == ephemeral_pubkey

    decrypted_auth_response = aesgcm_decrypt(
        key=auth_response_key,
        nonce=ZERO_NONCE,
        cipher_text=packet.auth_header.encrypted_auth_response,
        authenticated_data=tag,
    )
    decoded_auth_response = rlp.decode(decrypted_auth_response)
    assert is_list_like(decoded_auth_response) and len(decoded_auth_response) == 2
    assert decoded_auth_response[0] == id_nonce_signature
    assert ENR.deserialize(decoded_auth_response[1]) == enr

    decrypted_message = aesgcm_decrypt(
        key=initiator_key,
        nonce=auth_tag,
        cipher_text=packet.encrypted_message,
        authenticated_data=b"".join((
            tag,
            rlp.encode(packet.auth_header),
        ))
    )
    assert decrypted_message[0] == message.message_type
    assert rlp.decode(decrypted_message[1:], PingMessage) == message
Example #4
0
def test_mapping_interface(identity_scheme_registry):
    kv_pairs = {
        b"id": b"mock",
        b"key1": b"value1",
        b"key2": b"value2",
    }
    enr = ENR(
        signature=b"",
        sequence_number=0,
        kv_pairs=kv_pairs,
        identity_scheme_registry=identity_scheme_registry,
    )

    for key, value in kv_pairs.items():
        assert key in enr
        assert enr[key] == value
        assert enr.get(key) == value

    not_a_key = b"key3"
    assert not_a_key not in kv_pairs
    assert not_a_key not in enr
    enr.get(not_a_key) is None
    assert enr.get(not_a_key, b"default") == b"default"

    assert tuple(enr.keys()) == tuple(kv_pairs.keys())
    assert tuple(enr.values()) == tuple(kv_pairs.values())
    assert tuple(enr.items()) == tuple(kv_pairs.items())

    assert len(enr) == len(kv_pairs)

    assert tuple(iter(enr)) == tuple(iter(kv_pairs))
Example #5
0
 async def recv_enr_response(self, node: NodeAPI, payload: Sequence[Any],
                             msg_hash: Hash32) -> None:
     # The enr_response payload should have at least two elements: request_hash, enr.
     if len(payload) < 2:
         self.logger.warning(
             'Ignoring ENR_RESPONSE msg with invalid payload: %s', payload)
         return
     token, serialized_enr = payload[:2]
     try:
         enr = ENR.deserialize(serialized_enr)
     except DeserializationError as error:
         raise ValidationError(
             "ENR in response is not properly encoded") from error
     try:
         channel = self.enr_response_channels.get_channel(node)
     except KeyError:
         self.logger.debug("Unexpected ENR_RESPONSE from %s", node)
         return
     enr.validate_signature()
     self.logger.debug(
         "Received ENR %s (%s) with expected response token: %s", enr,
         enr.items(), encode_hex(token))
     try:
         await channel.send((enr, token))
     except trio.BrokenResourceError:
         # This means the receiver has already closed, probably because it timed out.
         pass
Example #6
0
def test_extract_forkid():
    enr = ENR.from_repr(
        "enr:-Jq4QO5zEyIBU5lSa9iaen0A2xUB5_IVrCi1DbyASTTnLV5RJan6aGPr8kU0p0MYKU5YezZgdSUE"
        "-GOBEio6Ultyf1Aog2V0aMrJhGN2AZCDGfCggmlkgnY0gmlwhF4_wLuJc2VjcDI1NmsxoQOt7cA_B_Kg"
        "nQ5RmwyA6ji8M1Y0jfINItRGbOOwy7XgbIN0Y3CCdl-DdWRwgnZf")
    assert extract_forkid(enr) == ForkID(hash=to_bytes(hexstr='0x63760190'),
                                         next=1700000)
Example #7
0
async def test_file_db_saves_enrs(file_db_dir, file_db):
    enr = ENRFactory()
    await file_db.insert(enr)
    filename = get_enr_filename(enr)
    assert (file_db_dir / filename).exists()
    assert (file_db_dir / filename).is_file()
    assert ENR.from_repr((file_db_dir / filename).read_text()) == enr
Example #8
0
def enr():
    return ENR(
        sequence_number=1,
        signature=b"",
        kv_pairs={
            b"id": b"v4",
        }
    )
Example #9
0
def test_real_life_test_vector():
    enr = ENR.from_repr(REAL_LIFE_TEST_DATA["repr"])

    assert enr.sequence_number == REAL_LIFE_TEST_DATA["sequence_number"]
    assert enr.public_key == REAL_LIFE_TEST_DATA["public_key"]
    assert enr.node_id == REAL_LIFE_TEST_DATA["node_id"]
    assert enr.identity_scheme is REAL_LIFE_TEST_DATA["identity_scheme"]
    assert dict(enr) == REAL_LIFE_TEST_DATA["kv_pairs"]
    assert repr(enr) == REAL_LIFE_TEST_DATA["repr"]
Example #10
0
def enr():
    return ENR(sequence_number=1,
               signature=b"",
               kv_pairs={
                   b"id":
                   b"v4",
                   b"secp256k1":
                   PrivateKey(b"\x01" * 32).public_key.to_compressed_bytes(),
               })
Example #11
0
    def decrypt_auth_response(
            self, auth_response_key: AES128Key) -> Tuple[bytes, Optional[ENR]]:
        """Extract id nonce signature and optional ENR from auth header packet."""
        plain_text = aesgcm_decrypt(
            key=auth_response_key,
            nonce=ZERO_NONCE,
            cipher_text=self.auth_header.encrypted_auth_response,
            authenticated_data=b"",
        )

        try:
            decoded_rlp = rlp.decode(plain_text)
        except DecodingError:
            raise ValidationError(
                f"Auth response does not contain valid RLP: {encode_hex(plain_text)}"
            )

        if not is_list_like(decoded_rlp):
            raise ValidationError(
                f"Auth response contains bytes instead of list: {encode_hex(decoded_rlp)}"
            )

        if len(decoded_rlp) != 3:
            raise ValidationError(
                f"Auth response is a list of {len(decoded_rlp)} instead of three elements"
            )
        version_bytes, id_nonce_signature, serialized_enr = decoded_rlp

        if not is_bytes(version_bytes):
            raise ValidationError(
                f"Version is a list instead of big endian encoded integer: {version_bytes}"
            )
        version_int = big_endian_to_int(version_bytes)
        if version_int != AUTH_RESPONSE_VERSION:
            raise ValidationError(
                f"Expected auth response version {AUTH_RESPONSE_VERSION}, but got {version_int}"
            )

        if not is_bytes(id_nonce_signature):
            raise ValidationError(
                f"Id nonce signature is a list instead of bytes: {id_nonce_signature}"
            )

        if not is_list_like(serialized_enr):
            raise ValidationError(
                f"ENR is bytes instead of list: {encode_hex(serialized_enr)}")

        if len(serialized_enr) == 0:
            enr = None
        else:
            try:
                enr = ENR.deserialize(serialized_enr)
            except DeserializationError as error:
                raise ValidationError(
                    "ENR in auth response is not properly encoded") from error

        return id_nonce_signature, enr
Example #12
0
def test_inititialization(identity_scheme_registry):
    valid_sequence_number = 0
    valid_kv_pairs = {b"id": b"mock"}
    valid_signature = b""  # signature is not validated during initialization

    assert UnsignedENR(
        sequence_number=valid_sequence_number,
        kv_pairs=valid_kv_pairs,
        identity_scheme_registry=identity_scheme_registry,
    )
    assert ENR(
        sequence_number=valid_sequence_number,
        kv_pairs=valid_kv_pairs,
        signature=valid_signature,
        identity_scheme_registry=identity_scheme_registry,
    )

    with pytest.raises(ValidationError):
        UnsignedENR(
            sequence_number=valid_sequence_number,
            kv_pairs={b"no-id": b""},
            identity_scheme_registry=identity_scheme_registry,
        )
    with pytest.raises(ValidationError):
        ENR(
            sequence_number=valid_sequence_number,
            kv_pairs={b"no-id": b""},
            signature=valid_signature,
            identity_scheme_registry=identity_scheme_registry,
        )

    with pytest.raises(ValidationError):
        UnsignedENR(
            sequence_number=-1,
            kv_pairs=valid_kv_pairs,
            identity_scheme_registry=identity_scheme_registry,
        )
    with pytest.raises(ValidationError):
        ENR(
            sequence_number=-1,
            kv_pairs=valid_kv_pairs,
            signature=valid_signature,
            identity_scheme_registry=identity_scheme_registry,
        )
Example #13
0
def test_repr(mock_identity_scheme, identity_scheme_registry):
    unsigned_enr = UnsignedENR(0, {b"id": b"mock"}, identity_scheme_registry)
    enr = unsigned_enr.to_signed_enr(b"\x00" * 32)
    base64_encoded_enr = base64.urlsafe_b64encode(rlp.encode(enr))
    represented_enr = repr(enr)

    assert represented_enr.startswith("enr:")
    assert base64_encoded_enr.rstrip(b"=").decode() == represented_enr[4:]

    assert ENR.from_repr(represented_enr, identity_scheme_registry) == enr
Example #14
0
def test_enr_v4_compat_signature_validation():
    private_key = PrivateKey(b"\x11" * 32)
    enr = ENR(
        0,
        {
            b"id": b"v4-compat",
            b"secp256k1": private_key.public_key.to_compressed_bytes(),
            b"key1": b"value1",
        },
        signature=b'')

    V4CompatIdentityScheme.validate_enr_signature(enr)
Example #15
0
def test_signature_validation(mock_identity_scheme, identity_scheme_registry):
    unsigned_enr = UnsignedENR(0, {b"id": b"mock"}, identity_scheme_registry)
    private_key = b"\x00" * 32
    enr = unsigned_enr.to_signed_enr(private_key)
    enr.validate_signature()

    invalid_signature = b"\xff" * 64
    invalid_enr = ENR(enr.sequence_number,
                      dict(enr),
                      invalid_signature,
                      identity_scheme_registry=identity_scheme_registry)
    with pytest.raises(ValidationError):
        invalid_enr.validate_signature()

    with pytest.raises(ValidationError):
        ENR(
            0,
            {b"id": b"unknown"},
            b"",
            identity_scheme_registry=identity_scheme_registry,
        )
Example #16
0
def test_official_test_vector():
    enr = ENR.from_repr(OFFICIAL_TEST_DATA["repr"])  # use default identity scheme registry

    assert enr.sequence_number == OFFICIAL_TEST_DATA["sequence_number"]
    assert dict(enr) == OFFICIAL_TEST_DATA["kv_pairs"]
    assert enr.public_key == OFFICIAL_TEST_DATA["public_key"]
    assert enr.node_id == OFFICIAL_TEST_DATA["node_id"]
    assert enr.identity_scheme is OFFICIAL_TEST_DATA["identity_scheme"]
    assert repr(enr) == OFFICIAL_TEST_DATA["repr"]

    unsigned_enr = UnsignedENR(enr.sequence_number, dict(enr))
    reconstructed_enr = unsigned_enr.to_signed_enr(OFFICIAL_TEST_DATA["private_key"])
    assert reconstructed_enr == enr
Example #17
0
def test_enr_signature_validation():
    private_key = PrivateKey(b"\x11" * 32)
    unsigned_enr = UnsignedENR(0, {
        b"id": b"v4",
        b"secp256k1": private_key.public_key.to_compressed_bytes(),
        b"key1": b"value1",
    })
    enr = unsigned_enr.to_signed_enr(private_key.to_bytes())

    V4IdentityScheme.validate_enr_signature(enr)

    forged_enr = ENR(enr.sequence_number, dict(enr), b"\x00" * 64)
    with pytest.raises(ValidationError):
        V4IdentityScheme.validate_enr_signature(forged_enr)
Example #18
0
 def _init(self, enr: ENR) -> None:
     try:
         ip = enr[IP_V4_ADDRESS_ENR_KEY]
         udp_port = enr[UDP_PORT_ENR_KEY]
     except KeyError:
         self._address = None
     else:
         tcp_port = enr.get(TCP_PORT_ENR_KEY, udp_port)
         self._address = Address(ip, udp_port, tcp_port)
     # FIXME: ENRs may use different pubkey formats and this would break, so instead of storing
     # a PublicKey with a certain format here we should simply use the APIs in the
     # ENR.identity_scheme for the crypto related operations.
     self._pubkey = keys.PublicKey.from_compressed_bytes(enr.public_key)
     self._id = NodeID(keccak(self.pubkey.to_bytes()))
     self._id_int = big_endian_to_int(self.id)
     self._enr = enr
Example #19
0
 def from_pubkey_and_addr(cls: Type[TNode], pubkey: datatypes.PublicKey,
                          address: AddressAPI) -> TNode:
     enr = ENR(0, {
         IDENTITY_SCHEME_ENR_KEY:
         V4CompatIdentityScheme.id,
         V4CompatIdentityScheme.public_key_enr_key:
         pubkey.to_compressed_bytes(),
         IP_V4_ADDRESS_ENR_KEY:
         address.ip_packed,
         UDP_PORT_ENR_KEY:
         address.udp_port,
         TCP_PORT_ENR_KEY:
         address.tcp_port,
     },
               signature=b'')
     return cls(enr)
Example #20
0
    def decrypt_auth_response(
            self, auth_response_key: AES128Key) -> Tuple[bytes, Optional[ENR]]:
        """Extract id nonce signature and optional ENR from auth header packet."""
        plain_text = aesgcm_decrypt(
            key=auth_response_key,
            nonce=ZERO_NONCE,
            cipher_text=self.auth_header.encrypted_auth_response,
            authenticated_data=self.tag,
        )

        try:
            decoded_rlp = rlp.decode(plain_text)
        except DecodingError as error:
            raise ValidationError(
                f"Auth response does not contain valid RLP: {encode_hex(plain_text)}"
            )

        if not is_list_like(decoded_rlp):
            raise ValidationError(
                f"Auth response contains bytes instead of list: {encode_hex(decoded_rlp)}"
            )

        if len(decoded_rlp) != 2:
            raise ValidationError(
                f"Auth response is a list of {len(decoded_rlp)} instead of two elements"
            )
        id_nonce_signature, serialized_enr = decoded_rlp

        if not is_bytes(id_nonce_signature):
            raise ValidationError(
                f"Id nonce signature is a list instead of bytes: {id_nonce_signature}"
            )

        if not is_list_like(serialized_enr):
            raise ValidationError(
                f"ENR is bytes instead of list: {encode_hex(serialized_enr)}")

        if len(serialized_enr) == 0:
            enr = None
        else:
            try:
                enr = ENR.deserialize(serialized_enr)
            except DeserializationError as error:
                raise ValidationError(
                    "ENR in auth response is not properly encoded") from error

        return id_nonce_signature, enr
Example #21
0
def test_serialization_roundtrip(identity_scheme_registry):
    original_enr = ENR(
        sequence_number=0,
        kv_pairs={
            b"id": b"mock",
            b"key2": b"value2",  # wrong order so that serialization is forced to fix this
            b"key1": b"value1",
        },
        signature=b"",
        identity_scheme_registry=identity_scheme_registry,
    )
    encoded = rlp.encode(original_enr)
    recovered_enr = rlp.decode(
        encoded,
        ENR,
        identity_scheme_registry=identity_scheme_registry,
    )
    assert recovered_enr == original_enr
Example #22
0
 async def recv_enr_request(self, node: NodeAPI, payload: Sequence[Any],
                            msg_hash: Hash32) -> None:
     # The enr_request payload should have at least one element: expiration.
     if len(payload) < 1:
         self.logger.warning(
             'Ignoring ENR_REQUEST msg with invalid payload: %s', payload)
         return
     expiration = payload[0]
     if self._is_msg_expired(expiration):
         return
     # XXX: Maybe reconsider this and accept all ENR requests until we have a persistent
     # routing store of nodes we've bonded with? Otherwise if a node request our ENR across a
     # restart, we'll not reply to them.
     if node not in self.routing:
         self.logger.info('Ignoring ENR_REQUEST from unknown node %s', node)
         return
     enr = await self.get_local_enr()
     self.logger.debug("Sending local ENR to %s: %s", node, enr)
     payload = (msg_hash, ENR.serialize(enr))
     self.send(node, CMD_ENR_RESPONSE, payload)
Example #23
0
 def load_enr_file(self, path: pathlib.Path) -> ENR:
     enr_base64 = path.read_text()
     enr = ENR.from_repr(enr_base64, self.identity_scheme_registry)
     return enr
Example #24
0
 def __setstate__(self, state: Dict[Any, Any]) -> None:
     self._init(ENR.from_repr(state.pop('enr')))
Example #25
0
         "request_id": 0x01,
         "total": 0x01,
         "enrs": [],
     },
     decode_hex("0x04c30101c0"),
 ],
 [
     NodesMessage,
     {
         "request_id":
         0x01,
         "total":
         0x01,
         "enrs": [
             ENR.from_repr(
                 "enr:-HW4QBzimRxkmT18hMKaAL3IcZF1UcfTMPyi3Q1pxwZZbcZVRI8DC5infUAB_UauARLOJtYTxa"
                 "agKoGmIjzQxO2qUygBgmlkgnY0iXNlY3AyNTZrMaEDymNMrg1JrLQB2KTGtv6MVbcNEVv0AHacwUAP"
                 "MljNMTg"),
             ENR.from_repr(
                 "enr:-HW4QNfxw543Ypf4HXKXdYxkyzfcxcO-6p9X986WldfVpnVTQX1xlTnWrktEWUbeTZnmgOuAY_"
                 "KUhbVV1Ft98WoYUBMBgmlkgnY0iXNlY3AyNTZrMaEDDiy3QkHAxPyOgWbxp5oF1bDdlYE6dLCUUp8x"
                 "fVw50jU"),
         ]
     },
     decode_hex(
         "0x04f8f20101f8eef875b8401ce2991c64993d7c84c29a00bdc871917551c7d330fca2dd0d69c706596dc6"
         "55448f030b98a77d4001fd46ae0112ce26d613c5a6a02a81a6223cd0c4edaa532801826964827634897365"
         "63703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138f875"
         "b840d7f1c39e376297f81d7297758c64cb37dcc5c3beea9f57f7ce9695d7d5a67553417d719539d6ae4b44"
         "5946de4d99e680eb8063f29485b555d45b7df16a1850130182696482763489736563703235366b31a1030e"
         "2cb74241c0c4fc8e8166f1a79a05d5b0dd95813a74b094529f317d5c39d235"),
 ],
Example #26
0
def extract_forkid(enr: ENR) -> ForkID:
    eth_cap = enr.get(b'eth', None)
    if eth_cap is not None:
        [forkid] = rlp.sedes.List([ForkID]).deserialize(eth_cap)
        return forkid
    return None
Example #27
0
    async def do_run(cls, boot_info: BootInfo, event_bus: EndpointAPI) -> None:
        identity_scheme_registry = default_identity_scheme_registry
        message_type_registry = default_message_type_registry

        nodedb_dir = get_nodedb_dir(boot_info)
        nodedb_dir.mkdir(exist_ok=True)
        node_db = NodeDB(default_identity_scheme_registry, LevelDB(nodedb_dir))

        local_private_key = get_local_private_key(boot_info)
        local_enr = await get_local_enr(boot_info, node_db, local_private_key)
        local_node_id = local_enr.node_id

        routing_table = KademliaRoutingTable(local_node_id,
                                             NUM_ROUTING_TABLE_BUCKETS)

        node_db.set_enr(local_enr)
        for enr_repr in boot_info.args.discovery_boot_enrs or ():
            enr = ENR.from_repr(enr_repr)
            node_db.set_enr(enr)
            routing_table.update(enr.node_id)

        port = boot_info.args.discovery_port

        socket = trio.socket.socket(
            family=trio.socket.AF_INET,
            type=trio.socket.SOCK_DGRAM,
        )
        outgoing_datagram_channels = trio.open_memory_channel[
            OutgoingDatagram](0)
        incoming_datagram_channels = trio.open_memory_channel[
            IncomingDatagram](0)
        outgoing_packet_channels = trio.open_memory_channel[OutgoingPacket](0)
        incoming_packet_channels = trio.open_memory_channel[IncomingPacket](0)
        outgoing_message_channels = trio.open_memory_channel[OutgoingMessage](
            0)
        incoming_message_channels = trio.open_memory_channel[IncomingMessage](
            0)
        endpoint_vote_channels = trio.open_memory_channel[EndpointVote](0)

        # types ignored due to https://github.com/ethereum/async-service/issues/5
        datagram_sender = DatagramSender(  # type: ignore
            outgoing_datagram_channels[1],
            socket,
        )
        datagram_receiver = DatagramReceiver(  # type: ignore
            socket,
            incoming_datagram_channels[0],
        )

        packet_encoder = PacketEncoder(  # type: ignore
            outgoing_packet_channels[1],
            outgoing_datagram_channels[0],
        )
        packet_decoder = PacketDecoder(  # type: ignore
            incoming_datagram_channels[1],
            incoming_packet_channels[0],
        )

        packer = Packer(
            local_private_key=local_private_key.to_bytes(),
            local_node_id=local_node_id,
            node_db=node_db,
            message_type_registry=message_type_registry,
            incoming_packet_receive_channel=incoming_packet_channels[1],
            incoming_message_send_channel=incoming_message_channels[0],
            outgoing_message_receive_channel=outgoing_message_channels[1],
            outgoing_packet_send_channel=outgoing_packet_channels[0],
        )

        message_dispatcher = MessageDispatcher(
            node_db=node_db,
            incoming_message_receive_channel=incoming_message_channels[1],
            outgoing_message_send_channel=outgoing_message_channels[0],
        )

        endpoint_tracker = EndpointTracker(
            local_private_key=local_private_key.to_bytes(),
            local_node_id=local_node_id,
            node_db=node_db,
            identity_scheme_registry=identity_scheme_registry,
            vote_receive_channel=endpoint_vote_channels[1],
        )

        routing_table_manager = RoutingTableManager(
            local_node_id=local_node_id,
            routing_table=routing_table,
            message_dispatcher=message_dispatcher,
            node_db=node_db,
            outgoing_message_send_channel=outgoing_message_channels[0],
            endpoint_vote_send_channel=endpoint_vote_channels[0],
        )

        logger.info(f"Starting discovery, listening on port {port}")
        logger.info(f"Local Node ID: {encode_hex(local_enr.node_id)}")
        logger.info(f"Local ENR: {local_enr}")

        await socket.bind(("0.0.0.0", port))
        services = (
            datagram_sender,
            datagram_receiver,
            packet_encoder,
            packet_decoder,
            packer,
            message_dispatcher,
            endpoint_tracker,
            routing_table_manager,
        )
        async with trio.open_nursery() as nursery:
            for service in services:
                nursery.start_soon(async_service.TrioManager.run_service,
                                   service)
Example #28
0
 def from_enr_repr(cls: Type[TNode], uri: str) -> TNode:
     return cls(ENR.from_repr(uri))