Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests based on K cov from #1420, updated to get into v08x before release. #1442

Merged
merged 11 commits into from
Oct 24, 2019
Merged
4 changes: 4 additions & 0 deletions test_generators/epoch_processing/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
test_process_final_updates,
test_process_justification_and_finalization,
test_process_registry_updates,
test_process_rewards_and_penalties,
test_process_slashings
)
from gen_base import gen_runner, gen_typing
Expand Down Expand Up @@ -43,6 +44,9 @@ def cases_fn() -> Iterable[gen_typing.TestCase]:
create_provider('justification_and_finalization', test_process_justification_and_finalization, 'mainnet'),
create_provider('registry_updates', test_process_registry_updates, 'minimal'),
create_provider('registry_updates', test_process_registry_updates, 'mainnet'),
create_provider('rewards_and_penalties', test_process_rewards_and_penalties, 'minimal'),
# runs full epochs filled with data, with uncached ssz. Disabled for now.
# create_provider('rewards_and_penalties', test_process_rewards_and_penalties, 'mainnet'),
create_provider('slashings', test_process_slashings, 'minimal'),
create_provider('slashings', test_process_slashings, 'mainnet'),
])
68 changes: 60 additions & 8 deletions test_libs/pyspec/eth2spec/test/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,67 @@

from .utils import vector_test, with_meta_tags

from typing import Any, Callable, Sequence

def with_state(fn):
def entry(*args, **kw):
try:
kw['state'] = create_genesis_state(spec=kw['spec'], num_validators=spec_phase0.SLOTS_PER_EPOCH * 8)
except KeyError:
raise TypeError('Spec decorator must come within state decorator to inject spec into state.')
return fn(*args, **kw)
return entry

def with_custom_state(balances_fn: Callable[[Any], Sequence[int]],
threshold_fn: Callable[[Any], int]):
def deco(fn):
def entry(*args, **kw):
try:
spec = kw['spec']

balances = balances_fn(spec)
activation_threshold = threshold_fn(spec)

kw['state'] = create_genesis_state(spec=spec, validator_balances=balances,
activation_threshold=activation_threshold)
except KeyError:
raise TypeError('Spec decorator must come within state decorator to inject spec into state.')
return fn(*args, **kw)
return entry
return deco


def default_activation_threshold(spec):
"""
Helper method to use the default balance activation threshold for state creation for tests.
Usage: `@with_custom_state(threshold_fn=default_activation_threshold, ...)`
"""
return spec.MAX_EFFECTIVE_BALANCE


def default_balances(spec):
"""
Helper method to create a series of default balances.
Usage: `@with_custom_state(balances_fn=default_balances, ...)`
"""
num_validators = spec.SLOTS_PER_EPOCH * 8
return [spec.MAX_EFFECTIVE_BALANCE] * num_validators


with_state = with_custom_state(default_balances, default_activation_threshold)


def low_balances(spec):
"""
Helper method to create a series of low balances.
Usage: `@with_custom_state(balances_fn=low_balances, ...)`
"""
num_validators = spec.SLOTS_PER_EPOCH * 8
# Technically the balances cannot be this low starting from genesis, but it is useful for testing
low_balance = 18 * 10 ** 9
return [low_balance] * num_validators


def misc_balances(spec):
"""
Helper method to create a series of balances that includes some misc. balances.
Usage: `@with_custom_state(balances_fn=misc_balances, ...)`
"""
num_validators = spec.SLOTS_PER_EPOCH * 8
num_misc_validators = spec.SLOTS_PER_EPOCH
return [spec.MAX_EFFECTIVE_BALANCE] * num_validators + [spec.MIN_DEPOSIT_AMOUNT] * num_misc_validators


# BLS is turned off by default *for performance purposes during TESTING*.
Expand Down
39 changes: 38 additions & 1 deletion test_libs/pyspec/eth2spec/test/genesis/test_initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@spec_test
def test_initialize_beacon_state_from_eth1(spec):
deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
deposits, deposit_root = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)
deposits, deposit_root, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)

eth1_block_hash = b'\x12' * 32
eth1_timestamp = spec.MIN_GENESIS_TIME
Expand All @@ -25,6 +25,43 @@ def test_initialize_beacon_state_from_eth1(spec):
assert state.eth1_data.deposit_root == deposit_root
assert state.eth1_data.deposit_count == deposit_count
assert state.eth1_data.block_hash == eth1_block_hash
assert spec.get_total_active_balance(state) == deposit_count * spec.MAX_EFFECTIVE_BALANCE

