Skip to content

Commit

Permalink
Fix missed rewards when a new validator enters
Browse files Browse the repository at this point in the history
  • Loading branch information
nalepae committed Jul 27, 2023
1 parent 1b0fa38 commit a50f1bd
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 102 deletions.
7 changes: 5 additions & 2 deletions eth_validator_watcher/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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)
Expand Down
22 changes: 18 additions & 4 deletions eth_validator_watcher/rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -49,18 +51,30 @@ 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
Parameters:
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

Expand Down
4 changes: 2 additions & 2 deletions tests/entrypoint/test__handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
198 changes: 104 additions & 94 deletions tests/rewards/test_process_rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit a50f1bd

Please sign in to comment.