Skip to content

Commit

Permalink
Manage 0x prefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
nalepae committed Jun 28, 2023
1 parent 0cd1cd2 commit 8d49015
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 32 deletions.
17 changes: 11 additions & 6 deletions eth_validator_watcher/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
SLOT_FOR_MISSED_ATTESTATIONS_PROCESS,
Slack,
get_our_pubkeys,
is_eth1_address,
slots,
write_liveness_file,
eth1_address_0x_prefixed,
)
from .web3signer import Web3Signer

Expand Down Expand Up @@ -182,10 +182,11 @@ def _handler(
"`execution-url` must be set if you want to use `fee-recipient`"
)

if fee_recipient is not None and not is_eth1_address(fee_recipient):
raise typer.BadParameter(
"`fee-recipient` should be a valid, 0x prefixed, eth1 address"
)
if fee_recipient is not None:
try:
fee_recipient = eth1_address_0x_prefixed(fee_recipient)
except ValueError:
raise typer.BadParameter("`fee-recipient` should be a valid ETH1 address")

if slack_channel is not None and slack_token is None:
raise typer.BadParameter(
Expand Down Expand Up @@ -229,7 +230,11 @@ def _handler(
is_new_epoch = previous_epoch is None or previous_epoch != epoch

if is_new_epoch:
our_pubkeys = get_our_pubkeys(pubkeys_file_path, web3signer)
try:
our_pubkeys = get_our_pubkeys(pubkeys_file_path, web3signer)
except ValueError:
raise typer.BadParameter("Some pubkeys are invalid")

total_status_to_index_to_validator = (
beacon.get_status_to_index_to_validator()
)
Expand Down
26 changes: 23 additions & 3 deletions eth_validator_watcher/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
from prometheus_client import Gauge
from slack_sdk import WebClient

import re

from .web3signer import Web3Signer

NB_SLOT_PER_EPOCH = 32
NB_SECOND_PER_SLOT = 12
BLOCK_NOT_ORPHANED_TIME_SEC = 9
SLOT_FOR_MISSED_ATTESTATIONS_PROCESS = 16
ETH1_ADDRESS_LEN = 40
ETH2_ADDRESS_LEN = 96

keys_count = Gauge(
"keys_count",
Expand Down Expand Up @@ -151,7 +155,7 @@ def load_pubkeys_from_file(path: Path) -> set[str]:
Returns the corresponding set of public keys.
"""
with path.open() as file_descriptor:
return set((f"0x{line.strip()}" for line in file_descriptor))
return set((eth2_address_0x_prefixed(line.strip()) for line in file_descriptor))


def get_our_pubkeys(
Expand Down Expand Up @@ -218,5 +222,21 @@ def slots(genesis_time_sec: int) -> Iterator[Tuple[int, int]]:
pass # pragma: no cover


def is_eth1_address(address: str) -> bool:
return address[:2] == "0x" and len(address) == 42
def eth1_address_0x_prefixed(address: str) -> str:
if not re.match(f"^(0x)?[0-9a-fA-F]{{{ETH1_ADDRESS_LEN}}}$", address):
raise ValueError(f"Invalid ETH1 address: {address}")

if len(address) == ETH1_ADDRESS_LEN:
return f"0x{address}"

return address


def eth2_address_0x_prefixed(address: str) -> str:
if not re.match(f"^(0x)?[0-9a-fA-F]{{{ETH2_ADDRESS_LEN}}}$", address):
raise ValueError(f"Invalid ETH2 address: {address}")

if len(address) == ETH2_ADDRESS_LEN:
return f"0x{address}"

return address
44 changes: 44 additions & 0 deletions tests/entrypoint/test__handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,50 @@ def test_slack_token_not_defined() -> None:
)


def test_invalid_pubkeys() -> None:
class Beacon:
def __init__(self, url: str) -> None:
assert url == "http://localhost:5052"

def get_genesis(self) -> Genesis:
return Genesis(
data=Genesis.Data(
genesis_time=0,
genesis_fork_version="0x123",
genesis_validators_root="0xabc",
)
)

def get_our_pubkeys(pubkeys_file_path: Path, web3signer: None) -> set[str]:
assert pubkeys_file_path == Path("/path/to/pubkeys")
raise ValueError("Invalid pubkeys")

def slots(genesis_time: int) -> Iterator[Tuple[(int, int)]]:
assert genesis_time == 0
yield 63, 1664
yield 64, 1676

def start_http_server(_: int) -> None:
pass

entrypoint.get_our_pubkeys = get_our_pubkeys # type: ignore
entrypoint.Beacon = Beacon # type: ignore
entrypoint.slots = slots # type: ignore
entrypoint.start_http_server = start_http_server # type: ignore

with raises(BadParameter):
_handler(
beacon_url="http://localhost:5052",
execution_url=None,
pubkeys_file_path=Path("/path/to/pubkeys"),
web3signer_url=None,
fee_recipient=None,
slack_channel=None,
beacon_type=BeaconType.TEKU,
liveness_file=None,
)


@freeze_time("2023-01-01 00:00:00", auto_tick_seconds=15)
def test_nominal() -> None:
class Beacon:
Expand Down
6 changes: 3 additions & 3 deletions tests/utils/assets/pubkeys.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
aaa
bbb
ccc
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
29 changes: 29 additions & 0 deletions tests/utils/test_eth1_address_0x_prefixed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from eth_validator_watcher.utils import eth1_address_0x_prefixed
from pytest import raises


def test_eth1_address_0x_prefixed_invalid() -> None:
# Too short
with raises(ValueError):
eth1_address_0x_prefixed("0x123")

# Too long
with raises(ValueError):
eth1_address_0x_prefixed(
"0x123456789012345678901234567890123456789012345678901234567890123"
)

# Invalid character
with raises(ValueError):
eth1_address_0x_prefixed("0x8d8b1b85d02d05ad3a14e2e9cc7b458d5invalid")


def test_eth1_address_0x_prefixed_valid_already_prefixed() -> None:
address = "0x8d8b1b85d02d05ad3a14e2e9cc7b458d5c7d8f8c"
assert eth1_address_0x_prefixed(address) == address


def test_eth1_address_0x_prefixed_valid_not_already_prefixed() -> None:
address_without_prefix = "8d8b1b85d02d05ad3a14e2e9cc7b458d5c7d8f8c"
address_with_prefix = "0x8d8b1b85d02d05ad3a14e2e9cc7b458d5c7d8f8c"
assert eth1_address_0x_prefixed(address_without_prefix) == address_with_prefix
29 changes: 29 additions & 0 deletions tests/utils/test_eth2_address_0x_prefixed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from eth_validator_watcher.utils import eth2_address_0x_prefixed
from pytest import raises


def test_eth2_address_0x_prefixed_invalid() -> None:
# Too short
with raises(ValueError):
eth2_address_0x_prefixed("0x123")

# Too long
with raises(ValueError):
eth2_address_0x_prefixed(
"0x123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
)

# Invalid character
with raises(ValueError):
eth2_address_0x_prefixed("0x8d8b1b85d02d05ad3a14e2e9cc7b458d5invalid")


def test_eth2_address_0x_prefixed_valid_already_prefixed() -> None:
address = "0xb2ddae7e32fd8257c2dd468ca16dc86d310cab218f9a41ed6fabea525a9620d46955350776e8496553138c8a291a365b"
assert eth2_address_0x_prefixed(address) == address


def test_eth2_address_0x_prefixed_valid_not_already_prefixed() -> None:
address_without_prefix = "b2ddae7e32fd8257c2dd468ca16dc86d310cab218f9a41ed6fabea525a9620d46955350776e8496553138c8a291a365b"
address_with_prefix = "0xb2ddae7e32fd8257c2dd468ca16dc86d310cab218f9a41ed6fabea525a9620d46955350776e8496553138c8a291a365b"
assert eth2_address_0x_prefixed(address_without_prefix) == address_with_prefix
15 changes: 13 additions & 2 deletions tests/utils/test_get_our_pubkeys.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,23 @@
class Web3Signer:
@staticmethod
def load_pubkeys() -> set[str]:
return {"0xccc", "0xddd", "0xeee"}
return {
"0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
}


def test_get_our_pubkeys() -> None:
pubkey_path = Path(assets.__file__).parent / "pubkeys.txt"
web3signer = Web3Signer()

expected = {"0xaaa", "0xbbb", "0xccc", "0xddd", "0xeee"}
expected = {
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
}
assert get_our_pubkeys(pubkey_path, web3signer) == expected # type: ignore
17 changes: 0 additions & 17 deletions tests/utils/test_is_eth1_address.py

This file was deleted.

6 changes: 5 additions & 1 deletion tests/utils/test_load_pubkeys_from_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@

def test_load_pubkeys_from_file():
pubkey_path = Path(assets.__file__).parent / "pubkeys.txt"
expected = {"0xaaa", "0xbbb", "0xccc"}
expected = {
"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
}
assert load_pubkeys_from_file(pubkey_path) == expected

0 comments on commit 8d49015

Please sign in to comment.