# yield state
yield 'state', state


@with_phases(['phase0'])
@spec_test
def test_initialize_beacon_state_some_small_balances(spec):
main_deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
main_deposits, _, deposit_data_list = prepare_genesis_deposits(spec, main_deposit_count,
spec.MAX_EFFECTIVE_BALANCE, signed=True)
# For deposits above, and for another deposit_count, add a balance of EFFECTIVE_BALANCE_INCREMENT
small_deposit_count = main_deposit_count * 2
small_deposits, deposit_root, _ = prepare_genesis_deposits(spec, small_deposit_count,
spec.MIN_DEPOSIT_AMOUNT,
signed=True,
deposit_data_list=deposit_data_list)
deposits = main_deposits + small_deposits

eth1_block_hash = b'\x12' * 32
eth1_timestamp = spec.MIN_GENESIS_TIME

yield 'eth1_block_hash', eth1_block_hash
yield 'eth1_timestamp', eth1_timestamp
yield 'deposits', deposits

# initialize beacon_state
state = spec.initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)

assert state.genesis_time == eth1_timestamp - eth1_timestamp % spec.SECONDS_PER_DAY + 2 * spec.SECONDS_PER_DAY
assert len(state.validators) == small_deposit_count
assert state.eth1_data.deposit_root == deposit_root
assert state.eth1_data.deposit_count == len(deposits)
assert state.eth1_data.block_hash == eth1_block_hash
# only main deposits participate to the active balance
assert spec.get_total_active_balance(state) == main_deposit_count * spec.MAX_EFFECTIVE_BALANCE

# yield state
yield 'state', state
6 changes: 3 additions & 3 deletions test_libs/pyspec/eth2spec/test/genesis/test_validity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

def create_valid_beacon_state(spec):
deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT
deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)
deposits, _, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)

eth1_block_hash = b'\x12' * 32
eth1_timestamp = spec.MIN_GENESIS_TIME
Expand Down Expand Up @@ -65,7 +65,7 @@ def test_is_valid_genesis_state_true_more_balance(spec):
@spec_test
def test_is_valid_genesis_state_true_one_more_validator(spec):
deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT + 1
deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)
deposits, _, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)

eth1_block_hash = b'\x12' * 32
eth1_timestamp = spec.MIN_GENESIS_TIME
Expand All @@ -78,7 +78,7 @@ def test_is_valid_genesis_state_true_one_more_validator(spec):
@spec_test
def test_is_valid_genesis_state_false_not_enough_validator(spec):
deposit_count = spec.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT - 1
deposits, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)
deposits, _, _ = prepare_genesis_deposits(spec, deposit_count, spec.MAX_EFFECTIVE_BALANCE, signed=True)

eth1_block_hash = b'\x12' * 32
eth1_timestamp = spec.MIN_GENESIS_TIME
Expand Down
7 changes: 4 additions & 3 deletions test_libs/pyspec/eth2spec/test/helpers/deposits.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@ def build_deposit(spec,
return deposit, root, deposit_data_list


def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False):
deposit_data_list = []
def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False, deposit_data_list=None):
if deposit_data_list is None:
deposit_data_list = []
genesis_deposits = []
for validator_index in range(genesis_validator_count):
pubkey = pubkeys[validator_index]
Expand All @@ -75,7 +76,7 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False
)
genesis_deposits.append(deposit)

return genesis_deposits, root
return genesis_deposits, root, deposit_data_list


def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_credentials=None, signed=False):
Expand Down
13 changes: 7 additions & 6 deletions test_libs/pyspec/eth2spec/test/helpers/genesis.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from eth2spec.test.helpers.keys import pubkeys
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
from eth2spec.utils.ssz.ssz_typing import List
import copy


def build_mock_validator(spec, i: int, balance: int):
Expand All @@ -18,28 +19,28 @@ def build_mock_validator(spec, i: int, balance: int):
)


def create_genesis_state(spec, num_validators):
def create_genesis_state(spec, validator_balances, activation_threshold):
deposit_root = b'\x42' * 32

