Skip to content

Commit

Permalink
Add more useful ENR.__str__ implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
pipermerriam committed Oct 21, 2020
1 parent d58b537 commit 39ae2e8
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 5 deletions.
4 changes: 4 additions & 0 deletions eth_enr/constants.py
Expand Up @@ -2,8 +2,12 @@
ENR_REPR_PREFIX = "enr:" # prefix used when printing an ENR
MAX_ENR_SIZE = 300 # maximum allowed size of an ENR
IP_V4_ADDRESS_ENR_KEY = b"ip"
IP_V6_ADDRESS_ENR_KEY = b"ip6"
UDP_PORT_ENR_KEY = b"udp"
TCP_PORT_ENR_KEY = b"tcp"

V4 = b"v4"
V4_SIGNATURE_KEY = b"secp256k1"

IP_V4_SIZE = 4 # size of an IPv4 address
IP_V6_SIZE = 16 # size of an IPv6 address
48 changes: 45 additions & 3 deletions eth_enr/enr.py
@@ -1,9 +1,10 @@
import base64
import ipaddress
import operator
from typing import AbstractSet, Any, Iterator, Mapping, Tuple, Type, ValuesView
from typing import AbstractSet, Any, Iterator, Mapping, Tuple, Type, Union, ValuesView

from eth_typing import NodeID
from eth_utils import ValidationError
from eth_utils import ValidationError, encode_hex
import rlp

from eth_enr.abc import (
Expand All @@ -13,7 +14,13 @@
IdentitySchemeRegistryAPI,
UnsignedENRAPI,
)
from eth_enr.constants import ENR_REPR_PREFIX, IDENTITY_SCHEME_ENR_KEY
from eth_enr.constants import (
ENR_REPR_PREFIX,
IDENTITY_SCHEME_ENR_KEY,
IP_V4_ADDRESS_ENR_KEY,
IP_V6_ADDRESS_ENR_KEY,
V4_SIGNATURE_KEY,
)
from eth_enr.exceptions import UnknownIdentityScheme
from eth_enr.identity_schemes import (
default_identity_scheme_registry as default_id_scheme_registry,
Expand Down Expand Up @@ -136,6 +143,32 @@ def __hash__(self) -> int:
return hash((self.sequence_number, sorted_key_value_pairs))


def _get_display_str(item: Union[int, bytes]) -> str:
if isinstance(item, bytes):
try:
return item.decode("ascii")
except UnicodeDecodeError:
return encode_hex(item)
elif isinstance(item, int):
return str(item)
else:
raise Exception("Unreachable")


def pretty_print_enr_item(key: bytes, value: Union[int, bytes]) -> str:
if key == IDENTITY_SCHEME_ENR_KEY:
return f"id={_get_display_str(value)}"
elif key == V4_SIGNATURE_KEY:
return f"secp256k1={encode_hex(value)}" # type: ignore
elif key == IP_V4_ADDRESS_ENR_KEY and isinstance(value, bytes) and len(value) == 4:
return f"ip={ipaddress.ip_address(value)}"
elif key == IP_V6_ADDRESS_ENR_KEY and isinstance(value, bytes) and len(value) == 16:
return f"ip={ipaddress.ip_address(value)}"

# final fallback if none of the *fancy* display options work.
return f"{_get_display_str(key)}={_get_display_str(value)}"


class ENR(ENRCommon, ENRSedes, ENRAPI):
def __init__(
self,
Expand Down Expand Up @@ -182,6 +215,15 @@ def __hash__(self) -> int:
sorted_key_value_pairs = tuple(sorted(self.items(), key=operator.itemgetter(0)))
return hash((self.signature, self.sequence_number, sorted_key_value_pairs))

def __str__(self) -> str:
kv_pairs = " ".join(
(pretty_print_enr_item(key, value) for key, value in sorted(self.items()))
)
return (
f"ENR: seq={self.sequence_number} node_id={self.node_id.hex()} "
f"sig={self.signature.hex()} KV: {kv_pairs}"
)

def __repr__(self) -> str:
base64_rlp = base64.urlsafe_b64encode(rlp.encode(self))
unpadded_base64_rlp = base64_rlp.rstrip(b"=")
Expand Down
5 changes: 3 additions & 2 deletions eth_enr/identity_schemes.py
Expand Up @@ -12,6 +12,7 @@
IdentitySchemeAPI,
IdentitySchemeRegistryAPI,
)
from eth_enr.constants import V4, V4_SIGNATURE_KEY


class IdentitySchemeRegistry(IdentitySchemeRegistryAPI):
Expand Down Expand Up @@ -40,8 +41,8 @@ def register(
@discv4_identity_scheme_registry.register
class V4IdentityScheme(IdentitySchemeAPI):

id = b"v4"
public_key_enr_key = b"secp256k1"
id = V4
public_key_enr_key = V4_SIGNATURE_KEY

private_key_size = 32

Expand Down

0 comments on commit 39ae2e8

Please sign in to comment.