Skip to content

Commit

Permalink
Fix #18
Browse files Browse the repository at this point in the history
  • Loading branch information
nalepae committed Jul 27, 2023
1 parent 1c8269d commit fdac197
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 86 deletions.
10 changes: 8 additions & 2 deletions eth_validator_watcher/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
NB_SLOT_PER_EPOCH,
SLOT_FOR_MISSED_ATTESTATIONS_PROCESS,
SLOT_FOR_REWARDS_PROCESS,
LimitedDict,
Slack,
get_our_pubkeys,
slots,
Expand Down Expand Up @@ -233,6 +234,7 @@ def _handler(

last_missed_attestations_process_epoch: Optional[int] = None
last_rewards_process_epoch: Optional[int] = None
epoch_to_our_active_index_to_validator = LimitedDict(2)

genesis = beacon.get_genesis()

Expand Down Expand Up @@ -278,6 +280,10 @@ def _handler(
| our_status_to_index_to_validator.get(StatusEnum.activeSlashed, {})
)

epoch_to_our_active_index_to_validator[
epoch
] = our_active_index_to_validator

our_active_validators_gauge.set(len(our_active_index_to_validator))

our_exited_unslashed_index_to_validator = (
Expand Down Expand Up @@ -356,14 +362,14 @@ def _handler(
if should_process_missed_attestations:
our_validators_indexes_that_missed_attestation = (
process_missed_attestations(
beacon, beacon_type, our_active_index_to_validator, epoch
beacon, beacon_type, epoch_to_our_active_index_to_validator, epoch
)
)

process_double_missed_attestations(
our_validators_indexes_that_missed_attestation,
our_validators_indexes_that_missed_previous_attestation,
our_active_index_to_validator,
epoch_to_our_active_index_to_validator,
epoch,
slack,
)
Expand Down
38 changes: 23 additions & 15 deletions eth_validator_watcher/missed_attestations.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from .beacon import Beacon
from .models import Validators
from .utils import Slack
from .utils import LimitedDict, Slack

print = functools.partial(print, flush=True)

Expand All @@ -27,20 +27,27 @@
def process_missed_attestations(
beacon: Beacon,
beacon_type: BeaconType,
our_active_index_to_validator: dict[int, Validators.DataItem.Validator],
epoch_to_index_to_validator_index: LimitedDict,
epoch: int,
) -> set[int]:
"""Process missed attestations.
Parameters:
beacon : Beacon instance
beacon_type : Beacon type
our_active_index_to_validator: Dictionary with:
key : our active validator index
value: validator data corresponding to the validator index
epoch_to_index_to_validator : Limited dictionary with:
outer key : epoch
outer value, inner key: validator indexes
inner value : validators
epoch : Epoch where the missed attestations are checked
"""
validators_index = set(our_active_index_to_validator)
index_to_validator: dict[int, Validators.DataItem.Validator] = (
epoch_to_index_to_validator_index[epoch - 1]
if epoch - 1 in epoch_to_index_to_validator_index
else epoch_to_index_to_validator_index[epoch]
)

validators_index = set(index_to_validator)
validators_liveness = beacon.get_validators_liveness(
beacon_type, epoch - 1, validators_index
)
Expand All @@ -57,8 +64,7 @@ def process_missed_attestations(
first_indexes = list(dead_indexes)[:5]

first_pubkeys = (
our_active_index_to_validator[first_index].pubkey
for first_index in first_indexes
index_to_validator[first_index].pubkey for first_index in first_indexes
)

short_first_pubkeys = [pubkey[:10] for pubkey in first_pubkeys]
Expand All @@ -76,7 +82,7 @@ def process_missed_attestations(
def process_double_missed_attestations(
dead_indexes: set[int],
previous_dead_indexes: set[int],
our_active_index_to_validator: dict[int, Validators.DataItem.Validator],
epoch_to_index_to_validator_index: LimitedDict,
epoch: int,
slack: Optional[Slack],
) -> Set[int]:
Expand All @@ -87,24 +93,26 @@ def process_double_missed_attestations(
attestations
previous_dead_indexes : Set of indexes of the validators that missed
attestations in the previous epoch
our_active_index_to_validator: Dictionary with:
key : our active validator index
value: validator data corresponding to the validator index
epoch_to_index_to_validator : Limited dictionary with:
outer key : epoch
outer value, inner key: validator indexes
inner value : validators
epoch : Epoch where the missed attestations are checked
slack : Slack instance
"""
double_dead_indexes = dead_indexes & previous_dead_indexes

double_missed_attestations_count.set(len(double_dead_indexes))

if len(double_dead_indexes) == 0:
return set()

index_to_validator = epoch_to_index_to_validator_index[epoch - 1]
first_indexes = list(double_dead_indexes)[:5]

first_pubkeys = (
our_active_index_to_validator[first_index].pubkey
for first_index in first_indexes
index_to_validator[first_index].pubkey for first_index in first_indexes
)

short_first_pubkeys = [pubkey[:10] for pubkey in first_pubkeys]
Expand Down
24 changes: 24 additions & 0 deletions eth_validator_watcher/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,27 @@ def eth2_address_0x_prefixed(address: str) -> str:
return f"0x{address}"

return address


class LimitedDict:
def __init__(self, max_size: int) -> None:
assert max_size >= 0, "max_size must be non-negative"

self.__max_size = max_size
self.__dict: dict[Any, Any] = dict()

def __setitem__(self, key: Any, value: Any) -> None:
self.__dict[key] = value

first_keys = sorted(self.__dict)[: -self.__max_size]
for key in first_keys:
self.__dict.pop(key)

def __getitem__(self, key: Any) -> Any:
return self.__dict[key]

def __contains__(self, key: Any) -> bool:
return key in self.__dict

def __len__(self) -> int:
return len(self.__dict)
10 changes: 5 additions & 5 deletions tests/entrypoint/test__handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from eth_validator_watcher import entrypoint
from eth_validator_watcher.entrypoint import _handler
from eth_validator_watcher.models import BeaconType, Genesis, Validators
from eth_validator_watcher.utils import Slack
from eth_validator_watcher.utils import LimitedDict, Slack

StatusEnum = Validators.DataItem.StatusEnum
Validator = Validators.DataItem.Validator
Expand Down Expand Up @@ -185,12 +185,12 @@ def get_our_pubkeys(pubkeys_file_path: Path, web3signer: Web3Signer) -> set[str]
def process_missed_attestations(
beacon: Beacon,
beacon_type: BeaconType,
index_to_validator: dict[int, Validator],
epoch_to_index_to_validator_index: LimitedDict,
epoch: int,
) -> set[int]:
assert isinstance(beacon, Beacon)
assert beacon_type is BeaconType.TEKU
assert index_to_validator == {
assert epoch_to_index_to_validator_index[1] == {
0: Validator(pubkey="0xaaa", effective_balance=32000000000, slashed=False),
2: Validator(pubkey="0xccc", effective_balance=32000000000, slashed=False),
4: Validator(pubkey="0xeee", effective_balance=32000000000, slashed=False),
Expand All @@ -202,13 +202,13 @@ def process_missed_attestations(
def process_double_missed_attestations(
indexes_that_missed_attestation: set[int],
indexes_that_previously_missed_attestation: set[int],
index_to_validator: dict[int, str],
epoch_to_index_to_validator_index: LimitedDict,
epoch: int,
slack: Slack,
) -> set[int]:
assert indexes_that_missed_attestation == {0, 4}
assert indexes_that_previously_missed_attestation == set()
assert index_to_validator == {
assert epoch_to_index_to_validator_index[1] == {
0: Validator(pubkey="0xaaa", effective_balance=32000000000, slashed=False),
2: Validator(pubkey="0xccc", effective_balance=32000000000, slashed=False),
4: Validator(pubkey="0xeee", effective_balance=32000000000, slashed=False),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from eth_validator_watcher.missed_attestations import process_double_missed_attestations
from eth_validator_watcher.models import Validators
from eth_validator_watcher.utils import LimitedDict

Validator = Validators.DataItem.Validator

Expand All @@ -16,29 +17,20 @@ def send_message(self, _: str) -> None:

slack = Slack()

epoch_to_index_to_validator_index = LimitedDict(2)
epoch_to_index_to_validator_index[1663] = {
40: Validator(pubkey="pubkey40", effective_balance=32000000000, slashed=False),
41: Validator(pubkey="pubkey41", effective_balance=32000000000, slashed=False),
42: Validator(pubkey="pubkey42", effective_balance=32000000000, slashed=False),
43: Validator(pubkey="pubkey43", effective_balance=32000000000, slashed=False),
44: Validator(pubkey="pubkey44", effective_balance=32000000000, slashed=False),
45: Validator(pubkey="pubkey45", effective_balance=32000000000, slashed=False),
}

actual = process_double_missed_attestations(
{42, 43, 44, 45},
{40, 41, 42, 43},
{
40: Validator(
pubkey="pubkey40", effective_balance=32000000000, slashed=False
),
41: Validator(
pubkey="pubkey41", effective_balance=32000000000, slashed=False
),
42: Validator(
pubkey="pubkey42", effective_balance=32000000000, slashed=False
),
43: Validator(
pubkey="pubkey43", effective_balance=32000000000, slashed=False
),
44: Validator(
pubkey="pubkey44", effective_balance=32000000000, slashed=False
),
45: Validator(
pubkey="pubkey45", effective_balance=32000000000, slashed=False
),
},
epoch_to_index_to_validator_index,
1664,
slack, # type: ignore
)
Expand All @@ -49,29 +41,20 @@ def send_message(self, _: str) -> None:


def test_process_double_missed_attestations_no_dead_indexes() -> None:
epoch_to_index_to_validator_index = LimitedDict(2)
epoch_to_index_to_validator_index[1663] = {
40: Validator(pubkey="pubkey40", effective_balance=32000000000, slashed=False),
41: Validator(pubkey="pubkey41", effective_balance=32000000000, slashed=False),
42: Validator(pubkey="pubkey42", effective_balance=32000000000, slashed=False),
43: Validator(pubkey="pubkey43", effective_balance=32000000000, slashed=False),
44: Validator(pubkey="pubkey44", effective_balance=32000000000, slashed=False),
45: Validator(pubkey="pubkey45", effective_balance=32000000000, slashed=False),
}

actual = process_double_missed_attestations(
{44, 45},
{40, 41},
{
40: Validator(
pubkey="pubkey40", effective_balance=32000000000, slashed=False
),
41: Validator(
pubkey="pubkey41", effective_balance=32000000000, slashed=False
),
42: Validator(
pubkey="pubkey42", effective_balance=32000000000, slashed=False
),
43: Validator(
pubkey="pubkey43", effective_balance=32000000000, slashed=False
),
44: Validator(
pubkey="pubkey44", effective_balance=32000000000, slashed=False
),
45: Validator(
pubkey="pubkey45", effective_balance=32000000000, slashed=False
),
},
epoch_to_index_to_validator_index,
1664,
None,
)
Expand Down
42 changes: 18 additions & 24 deletions tests/missed_attestations/test_process_missed_attestations.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import Set

from eth_validator_watcher.missed_attestations import \
process_missed_attestations
from eth_validator_watcher.missed_attestations import process_missed_attestations
from eth_validator_watcher.models import BeaconType, Validators
from eth_validator_watcher.utils import LimitedDict

Validator = Validators.DataItem.Validator

Expand All @@ -21,20 +21,17 @@ def get_validators_liveness(

expected = {42, 44}

epoch_to_index_to_validator_client = LimitedDict(2)
epoch_to_index_to_validator_client[0] = {
42: Validator(pubkey="pubkey42", effective_balance=32000000000, slashed=False),
43: Validator(pubkey="pubkey43", effective_balance=32000000000, slashed=False),
44: Validator(pubkey="pubkey44", effective_balance=32000000000, slashed=False),
}

actual = process_missed_attestations(
beacon=Beacon(), # type: ignore
beacon_type=BeaconType.TEKU,
our_active_index_to_validator={
42: Validator(
pubkey="pubkey42", effective_balance=32000000000, slashed=False
),
43: Validator(
pubkey="pubkey43", effective_balance=32000000000, slashed=False
),
44: Validator(
pubkey="pubkey44", effective_balance=32000000000, slashed=False
),
},
epoch_to_index_to_validator_index=epoch_to_index_to_validator_client,
epoch=1,
)

Expand All @@ -55,20 +52,17 @@ def get_validators_liveness(

expected: Set[int] = set()

epoch_to_index_to_validator_client = LimitedDict(2)
epoch_to_index_to_validator_client[0] = {
42: Validator(pubkey="pubkey42", effective_balance=32000000000, slashed=False),
43: Validator(pubkey="pubkey43", effective_balance=32000000000, slashed=False),
44: Validator(pubkey="pubkey44", effective_balance=32000000000, slashed=False),
}

actual = process_missed_attestations(
beacon=Beacon(), # type: ignore
beacon_type=BeaconType.TEKU,
our_active_index_to_validator={
42: Validator(
pubkey="pubkey42", effective_balance=32000000000, slashed=False
),
43: Validator(
pubkey="pubkey43", effective_balance=32000000000, slashed=False
),
44: Validator(
pubkey="pubkey44", effective_balance=32000000000, slashed=False
),
},
epoch_to_index_to_validator_index=epoch_to_index_to_validator_client,
epoch=1,
)

Expand Down
Loading

0 comments on commit fdac197

Please sign in to comment.