state = spec.BeaconState(
genesis_time=0,
eth1_deposit_index=num_validators,
eth1_deposit_index=len(validator_balances),
eth1_data=spec.Eth1Data(
deposit_root=deposit_root,
deposit_count=num_validators,
deposit_count=len(validator_balances),
block_hash=spec.Hash(),
),
latest_block_header=spec.BeaconBlockHeader(body_root=spec.hash_tree_root(spec.BeaconBlockBody())),
)

# We "hack" in the initial validators,
# as it is much faster than creating and processing genesis deposits for every single test case.
state.balances = [spec.MAX_EFFECTIVE_BALANCE] * num_validators
state.validators = [build_mock_validator(spec, i, state.balances[i]) for i in range(num_validators)]
state.balances = copy.deepcopy(validator_balances)
state.validators = [build_mock_validator(spec, i, state.balances[i]) for i in range(len(validator_balances))]

# Process genesis activations
for validator in state.validators:
if validator.effective_balance >= spec.MAX_EFFECTIVE_BALANCE:
if validator.effective_balance >= activation_threshold:
validator.activation_eligibility_epoch = spec.GENESIS_EPOCH
validator.activation_epoch = spec.GENESIS_EPOCH

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases, with_phases
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, \
with_all_phases, with_phases, spec_test, low_balances, with_custom_state
from eth2spec.test.helpers.attestations import (
get_valid_attestation,
sign_aggregate_attestation,
Expand Down Expand Up @@ -56,6 +57,17 @@ def test_success(spec, state):
yield from run_attestation_processing(spec, state, attestation)


@with_all_phases
@spec_test
@with_custom_state(balances_fn=low_balances, threshold_fn=lambda spec: spec.EJECTION_BALANCE)
def test_success_multi_proposer_index_iterations(spec, state):
state.slot += spec.SLOTS_PER_EPOCH * 2
attestation = get_valid_attestation(spec, state, signed=True)
state.slot += spec.MIN_ATTESTATION_INCLUSION_DELAY

yield from run_attestation_processing(spec, state, attestation)


@with_all_phases
@spec_state_test
def test_success_previous_epoch(spec, state):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def get_shards_for_slot(spec, state, slot):
return [shard + i for i in range(committees_per_slot)]


def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False):
def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False, messed_up_target=False):
# we must be at the end of the epoch
assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0

Expand Down Expand Up @@ -67,6 +67,8 @@ def add_mock_attestations(spec, state, epoch, source, target, sufficient_support
),
inclusion_delay=1,
))
if messed_up_target:
attestations[len(attestations) - 1].data.target.root = b'\x99' * 32


def get_checkpoints(spec, epoch):
Expand Down Expand Up @@ -196,7 +198,7 @@ def finalize_on_123(spec, state, epoch, sufficient_support):
assert state.finalized_checkpoint == old_finalized # no new finalized


def finalize_on_12(spec, state, epoch, sufficient_support):
def finalize_on_12(spec, state, epoch, sufficient_support, messed_up_target):
assert epoch > 2
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch

Expand All @@ -218,13 +220,14 @@ def finalize_on_12(spec, state, epoch, sufficient_support):
epoch=epoch - 1,
source=c2,
target=c1,
sufficient_support=sufficient_support)
sufficient_support=sufficient_support,
messed_up_target=messed_up_target)

# process!
yield from run_process_just_and_fin(spec, state)

assert state.previous_justified_checkpoint == c2 # changed to old current
if sufficient_support:
if sufficient_support and not messed_up_target:
assert state.current_justified_checkpoint == c1 # changed to 1st latest
assert state.finalized_checkpoint == c2 # finalized previous justified epoch
else:
Expand Down Expand Up @@ -271,10 +274,16 @@ def test_123_poor_support(spec, state):
@with_all_phases
@spec_state_test
def test_12_ok_support(spec, state):
yield from finalize_on_12(spec, state, 3, True)
yield from finalize_on_12(spec, state, 3, True, False)


@with_all_phases
@spec_state_test
def test_12_ok_support_messed_target(spec, state):
yield from finalize_on_12(spec, state, 3, True, True)


@with_all_phases
@spec_state_test
def test_12_poor_support(spec, state):
yield from finalize_on_12(spec, state, 3, False)
yield from finalize_on_12(spec, state, 3, False, False)
Loading