refactor rewards/penalties tests to use a single structure

This commit is contained in:
Danny Ryan 2020-05-18 16:00:59 -06:00
parent 5da4fe37f8
commit 8060505743
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
10 changed files with 504 additions and 822 deletions

View File

@ -25,17 +25,50 @@ def has_enough_for_reward(spec, state, index):
)
def run_attestation_component_deltas(spec, state, component_delta_fn, matching_att_fn):
def run_deltas(spec, state):
"""
Run ``component_delta_fn``, yielding:
Run all deltas functions yielding:
- pre-state ('pre')
- deltas ('deltas')
- source deltas ('source_deltas')
- target deltas ('target_deltas')
- head deltas ('head_deltas')
- inclusion delay deltas ('inclusion_delay_deltas')
- inactivity penalty deltas ('inactivity_penalty_deltas')
"""
yield 'pre', state
yield from run_attestation_component_deltas(
spec,
state,
spec.get_source_deltas,
spec.get_matching_source_attestations,
'source_deltas',
)
yield from run_attestation_component_deltas(
spec,
state,
spec.get_target_deltas,
spec.get_matching_target_attestations,
'target_deltas',
)
yield from run_attestation_component_deltas(
spec,
state,
spec.get_head_deltas,
spec.get_matching_head_attestations,
'head_deltas',
)
yield from run_get_inclusion_delay_deltas(spec, state)
yield from run_get_inactivity_penalty_deltas(spec, state)
def run_attestation_component_deltas(spec, state, component_delta_fn, matching_att_fn, deltas_name):
"""
Run ``component_delta_fn``, yielding:
- deltas ('{``deltas_name``}')
"""
rewards, penalties = component_delta_fn(state)
yield 'deltas', Deltas(rewards=rewards, penalties=penalties)
yield deltas_name, Deltas(rewards=rewards, penalties=penalties)
matching_attestations = matching_att_fn(state, spec.get_previous_epoch(state))
matching_indices = spec.get_unslashed_attesting_indices(state, matching_attestations)
@ -62,6 +95,81 @@ def run_attestation_component_deltas(spec, state, component_delta_fn, matching_a
assert penalties[index] == 0
def run_get_inclusion_delay_deltas(spec, state):
"""
Run ``get_inclusion_delay_deltas``, yielding:
- inclusion delay deltas ('inclusion_delay_deltas')
"""
rewards, penalties = spec.get_inclusion_delay_deltas(state)
yield 'inclusion_delay_deltas', Deltas(rewards=rewards, penalties=penalties)
eligible_attestations = spec.get_matching_source_attestations(state, spec.get_previous_epoch(state))
attesting_indices = spec.get_unslashed_attesting_indices(state, eligible_attestations)
rewarded_indices = set()
rewarded_proposer_indices = set()
# Ensure attesters with enough balance are rewarded for attestations
# Track those that are rewarded and track proposers that should be rewarded
for index in range(len(state.validators)):
if index in attesting_indices and has_enough_for_reward(spec, state, index):
assert rewards[index] > 0
rewarded_indices.add(index)
# Track proposer of earliest included attestation for the validator defined by index
earliest_attestation = min([
a for a in eligible_attestations
if index in spec.get_attesting_indices(state, a.data, a.aggregation_bits)
], key=lambda a: a.inclusion_delay)
rewarded_proposer_indices.add(earliest_attestation.proposer_index)
# Ensure all expected proposers have been rewarded
# Track rewarde indices
proposing_indices = [a.proposer_index for a in eligible_attestations]
for index in proposing_indices:
if index in rewarded_proposer_indices:
assert rewards[index] > 0
rewarded_indices.add(index)
# Ensure all expected non-rewarded indices received no reward
for index in range(len(state.validators)):
assert penalties[index] == 0
if index not in rewarded_indices:
assert rewards[index] == 0
def run_get_inactivity_penalty_deltas(spec, state):
"""
Run ``get_inactivity_penalty_deltas``, yielding:
- inactivity penalty deltas ('inactivity_penalty_deltas')
"""
rewards, penalties = spec.get_inactivity_penalty_deltas(state)
yield 'inactivity_penalty_deltas', Deltas(rewards=rewards, penalties=penalties)
matching_attestations = spec.get_matching_target_attestations(state, spec.get_previous_epoch(state))
matching_attesting_indices = spec.get_unslashed_attesting_indices(state, matching_attestations)
finality_delay = spec.get_previous_epoch(state) - state.finalized_checkpoint.epoch
eligible_indices = spec.get_eligible_validator_indices(state)
for index in range(len(state.validators)):
assert rewards[index] == 0
if index not in eligible_indices:
assert penalties[index] == 0
continue
if finality_delay > spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY:
base_penalty = spec.BASE_REWARDS_PER_EPOCH * spec.get_base_reward(state, index)
if not has_enough_for_reward(spec, state, index):
assert penalties[index] == 0
elif index in matching_attesting_indices:
assert penalties[index] == base_penalty
else:
assert penalties[index] > base_penalty
else:
assert penalties[index] == 0
def set_some_new_deposits(spec, state, rng):
num_validators = len(state.validators)
# Set ~1/10 to just recently deposited
@ -102,74 +210,74 @@ def slash_random_validators(spec, state, rng):
spec.slash_validator(state, index)
def run_test_empty(spec, state, runner):
def run_test_empty(spec, state):
# Do not add any attestations to state
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_full_all_correct(spec, state, runner):
def run_test_full_all_correct(spec, state):
prepare_state_with_attestations(spec, state)
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_full_but_partial_participation(spec, state, runner, rng=Random(5522)):
def run_test_full_but_partial_participation(spec, state, rng=Random(5522)):
prepare_state_with_attestations(spec, state)
for a in state.previous_epoch_attestations:
a.aggregation_bits = [rng.choice([True, False]) for _ in a.aggregation_bits]
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_partial(spec, state, fraction_filled, runner):
def run_test_partial(spec, state, fraction_filled):
prepare_state_with_attestations(spec, state)
# Remove portion of attestations
num_attestations = int(len(state.previous_epoch_attestations) * fraction_filled)
state.previous_epoch_attestations = state.previous_epoch_attestations[:num_attestations]
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_half_full(spec, state, runner):
yield from run_test_partial(spec, state, 0.5, runner)
def run_test_half_full(spec, state):
yield from run_test_partial(spec, state, 0.5)
def run_test_one_attestation_one_correct(spec, state, runner):
def run_test_one_attestation_one_correct(spec, state):
prepare_state_with_attestations(spec, state)
# Remove all attestations except for the first one
state.previous_epoch_attestations = state.previous_epoch_attestations[:1]
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_with_not_yet_activated_validators(spec, state, runner, rng=Random(5555)):
def run_test_with_not_yet_activated_validators(spec, state, rng=Random(5555)):
set_some_new_deposits(spec, state, rng)
prepare_state_with_attestations(spec, state)
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_with_exited_validators(spec, state, runner, rng=Random(1337)):
def run_test_with_exited_validators(spec, state, rng=Random(1337)):
exit_random_validators(spec, state, rng)
prepare_state_with_attestations(spec, state)
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_with_slashed_validators(spec, state, runner, rng=Random(3322)):
def run_test_with_slashed_validators(spec, state, rng=Random(3322)):
exit_random_validators(spec, state, rng)
slash_random_validators(spec, state, rng)
prepare_state_with_attestations(spec, state)
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_some_very_low_effective_balances_that_attested(spec, state, runner):
def run_test_some_very_low_effective_balances_that_attested(spec, state):
state.balances
prepare_state_with_attestations(spec, state)
@ -178,10 +286,10 @@ def run_test_some_very_low_effective_balances_that_attested(spec, state, runner)
for i, index in enumerate(range(5)):
state.validators[index].effective_balance = i
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_some_very_low_effective_balances_that_did_not_attest(spec, state, runner):
def run_test_some_very_low_effective_balances_that_did_not_attest(spec, state):
prepare_state_with_attestations(spec, state)
# Remove attestation
@ -192,10 +300,10 @@ def run_test_some_very_low_effective_balances_that_did_not_attest(spec, state, r
for i, index in enumerate(indices):
state.validators[index].effective_balance = i
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_full_fraction_incorrect(spec, state, correct_target, correct_head, fraction_incorrect, runner):
def run_test_full_fraction_incorrect(spec, state, correct_target, correct_head, fraction_incorrect):
prepare_state_with_attestations(spec, state)
# Make fraction_incorrect of pending attestations have bad target/head as specified
@ -206,10 +314,92 @@ def run_test_full_fraction_incorrect(spec, state, correct_target, correct_head,
if not correct_head:
pending_attestation.data.beacon_block_root = b'\x66' * 32
yield from runner(spec, state)
yield from run_deltas(spec, state)
def run_test_full_random(spec, state, runner, rng=Random(8020)):
def run_test_full_delay_one_slot(spec, state):
prepare_state_with_attestations(spec, state)
for a in state.previous_epoch_attestations:
a.inclusion_delay += 1
yield from run_deltas(spec, state)
def run_test_full_delay_max_slots(spec, state):
prepare_state_with_attestations(spec, state)
for a in state.previous_epoch_attestations:
a.inclusion_delay += spec.SLOTS_PER_EPOCH
yield from run_deltas(spec, state)
def run_test_full_mixed_delay(spec, state, rng=Random(1234)):
prepare_state_with_attestations(spec, state)
for a in state.previous_epoch_attestations:
a.inclusion_delay = rng.randint(1, spec.SLOTS_PER_EPOCH)
yield from run_deltas(spec, state)
def run_test_proposer_not_in_attestations(spec, state):
prepare_state_with_attestations(spec, state)
# Get an attestation where the proposer is not in the committee
non_proposer_attestations = []
for a in state.previous_epoch_attestations:
if a.proposer_index not in spec.get_unslashed_attesting_indices(state, [a]):
non_proposer_attestations.append(a)
assert any(non_proposer_attestations)
state.previous_epoch_attestations = non_proposer_attestations
yield from run_deltas(spec, state)
def run_test_duplicate_attestations_at_later_slots(spec, state):
prepare_state_with_attestations(spec, state)
# Remove 2/3 of attestations to make it more interesting
num_attestations = int(len(state.previous_epoch_attestations) * 0.33)
state.previous_epoch_attestations = state.previous_epoch_attestations[:num_attestations]
# Get map of the proposer at each slot to make valid-looking duplicate attestations
per_slot_proposers = {
(a.data.slot + a.inclusion_delay): a.proposer_index
for a in state.previous_epoch_attestations
}
max_slot = max([a.data.slot + a.inclusion_delay for a in state.previous_epoch_attestations])
later_attestations = []
for a in state.previous_epoch_attestations:
# Only have proposers for previous epoch so do not create later
# duplicate if slot exceeds the max slot in previous_epoch_attestations
if a.data.slot + a.inclusion_delay >= max_slot:
continue
later_a = a.copy()
later_a.inclusion_delay += 1
later_a.proposer_index = per_slot_proposers[later_a.data.slot + later_a.inclusion_delay]
later_attestations.append(later_a)
assert any(later_attestations)
state.previous_epoch_attestations = sorted(
state.previous_epoch_attestations + later_attestations,
key=lambda a: a.data.slot + a.inclusion_delay
)
yield from run_deltas(spec, state)
def run_test_all_balances_too_low_for_reward(spec, state):
prepare_state_with_attestations(spec, state)
for index in range(len(state.validators)):
state.validators[index].effective_balance = 10
yield from run_deltas(spec, state)
def run_test_full_random(spec, state, rng=Random(8020)):
set_some_new_deposits(spec, state, rng)
exit_random_validators(spec, state, rng)
slash_random_validators(spec, state, rng)
@ -228,4 +418,4 @@ def run_test_full_random(spec, state, runner, rng=Random(8020)):
# Random inclusion delay
pending_attestation.inclusion_delay = rng.randint(1, spec.SLOTS_PER_EPOCH)
yield from runner(spec, state)
yield from run_deltas(spec, state)

View File

@ -1,89 +1,71 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.rewards import run_attestation_component_deltas
import eth2spec.test.helpers.rewards as rewards_helpers
def run_get_source_deltas(spec, state):
"""
Run ``get_source_deltas``, yielding:
- pre-state ('pre')
- deltas ('deltas')
"""
yield from run_attestation_component_deltas(
spec,
state,
spec.get_source_deltas,
spec.get_matching_source_attestations,
)
@with_all_phases
@spec_state_test
def test_empty(spec, state):
yield from rewards_helpers.run_test_empty(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_empty(spec, state)
@with_all_phases
@spec_state_test
def test_full_all_correct(spec, state):
yield from rewards_helpers.run_test_full_all_correct(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_full_all_correct(spec, state)
@with_all_phases
@spec_state_test
def test_half_full(spec, state):
yield from rewards_helpers.run_test_half_full(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_half_full(spec, state)
@with_all_phases
@spec_state_test
def test_quarter_full(spec, state):
yield from rewards_helpers.run_test_partial(spec, state, 0.25)
@with_all_phases
@spec_state_test
def test_full_but_partial_participation(spec, state):
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state)
@with_all_phases
@spec_state_test
def test_one_attestation_one_correct(spec, state):
yield from rewards_helpers.run_test_one_attestation_one_correct(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_one_attestation_one_correct(spec, state)
@with_all_phases
@spec_state_test
def test_with_not_yet_activated_validators(spec, state):
yield from rewards_helpers.run_test_with_not_yet_activated_validators(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_with_not_yet_activated_validators(spec, state)
@with_all_phases
@spec_state_test
def test_with_exited_validators(spec, state):
yield from rewards_helpers.run_test_with_exited_validators(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_with_exited_validators(spec, state)
@with_all_phases
@spec_state_test
def test_with_slashed_validators(spec, state):
yield from rewards_helpers.run_test_with_slashed_validators(spec, state, run_get_source_deltas)
yield from rewards_helpers.run_test_with_slashed_validators(spec, state)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_attested(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(
spec,
state,
run_get_source_deltas
)
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(spec, state)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_did_not_attest(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_did_not_attest(
spec,
state,
run_get_source_deltas,
)
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_did_not_attest(spec, state)
#
@ -101,7 +83,6 @@ def test_full_half_correct_target_incorrect_head(spec, state):
correct_target=True,
correct_head=False,
fraction_incorrect=0.5,
runner=run_get_source_deltas
)
@ -113,7 +94,6 @@ def test_full_correct_target_incorrect_head(spec, state):
correct_target=True,
correct_head=False,
fraction_incorrect=1.0,
runner=run_get_source_deltas
)
@ -125,7 +105,6 @@ def test_full_half_incorrect_target_incorrect_head(spec, state):
correct_target=False,
correct_head=False,
fraction_incorrect=0.5,
runner=run_get_source_deltas
)
@ -137,11 +116,40 @@ def test_full_half_incorrect_target_correct_head(spec, state):
correct_target=False,
correct_head=True,
fraction_incorrect=0.5,
runner=run_get_source_deltas
)
@with_all_phases
@spec_state_test
def test_full_random(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, run_get_source_deltas)
def test_full_delay_one_slot(spec, state):
yield from rewards_helpers.run_test_full_delay_one_slot(spec, state)
@with_all_phases
@spec_state_test
def test_full_delay_max_slots(spec, state):
yield from rewards_helpers.run_test_full_delay_max_slots(spec, state)
@with_all_phases
@spec_state_test
def test_full_mixed_delay(spec, state):
yield from rewards_helpers.run_test_full_mixed_delay(spec, state)
@with_all_phases
@spec_state_test
def test_proposer_not_in_attestations(spec, state):
yield from rewards_helpers.run_test_proposer_not_in_attestations(spec, state)
@with_all_phases
@spec_state_test
def test_duplicate_attestations_at_later_slots(spec, state):
yield from rewards_helpers.run_test_duplicate_attestations_at_later_slots(spec, state)
@with_all_phases
@spec_state_test
def test_all_balances_too_low_for_reward(spec, state):
yield from rewards_helpers.run_test_all_balances_too_low_for_reward(spec, state)

View File

@ -1,136 +0,0 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.rewards import run_attestation_component_deltas
import eth2spec.test.helpers.rewards as rewards_helpers
def run_get_head_deltas(spec, state):
"""
Run ``get_head_deltas``, yielding:
- pre-state ('pre')
- deltas ('deltas')
"""
yield from run_attestation_component_deltas(
spec,
state,
spec.get_head_deltas,
spec.get_matching_head_attestations,
)
@with_all_phases
@spec_state_test
def test_empty(spec, state):
yield from rewards_helpers.run_test_empty(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_full_all_correct(spec, state):
yield from rewards_helpers.run_test_full_all_correct(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_half_full(spec, state):
yield from rewards_helpers.run_test_half_full(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_full_but_partial_participation(spec, state):
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_one_attestation_one_correct(spec, state):
yield from rewards_helpers.run_test_one_attestation_one_correct(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_with_not_yet_activated_validators(spec, state):
yield from rewards_helpers.run_test_with_not_yet_activated_validators(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_with_exited_validators(spec, state):
yield from rewards_helpers.run_test_with_exited_validators(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_with_slashed_validators(spec, state):
yield from rewards_helpers.run_test_with_slashed_validators(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_attested(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(spec, state, run_get_head_deltas)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_did_not_attest(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_did_not_attest(
spec,
state,
run_get_head_deltas,
)
@with_all_phases
@spec_state_test
def test_full_half_correct_target_incorrect_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=True,
correct_head=False,
fraction_incorrect=0.5,
runner=run_get_head_deltas
)
@with_all_phases
@spec_state_test
def test_full_correct_target_incorrect_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=True,
correct_head=False,
fraction_incorrect=1.0,
runner=run_get_head_deltas
)
@with_all_phases
@spec_state_test
def test_full_half_incorrect_target_incorrect_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=False,
correct_head=False,
fraction_incorrect=0.5,
runner=run_get_head_deltas
)
@with_all_phases
@spec_state_test
def test_full_half_incorrect_target_correct_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=False,
correct_head=True,
fraction_incorrect=0.5,
runner=run_get_head_deltas
)
@with_all_phases
@spec_state_test
def test_full_random(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, run_get_head_deltas)

View File

@ -1,231 +0,0 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.rewards import has_enough_for_reward
from eth2spec.test.helpers.state import next_epoch
from eth2spec.test.helpers.rewards import Deltas
import eth2spec.test.helpers.rewards as rewards_helpers
def run_get_inactivity_penalty_deltas(spec, state):
"""
Run ``get_inactivity_penalty_deltas``, yielding:
- pre-state ('pre')
- deltas ('deltas')
"""
yield 'pre', state
rewards, penalties = spec.get_inactivity_penalty_deltas(state)
yield 'deltas', Deltas(rewards=rewards, penalties=penalties)
matching_attestations = spec.get_matching_target_attestations(state, spec.get_previous_epoch(state))
matching_attesting_indices = spec.get_unslashed_attesting_indices(state, matching_attestations)
finality_delay = spec.get_previous_epoch(state) - state.finalized_checkpoint.epoch
eligible_indices = spec.get_eligible_validator_indices(state)
for index in range(len(state.validators)):
assert rewards[index] == 0
if index not in eligible_indices:
assert penalties[index] == 0
continue
if finality_delay > spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY:
base_penalty = spec.BASE_REWARDS_PER_EPOCH * spec.get_base_reward(state, index)
if not has_enough_for_reward(spec, state, index):
assert penalties[index] == 0
elif index in matching_attesting_indices:
assert penalties[index] == base_penalty
else:
assert penalties[index] > base_penalty
else:
assert penalties[index] == 0
def transition_state_to_leak(spec, state, epochs=None):
if epochs is None:
epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY
assert epochs >= spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY
for _ in range(epochs):
next_epoch(spec, state)
@with_all_phases
@spec_state_test
def test_empty_no_leak(spec, state):
yield from rewards_helpers.run_test_empty(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_empty_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_empty(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_full_no_leak(spec, state):
yield from rewards_helpers.run_test_full_all_correct(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_full_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_all_correct(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_half_full_no_leak(spec, state):
yield from rewards_helpers.run_test_half_full(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_half_full_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_half_full(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_quarter_full_no_leak(spec, state):
yield from rewards_helpers.run_test_partial(spec, state, 0.25, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_quarter_full_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_partial(spec, state, 0.25, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_full_but_partial_participation_no_leak(spec, state):
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_full_but_partial_participation_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_with_not_yet_activated_validators_no_leak(spec, state):
yield from rewards_helpers.run_test_with_not_yet_activated_validators(
spec,
state,
run_get_inactivity_penalty_deltas,
)
@with_all_phases
@spec_state_test
def test_with_not_yet_activated_validators_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_with_not_yet_activated_validators(
spec,
state,
run_get_inactivity_penalty_deltas,
)
@with_all_phases
@spec_state_test
def test_with_exited_validators_no_leak(spec, state):
yield from rewards_helpers.run_test_with_exited_validators(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_with_exited_validators_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_with_exited_validators(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_with_slashed_validators_no_leak(spec, state):
yield from rewards_helpers.run_test_with_slashed_validators(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_with_slashed_validators_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_with_slashed_validators(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_attested_no_leak(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(
spec,
state,
run_get_inactivity_penalty_deltas,
)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_attested_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(
spec,
state,
run_get_inactivity_penalty_deltas,
)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_did_not_attest_no_leak(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_did_not_attest(
spec,
state,
run_get_inactivity_penalty_deltas,
)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_did_not_attest_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_did_not_attest(
spec,
state,
run_get_inactivity_penalty_deltas,
)
@with_all_phases
@spec_state_test
def test_full_random_no_leak(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_full_random_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_random(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_full_random_five_epoch_leak(spec, state):
transition_state_to_leak(spec, state, epochs=5)
yield from rewards_helpers.run_test_full_random(spec, state, run_get_inactivity_penalty_deltas)
@with_all_phases
@spec_state_test
def test_full_random_ten_epoch_leak(spec, state):
transition_state_to_leak(spec, state, epochs=10)
yield from rewards_helpers.run_test_full_random(spec, state, run_get_inactivity_penalty_deltas)

View File

@ -1,213 +0,0 @@
from random import Random
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.attestations import prepare_state_with_attestations
from eth2spec.test.helpers.rewards import Deltas, has_enough_for_reward
import eth2spec.test.helpers.rewards as rewards_helpers
def run_get_inclusion_delay_deltas(spec, state):
"""
Run ``get_inclusion_delay_deltas``, yielding:
- pre-state ('pre')
- deltas ('deltas')
"""
yield 'pre', state
rewards, penalties = spec.get_inclusion_delay_deltas(state)
yield 'deltas', Deltas(rewards=rewards, penalties=penalties)
eligible_attestations = spec.get_matching_source_attestations(state, spec.get_previous_epoch(state))
attesting_indices = spec.get_unslashed_attesting_indices(state, eligible_attestations)
rewarded_indices = set()
rewarded_proposer_indices = set()
# Ensure attesters with enough balance are rewarded for attestations
# Track those that are rewarded and track proposers that should be rewarded
for index in range(len(state.validators)):
if index in attesting_indices and has_enough_for_reward(spec, state, index):
assert rewards[index] > 0
rewarded_indices.add(index)
# Track proposer of earliest included attestation for the validator defined by index
earliest_attestation = min([
a for a in eligible_attestations
if index in spec.get_attesting_indices(state, a.data, a.aggregation_bits)
], key=lambda a: a.inclusion_delay)
rewarded_proposer_indices.add(earliest_attestation.proposer_index)
# Ensure all expected proposers have been rewarded
# Track rewarde indices
proposing_indices = [a.proposer_index for a in eligible_attestations]
for index in proposing_indices:
if index in rewarded_proposer_indices:
assert rewards[index] > 0
rewarded_indices.add(index)
# Ensure all expected non-rewarded indices received no reward
for index in range(len(state.validators)):
assert penalties[index] == 0
if index not in rewarded_indices:
assert rewards[index] == 0
@with_all_phases
@spec_state_test
def test_empty(spec, state):
yield from rewards_helpers.run_test_empty(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_full(spec, state):
yield from rewards_helpers.run_test_full_all_correct(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_half_full(spec, state):
yield from rewards_helpers.run_test_half_full(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_quarter_full(spec, state):
yield from rewards_helpers.run_test_partial(spec, state, 0.25, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_full_but_partial_participation(spec, state):
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_with_not_yet_activated_validators(spec, state):
yield from rewards_helpers.run_test_with_not_yet_activated_validators(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_with_exited_validators(spec, state):
yield from rewards_helpers.run_test_with_exited_validators(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_with_slashed_validators(spec, state):
yield from rewards_helpers.run_test_with_slashed_validators(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_attested(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(
spec,
state,
run_get_inclusion_delay_deltas
)
@with_all_phases
@spec_state_test
def test_full_random(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, run_get_inclusion_delay_deltas)
@with_all_phases
@spec_state_test
def test_full_delay_one_slot(spec, state):
prepare_state_with_attestations(spec, state)
for a in state.previous_epoch_attestations:
a.inclusion_delay += 1
yield from run_get_inclusion_delay_deltas(spec, state)
@with_all_phases
@spec_state_test
def test_full_delay_max_slots(spec, state):
prepare_state_with_attestations(spec, state)
for a in state.previous_epoch_attestations:
a.inclusion_delay += spec.SLOTS_PER_EPOCH
yield from run_get_inclusion_delay_deltas(spec, state)
@with_all_phases
@spec_state_test
def test_full_mixed_delay(spec, state):
rng = Random(1234)
prepare_state_with_attestations(spec, state)
for a in state.previous_epoch_attestations:
a.inclusion_delay = rng.randint(1, spec.SLOTS_PER_EPOCH)
yield from run_get_inclusion_delay_deltas(spec, state)
@with_all_phases
@spec_state_test
def test_proposer_not_in_attestations(spec, state):
prepare_state_with_attestations(spec, state)
# Get an attestation where the proposer is not in the committee
non_proposer_attestations = []
for a in state.previous_epoch_attestations:
if a.proposer_index not in spec.get_unslashed_attesting_indices(state, [a]):
non_proposer_attestations.append(a)
assert any(non_proposer_attestations)
state.previous_epoch_attestations = non_proposer_attestations
yield from run_get_inclusion_delay_deltas(spec, state)
@with_all_phases
@spec_state_test
def test_duplicate_attestations_at_later_slots(spec, state):
prepare_state_with_attestations(spec, state)
# Remove 2/3 of attestations to make it more interesting
num_attestations = int(len(state.previous_epoch_attestations) * 0.33)
state.previous_epoch_attestations = state.previous_epoch_attestations[:num_attestations]
# Get map of the proposer at each slot to make valid-looking duplicate attestations
per_slot_proposers = {
(a.data.slot + a.inclusion_delay): a.proposer_index
for a in state.previous_epoch_attestations
}
max_slot = max([a.data.slot + a.inclusion_delay for a in state.previous_epoch_attestations])
later_attestations = []
for a in state.previous_epoch_attestations:
# Only have proposers for previous epoch so do not create later
# duplicate if slot exceeds the max slot in previous_epoch_attestations
if a.data.slot + a.inclusion_delay >= max_slot:
continue
later_a = a.copy()
later_a.inclusion_delay += 1
later_a.proposer_index = per_slot_proposers[later_a.data.slot + later_a.inclusion_delay]
later_attestations.append(later_a)
assert any(later_attestations)
state.previous_epoch_attestations = sorted(
state.previous_epoch_attestations + later_attestations,
key=lambda a: a.data.slot + a.inclusion_delay
)
yield from run_get_inclusion_delay_deltas(spec, state)
@with_all_phases
@spec_state_test
def test_all_balances_too_low_for_reward(spec, state):
prepare_state_with_attestations(spec, state)
for index in range(len(state.validators)):
state.validators[index].effective_balance = 10
yield from run_get_inclusion_delay_deltas(spec, state)

View File

@ -1,140 +0,0 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.rewards import run_attestation_component_deltas
import eth2spec.test.helpers.rewards as rewards_helpers
def run_get_target_deltas(spec, state):
"""
Run ``get_target_deltas``, yielding:
- pre-state ('pre')
- deltas ('deltas')
"""
yield from run_attestation_component_deltas(
spec,
state,
spec.get_target_deltas,
spec.get_matching_target_attestations,
)
@with_all_phases
@spec_state_test
def test_empty(spec, state):
yield from rewards_helpers.run_test_empty(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_full_all_correct(spec, state):
yield from rewards_helpers.run_test_full_all_correct(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_half_full(spec, state):
yield from rewards_helpers.run_test_half_full(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_full_but_partial_participation(spec, state):
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_one_attestation_one_correct(spec, state):
yield from rewards_helpers.run_test_one_attestation_one_correct(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_with_not_yet_activated_validators(spec, state):
yield from rewards_helpers.run_test_with_not_yet_activated_validators(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_with_exited_validators(spec, state):
yield from rewards_helpers.run_test_with_exited_validators(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_with_slashed_validators(spec, state):
yield from rewards_helpers.run_test_with_slashed_validators(spec, state, run_get_target_deltas)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_attested(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(
spec,
state,
run_get_target_deltas
)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_did_not_attest(spec, state):
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_did_not_attest(
spec,
state,
run_get_target_deltas,
)
@with_all_phases
@spec_state_test
def test_full_half_correct_target_incorrect_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=True,
correct_head=False,
fraction_incorrect=0.5,
runner=run_get_target_deltas
)
@with_all_phases
@spec_state_test
def test_full_correct_target_incorrect_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=True,
correct_head=False,
fraction_incorrect=1.0,
runner=run_get_target_deltas
)
@with_all_phases
@spec_state_test
def test_full_half_incorrect_target_incorrect_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=False,
correct_head=False,
fraction_incorrect=0.5,
runner=run_get_target_deltas
)
@with_all_phases
@spec_state_test
def test_full_half_incorrect_target_correct_head(spec, state):
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=False,
correct_head=True,
fraction_incorrect=0.5,
runner=run_get_target_deltas
)
@with_all_phases
@spec_state_test
def test_full_random(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, run_get_target_deltas)

View File

@ -0,0 +1,165 @@
from eth2spec.test.context import with_all_phases, spec_state_test
from eth2spec.test.helpers.state import next_epoch
import eth2spec.test.helpers.rewards as rewards_helpers
def transition_state_to_leak(spec, state, epochs=None):
if epochs is None:
epochs = spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY
assert epochs >= spec.MIN_EPOCHS_TO_INACTIVITY_PENALTY
for _ in range(epochs):
next_epoch(spec, state)
@with_all_phases
@spec_state_test
def test_empty_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_empty(spec, state)
@with_all_phases
@spec_state_test
def test_full_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_all_correct(spec, state)
@with_all_phases
@spec_state_test
def test_half_full_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_half_full(spec, state)
@with_all_phases
@spec_state_test
def test_quarter_full_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_partial(spec, state, 0.25)
@with_all_phases
@spec_state_test
def test_full_but_partial_participation_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_but_partial_participation(spec, state)
@with_all_phases
@spec_state_test
def test_one_attestation_one_correct_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_one_attestation_one_correct(spec, state)
@with_all_phases
@spec_state_test
def test_with_not_yet_activated_validators_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_with_not_yet_activated_validators(spec, state)
@with_all_phases
@spec_state_test
def test_with_exited_validators_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_with_exited_validators(spec, state)
@with_all_phases
@spec_state_test
def test_with_slashed_validators_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_with_slashed_validators(spec, state)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_attested_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_attested(spec, state)
@with_all_phases
@spec_state_test
def test_some_very_low_effective_balances_that_did_not_attest_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_some_very_low_effective_balances_that_did_not_attest(spec, state)
#
# NOTE: No source incorrect tests
# All PendingAttestations in state have source validated
# We choose to keep this invariant in these tests to not force clients to test with degenerate states
#
@with_all_phases
@spec_state_test
def test_full_half_correct_target_incorrect_head_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=True,
correct_head=False,
fraction_incorrect=0.5,
)
@with_all_phases
@spec_state_test
def test_full_correct_target_incorrect_head_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=True,
correct_head=False,
fraction_incorrect=1.0,
)
@with_all_phases
@spec_state_test
def test_full_half_incorrect_target_incorrect_head_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=False,
correct_head=False,
fraction_incorrect=0.5,
)
@with_all_phases
@spec_state_test
def test_full_half_incorrect_target_correct_head_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_fraction_incorrect(
spec, state,
correct_target=False,
correct_head=True,
fraction_incorrect=0.5,
)
@with_all_phases
@spec_state_test
def test_full_random_leak(spec, state):
transition_state_to_leak(spec, state)
yield from rewards_helpers.run_test_full_random(spec, state)
@with_all_phases
@spec_state_test
def test_full_random_five_epoch_leak(spec, state):
transition_state_to_leak(spec, state, epochs=5)
yield from rewards_helpers.run_test_full_random(spec, state)
@with_all_phases
@spec_state_test
def test_full_random_ten_epoch_leak(spec, state):
transition_state_to_leak(spec, state, epochs=10)
yield from rewards_helpers.run_test_full_random(spec, state)

View File

@ -0,0 +1,22 @@
from random import Random
from eth2spec.test.context import with_all_phases, spec_state_test
import eth2spec.test.helpers.rewards as rewards_helpers
@with_all_phases
@spec_state_test
def test_full_random_0(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, rng=Random(1010))
@with_all_phases
@spec_state_test
def test_full_random_1(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, rng=Random(2020))
@with_all_phases
@spec_state_test
def test_full_random_2(spec, state):
yield from rewards_helpers.run_test_full_random(spec, state, rng=Random(3030))

View File

@ -1,8 +1,15 @@
# Rewards tests
The different rewards deltas sub-functions are testing individually with the test handlers, each returning the related `rewards`/`penalties`.
All rewards deltas sub-functions are tested for each test case.
There is no "change" factor, the rewards/penalties outputs are pure functions with just the pre-state as input.
Hence, the format is shared between each test-handler. (See test condition documentation on how to run the tests.)
(See test condition documentation on how to run the tests.)
`Deltas` is defined as:
```python
class Deltas(Container):
rewards: List[uint64, VALIDATOR_REGISTRY_LIMIT]
penalties: List[uint64, VALIDATOR_REGISTRY_LIMIT]
```
## Test case format
@ -22,31 +29,47 @@ A YAML-encoded `BeaconState`, the state before running the rewards sub-function.
Also available as `pre.ssz`.
### `deltas.yaml`
### `source_deltas.yaml`
A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards sub-function
A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_source_deltas` function
Where `Deltas` is defined as:
```python
class Deltas(Container):
rewards: List[uint64, VALIDATOR_REGISTRY_LIMIT]
penalties: List[uint64, VALIDATOR_REGISTRY_LIMIT]
```
Also available as `source_deltas.ssz`.
Also available as `deltas.ssz`.
### `target_deltas.yaml`
A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_target_deltas` function
Also available as `target_deltas.ssz`.
### `head_deltas.yaml`
A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_head_deltas` function
Also available as `head_deltas.ssz`.
### `inclusion_delay_deltas.yaml`
A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_inclusion_delay_deltas` function
Also available as `inclusion_delay_deltas.ssz`.
### `inactivity_penalty_deltas.yaml`
A YAML-encoded `Deltas` representing the rewards and penalties returned by the rewards the `get_inactivity_penalty_deltas` function
Also available as `inactivity_penalty_deltas.ssz`.
## Condition
A handler of the `rewards` test-runner should process these cases,
calling the corresponding rewards deltas function (same name in spec).
This excludes all other parts of `process_rewards_and_penalties`
calling the corresponding rewards deltas function for each set of deltas.
The provided pre-state is ready to be input into the designated handler.
The provided pre-state is ready to be input into each rewards deltas function.
The provided `deltas` should match the return values of the
handler. Specifically the following must hold true:
deltas function. Specifically the following must hold true for each set of deltas:
```python
deltas.rewards == handler(state)[0]
deltas.penalties == handler(state)[1]
deltas.rewards == deltas_function(state)[0]
deltas.penalties == deltas_function(state)[1]
```

View File

@ -3,11 +3,9 @@ from typing import Iterable
from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.test.phase_0.rewards import (
test_get_source_deltas,
test_get_target_deltas,
test_get_head_deltas,
test_get_inclusion_delay_deltas,
test_get_inactivity_penalty_deltas,
test_basic,
test_leak,
test_random,
)
from gen_base import gen_runner, gen_typing
from gen_from_tests.gen import generate_from_tests
@ -37,14 +35,10 @@ def create_provider(handler_name: str, tests_src, config_name: str) -> gen_typin
if __name__ == "__main__":
gen_runner.run_generator("epoch_processing", [
create_provider('get_source_deltas', test_get_source_deltas, 'minimal'),
create_provider('get_source_deltas', test_get_source_deltas, 'mainnet'),
create_provider('get_target_deltas', test_get_target_deltas, 'minimal'),
create_provider('get_target_deltas', test_get_target_deltas, 'mainnet'),
create_provider('get_head_deltas', test_get_head_deltas, 'minimal'),
create_provider('get_head_deltas', test_get_head_deltas, 'mainnet'),
create_provider('get_inclusion_delay_deltas', test_get_inclusion_delay_deltas, 'minimal'),
create_provider('get_inclusion_delay_deltas', test_get_inclusion_delay_deltas, 'mainnet'),
create_provider('get_inactivity_penalty_deltas', test_get_inactivity_penalty_deltas, 'minimal'),
create_provider('get_inactivity_penalty_deltas', test_get_inactivity_penalty_deltas, 'mainnet'),
create_provider('get_deltas', test_basic, 'minimal'),
create_provider('get_deltas', test_basic, 'mainnet'),
create_provider('get_deltas', test_leak, 'minimal'),
create_provider('get_deltas', test_leak, 'mainnet'),
create_provider('get_deltas', test_random, 'minimal'),
create_provider('get_deltas', test_random, 'mainnet'),
])