From a50f1bd1c7002e5b141173193ec0fafc669a91fb Mon Sep 17 00:00:00 2001 From: Manu NALEPA Date: Thu, 27 Jul 2023 17:30:43 +0200 Subject: [PATCH] Fix missed rewards when a new validator enters --- eth_validator_watcher/entrypoint.py | 7 +- eth_validator_watcher/rewards.py | 22 ++- tests/entrypoint/test__handler.py | 4 +- tests/rewards/test_process_rewards.py | 198 ++++++++++++++------------ 4 files changed, 129 insertions(+), 102 deletions(-) diff --git a/eth_validator_watcher/entrypoint.py b/eth_validator_watcher/entrypoint.py index 6e6e6da..cb3df0f 100644 --- a/eth_validator_watcher/entrypoint.py +++ b/eth_validator_watcher/entrypoint.py @@ -234,7 +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) + epoch_to_our_active_index_to_validator = LimitedDict(4) genesis = beacon.get_genesis() @@ -381,7 +381,10 @@ def _handler( ) if should_process_rewards: - process_rewards(beacon, beacon_type, epoch, our_active_index_to_validator) + process_rewards( + beacon, beacon_type, epoch, epoch_to_our_active_index_to_validator + ) + last_rewards_process_epoch = epoch process_future_blocks_proposal(beacon, our_pubkeys, slot, is_new_epoch) diff --git a/eth_validator_watcher/rewards.py b/eth_validator_watcher/rewards.py index 70eec95..b11b3ba 100644 --- a/eth_validator_watcher/rewards.py +++ b/eth_validator_watcher/rewards.py @@ -4,6 +4,8 @@ from prometheus_client import Counter, Gauge +from eth_validator_watcher.utils import LimitedDict + from .beacon import Beacon from .models import BeaconType, Validators @@ -49,7 +51,7 @@ def process_rewards( beacon: Beacon, beacon_type: BeaconType, epoch: int, - index_to_validator: dict[int, Validator], + epoch_to_index_to_validator: LimitedDict, ) -> None: """Process rewards for given epoch and validators @@ -57,10 +59,22 @@ def process_rewards( beacon (Beacon): Beacon object beacon_type (BeaconType): Beacon type epoch (int): Epoch number - index_to_validator (dict[int, Validator]): Dictionary with: - key: validator index - value: Validator object + + epoch_to_index_to_validator : Limited dictionary with: + outer key : epoch + outer value, inner key: validator indexes + inner value : validators """ + index_to_validator = ( + epoch_to_index_to_validator[epoch - 2] + if epoch - 2 in epoch_to_index_to_validator + else ( + epoch_to_index_to_validator[epoch - 1] + if epoch - 1 in epoch_to_index_to_validator + else epoch_to_index_to_validator[epoch] + ) + ) + if len(index_to_validator) == 0: return diff --git a/tests/entrypoint/test__handler.py b/tests/entrypoint/test__handler.py index 1e72a87..bfdccdf 100644 --- a/tests/entrypoint/test__handler.py +++ b/tests/entrypoint/test__handler.py @@ -264,12 +264,12 @@ def process_rewards( beacon: Beacon, beacon_type: BeaconType, epoch: int, - our_active_index_to_validator: dict[int, Validator], + epoch_to_index_to_validator: dict[int, Validator], ): assert isinstance(beacon, Beacon) assert isinstance(beacon_type, BeaconType) assert epoch == 1 - assert our_active_index_to_validator == { + assert epoch_to_index_to_validator[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), diff --git a/tests/rewards/test_process_rewards.py b/tests/rewards/test_process_rewards.py index ca7ec0a..3304319 100644 --- a/tests/rewards/test_process_rewards.py +++ b/tests/rewards/test_process_rewards.py @@ -15,12 +15,16 @@ suboptimal_sources_rate_gauge, suboptimal_targets_rate_gauge, ) +from eth_validator_watcher.utils import LimitedDict Validator = Validators.DataItem.Validator def test_process_rewards_no_validator() -> None: - process_rewards(BeaconType.LIGHTHOUSE, "a beacon", 42, {}) # type: ignore + epoch_to_index_to_validator = LimitedDict(2) + epoch_to_index_to_validator[42] = {} + + process_rewards(BeaconType.LIGHTHOUSE, "a beacon", 42, epoch_to_index_to_validator) # type: ignore def test_process_rewards_empty() -> None: @@ -41,7 +45,10 @@ def get_rewards( beacon = Beacon() - process_rewards(beacon, BeaconType.PRYSM, 42, {12345: "a validator"}) # type: ignore + epoch_to_index_to_validator = LimitedDict(2) + epoch_to_index_to_validator[42] = {12345: "a validator"} + + process_rewards(beacon, BeaconType.PRYSM, 42, epoch_to_index_to_validator) # type: ignore def test_process_rewards_all_validators_are_ideal() -> None: @@ -95,27 +102,30 @@ def get_rewards( actual_negative_targets_count_before = actual_negative_targets_count.collect()[0].samples[0].value # type: ignore actual_heads_count_before = actual_heads_count.collect()[0].samples[0].value # type: ignore + epoch_to_index_to_validator = LimitedDict(2) + epoch_to_index_to_validator[42] = { + 1: Validator( + pubkey="0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + effective_balance=32_000_000_000, + slashed=False, + ), + 2: Validator( + pubkey="0x222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222", + effective_balance=31_000_000_000, + slashed=False, + ), + 3: Validator( + pubkey="0x333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", + effective_balance=32_000_000_000, + slashed=False, + ), + } + process_rewards( beacon, # type: ignore BeaconType.LIGHTHOUSE, 42, - { - 1: Validator( - pubkey="0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - effective_balance=32_000_000_000, - slashed=False, - ), - 2: Validator( - pubkey="0x222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222", - effective_balance=31_000_000_000, - slashed=False, - ), - 3: Validator( - pubkey="0x333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", - effective_balance=32_000_000_000, - slashed=False, - ), - }, + epoch_to_index_to_validator, ) ideal_sources_count_after = ideal_sources_count.collect()[0].samples[0].value # type: ignore @@ -237,62 +247,62 @@ def get_rewards( actual_negative_targets_count_before = actual_negative_targets_count.collect()[0].samples[0].value # type: ignore actual_heads_count_before = actual_heads_count.collect()[0].samples[0].value # type: ignore + epoch_to_index_to_validator = LimitedDict(2) + epoch_to_index_to_validator[42] = { + 1: Validator( + pubkey="0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + effective_balance=32_000_000_000, + slashed=False, + ), + 2: Validator( + pubkey="0x222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222", + effective_balance=32_000_000_000, + slashed=False, + ), + 3: Validator( + pubkey="0x333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", + effective_balance=32_000_000_000, + slashed=False, + ), + 4: Validator( + pubkey="444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", + effective_balance=32_000_000_000, + slashed=False, + ), + 5: Validator( + pubkey="555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555", + effective_balance=32_000_000_000, + slashed=False, + ), + 6: Validator( + pubkey="666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666", + effective_balance=32_000_000_000, + slashed=False, + ), + 7: Validator( + pubkey="777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", + effective_balance=32_000_000_000, + slashed=False, + ), + 8: Validator( + pubkey="888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888", + effective_balance=32_000_000_000, + slashed=False, + ), + 9: Validator( + pubkey="999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", + effective_balance=31_000_000_000, + slashed=False, + ), + 10: Validator( + pubkey="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + effective_balance=32_000_000_000, + slashed=False, + ), + } + process_rewards( - beacon, # type: ignore - BeaconType.LIGHTHOUSE, - 42, - { - 1: Validator( - pubkey="0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - effective_balance=32_000_000_000, - slashed=False, - ), - 2: Validator( - pubkey="0x222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222", - effective_balance=32_000_000_000, - slashed=False, - ), - 3: Validator( - pubkey="0x333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", - effective_balance=32_000_000_000, - slashed=False, - ), - 4: Validator( - pubkey="444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", - effective_balance=32_000_000_000, - slashed=False, - ), - 5: Validator( - pubkey="555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555", - effective_balance=32_000_000_000, - slashed=False, - ), - 6: Validator( - pubkey="666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666", - effective_balance=32_000_000_000, - slashed=False, - ), - 7: Validator( - pubkey="777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777", - effective_balance=32_000_000_000, - slashed=False, - ), - 8: Validator( - pubkey="888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888", - effective_balance=32_000_000_000, - slashed=False, - ), - 9: Validator( - pubkey="999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", - effective_balance=31_000_000_000, - slashed=False, - ), - 10: Validator( - pubkey="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - effective_balance=32_000_000_000, - slashed=False, - ), - }, + beacon, BeaconType.LIGHTHOUSE, 42, epoch_to_index_to_validator # type: ignore ) ideal_sources_count_after = ideal_sources_count.collect()[0].samples[0].value # type: ignore @@ -397,27 +407,27 @@ def get_rewards( actual_negative_targets_count_before = actual_negative_targets_count.collect()[0].samples[0].value # type: ignore actual_heads_count_before = actual_heads_count.collect()[0].samples[0].value # type: ignore + epoch_to_index_to_validator = LimitedDict(2) + epoch_to_index_to_validator[42] = { + 1: Validator( + pubkey="0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + effective_balance=32_000_000_000, + slashed=False, + ), + 2: Validator( + pubkey="0x222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222", + effective_balance=31_000_000_000, + slashed=False, + ), + 3: Validator( + pubkey="0x333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", + effective_balance=32_000_000_000, + slashed=False, + ), + } + process_rewards( - beacon, # type: ignore - BeaconType.LIGHTHOUSE, - 42, - { - 1: Validator( - pubkey="0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - effective_balance=32_000_000_000, - slashed=False, - ), - 2: Validator( - pubkey="0x222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222", - effective_balance=31_000_000_000, - slashed=False, - ), - 3: Validator( - pubkey="0x333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", - effective_balance=32_000_000_000, - slashed=False, - ), - }, + beacon, BeaconType.LIGHTHOUSE, 42, epoch_to_index_to_validator # type: ignore ) ideal_sources_count_after = ideal_sources_count.collect()[0].samples[0].value # type: ignore