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

phase restricted generators #1165

Merged
merged 12 commits into from
Jun 11, 2019
12 changes: 7 additions & 5 deletions test_generators/epoch_processing/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.test.epoch_processing import (
from eth2spec.test.phase_0.epoch_processing import (
test_process_crosslinks,
test_process_registry_updates
)
Expand Down Expand Up @@ -33,8 +33,10 @@ def suite_definition(configs_path: str) -> gen_typing.TestSuiteOutput:

if __name__ == "__main__":
gen_runner.run_generator("epoch_processing", [
create_suite('crosslinks', 'minimal', lambda: generate_from_tests(test_process_crosslinks)),
create_suite('crosslinks', 'mainnet', lambda: generate_from_tests(test_process_crosslinks)),
create_suite('registry_updates', 'minimal', lambda: generate_from_tests(test_process_registry_updates)),
create_suite('registry_updates', 'mainnet', lambda: generate_from_tests(test_process_registry_updates)),
create_suite('crosslinks', 'minimal', lambda: generate_from_tests(test_process_crosslinks, 'phase0')),
create_suite('crosslinks', 'mainnet', lambda: generate_from_tests(test_process_crosslinks, 'phase0')),
create_suite('registry_updates', 'minimal',
lambda: generate_from_tests(test_process_registry_updates, 'phase0')),
create_suite('registry_updates', 'mainnet',
lambda: generate_from_tests(test_process_registry_updates, 'phase0')),
])
32 changes: 16 additions & 16 deletions test_generators/operations/main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from typing import Callable, Iterable

from eth2spec.test.block_processing import (
from eth2spec.test.phase_0.block_processing import (
test_process_attestation,
test_process_attester_slashing,
test_process_block_header,
test_process_deposit,
test_process_proposer_slashing,
test_process_transfer,
test_process_voluntary_exit
test_process_voluntary_exit,
)

from gen_base import gen_runner, gen_suite, gen_typing
Expand Down Expand Up @@ -38,18 +38,18 @@ def suite_definition(configs_path: str) -> gen_typing.TestSuiteOutput:

if __name__ == "__main__":
gen_runner.run_generator("operations", [
create_suite('attestation', 'minimal', lambda: generate_from_tests(test_process_attestation)),
create_suite('attestation', 'mainnet', lambda: generate_from_tests(test_process_attestation)),
create_suite('attester_slashing', 'minimal', lambda: generate_from_tests(test_process_attester_slashing)),
create_suite('attester_slashing', 'mainnet', lambda: generate_from_tests(test_process_attester_slashing)),
create_suite('block_header', 'minimal', lambda: generate_from_tests(test_process_block_header)),
create_suite('block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header)),
create_suite('deposit', 'minimal', lambda: generate_from_tests(test_process_deposit)),
create_suite('deposit', 'mainnet', lambda: generate_from_tests(test_process_deposit)),
create_suite('proposer_slashing', 'minimal', lambda: generate_from_tests(test_process_proposer_slashing)),
create_suite('proposer_slashing', 'mainnet', lambda: generate_from_tests(test_process_proposer_slashing)),
create_suite('transfer', 'minimal', lambda: generate_from_tests(test_process_transfer)),
create_suite('transfer', 'mainnet', lambda: generate_from_tests(test_process_transfer)),
create_suite('voluntary_exit', 'minimal', lambda: generate_from_tests(test_process_voluntary_exit)),
create_suite('voluntary_exit', 'mainnet', lambda: generate_from_tests(test_process_voluntary_exit)),
create_suite('attestation', 'minimal', lambda: generate_from_tests(test_process_attestation, 'phase0')),
create_suite('attestation', 'mainnet', lambda: generate_from_tests(test_process_attestation, 'phase0')),
create_suite('attester_slashing', 'minimal', lambda: generate_from_tests(test_process_attester_slashing, 'phase0')),
create_suite('attester_slashing', 'mainnet', lambda: generate_from_tests(test_process_attester_slashing, 'phase0')),
create_suite('block_header', 'minimal', lambda: generate_from_tests(test_process_block_header, 'phase0')),
create_suite('block_header', 'mainnet', lambda: generate_from_tests(test_process_block_header, 'phase0')),
create_suite('deposit', 'minimal', lambda: generate_from_tests(test_process_deposit, 'phase0')),
create_suite('deposit', 'mainnet', lambda: generate_from_tests(test_process_deposit, 'phase0')),
create_suite('proposer_slashing', 'minimal', lambda: generate_from_tests(test_process_proposer_slashing, 'phase0')),
create_suite('proposer_slashing', 'mainnet', lambda: generate_from_tests(test_process_proposer_slashing, 'phase0')),
create_suite('transfer', 'minimal', lambda: generate_from_tests(test_process_transfer, 'phase0')),
create_suite('transfer', 'mainnet', lambda: generate_from_tests(test_process_transfer, 'phase0')),
create_suite('voluntary_exit', 'minimal', lambda: generate_from_tests(test_process_voluntary_exit, 'phase0')),
create_suite('voluntary_exit', 'mainnet', lambda: generate_from_tests(test_process_voluntary_exit, 'phase0')),
])
10 changes: 5 additions & 5 deletions test_generators/sanity/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def suite_definition(configs_path: str) -> gen_typing.TestSuiteOutput:
spec_phase0.apply_constants_preset(presets)
spec_phase1.apply_constants_preset(presets)

return ("%sanity_s_%s" % (handler_name, config_name), handler_name, gen_suite.render_suite(
return ("sanity_%s_%s" % (handler_name, config_name), handler_name, gen_suite.render_suite(
title="sanity testing",
summary="Sanity test suite, %s type, generated from pytests" % handler_name,
forks_timeline="testing",
Expand All @@ -30,8 +30,8 @@ def suite_definition(configs_path: str) -> gen_typing.TestSuiteOutput:

if __name__ == "__main__":
gen_runner.run_generator("sanity", [
create_suite('blocks', 'minimal', lambda: generate_from_tests(test_blocks)),
create_suite('blocks', 'mainnet', lambda: generate_from_tests(test_blocks)),
create_suite('slots', 'minimal', lambda: generate_from_tests(test_slots)),
create_suite('slots', 'mainnet', lambda: generate_from_tests(test_slots)),
create_suite('blocks', 'minimal', lambda: generate_from_tests(test_blocks, 'phase0')),
create_suite('blocks', 'mainnet', lambda: generate_from_tests(test_blocks, 'phase0')),
create_suite('slots', 'minimal', lambda: generate_from_tests(test_slots, 'phase0')),
create_suite('slots', 'mainnet', lambda: generate_from_tests(test_slots, 'phase0')),
])
11 changes: 4 additions & 7 deletions test_generators/shuffling/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from eth2spec.phase0 import spec as spec_phase0
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.phase0 import spec as spec
from eth_utils import (
to_dict, to_tuple
)
Expand All @@ -8,7 +7,7 @@


@to_dict
def shuffling_case(seed: spec.Bytes32, count: int):
def shuffling_case(seed, count):
yield 'seed', '0x' + seed.hex()
yield 'count', count
yield 'shuffled', [spec.get_shuffled_index(i, count, seed) for i in range(count)]
Expand All @@ -23,8 +22,7 @@ def shuffling_test_cases():

def mini_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
presets = loader.load_presets(configs_path, 'minimal')
spec_phase0.apply_constants_preset(presets)
spec_phase1.apply_constants_preset(presets)
spec.apply_constants_preset(presets)

return ("shuffling_minimal", "core", gen_suite.render_suite(
title="Swap-or-Not Shuffling tests with minimal config",
Expand All @@ -39,8 +37,7 @@ def mini_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:

def full_shuffling_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
presets = loader.load_presets(configs_path, 'mainnet')
spec_phase0.apply_constants_preset(presets)
spec_phase1.apply_constants_preset(presets)
spec.apply_constants_preset(presets)

return ("shuffling_full", "core", gen_suite.render_suite(
title="Swap-or-Not Shuffling tests with mainnet config",
Expand Down
19 changes: 13 additions & 6 deletions test_generators/ssz_static/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from random import Random

from inspect import getmembers, isclass

from eth2spec.debug import random_value, encode
from eth2spec.phase0 import spec
from eth2spec.utils.ssz.ssz_typing import Container
from eth2spec.utils.ssz.ssz_impl import (
hash_tree_root,
signing_root,
Expand All @@ -27,17 +30,23 @@ def create_test_case_contents(value, typ):


@to_dict
def create_test_case(rng: Random, name: str, mode: random_value.RandomizationMode, chaos: bool):
typ = spec.get_ssz_type_by_name(name)
def create_test_case(rng: Random, name: str, typ, mode: random_value.RandomizationMode, chaos: bool):
value = random_value.get_random_ssz_object(rng, typ, MAX_BYTES_LENGTH, MAX_LIST_LENGTH, mode, chaos)
yield name, create_test_case_contents(value, typ)


def get_spec_ssz_types():
return [
(name, value) for (name, value) in getmembers(spec, isclass)
if issubclass(value, Container) and value != Container # only the subclasses, not the imported base class
]


@to_tuple
def ssz_static_cases(rng: Random, mode: random_value.RandomizationMode, chaos: bool, count: int):
for type_name in spec.ssz_types:
for (name, ssz_type) in get_spec_ssz_types():
for i in range(count):
yield create_test_case(rng, type_name, mode, chaos)
yield create_test_case(rng, name, ssz_type, mode, chaos)


def get_ssz_suite(seed: int, config_name: str, mode: random_value.RandomizationMode, chaos: bool, cases_if_random: int):
Expand Down Expand Up @@ -81,8 +90,6 @@ def ssz_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
settings.append((seed, "mainnet", random_value.RandomizationMode.mode_random, False, 5))
seed += 1

print("Settings: %d, SSZ-types: %d" % (len(settings), len(spec.ssz_types)))

gen_runner.run_generator("ssz_static", [
get_ssz_suite(seed, config_name, mode, chaos, cases_if_random)
for (seed, config_name, mode, chaos, cases_if_random) in settings
Expand Down
7 changes: 4 additions & 3 deletions test_libs/gen_helpers/gen_from_tests/gen.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from inspect import getmembers, isfunction

def generate_from_tests(src, bls_active=True):
def generate_from_tests(src, phase, bls_active=True):
"""
Generate a list of test cases by running tests from the given src in generator-mode.
:param src: to retrieve tests from (discovered using inspect.getmembers)
:param src: to retrieve tests from (discovered using inspect.getmembers).
:param phase: to run tests against particular phase.
:param bls_active: optional, to override BLS switch preference. Defaults to True.
:return: the list of test cases.
"""
Expand All @@ -16,7 +17,7 @@ def generate_from_tests(src, bls_active=True):
for name in fn_names:
tfn = getattr(src, name)
try:
test_case = tfn(generator_mode=True, bls_active=bls_active)
test_case = tfn(generator_mode=True, phase=phase, bls_active=bls_active)
# If no test case data is returned, the test is ignored.
if test_case is not None:
out.append(test_case)
Expand Down
20 changes: 15 additions & 5 deletions test_libs/pyspec/eth2spec/test/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,22 @@ def with_phases(phases):
def decorator(fn):
def run_with_spec_version(spec, *args, **kw):
kw['spec'] = spec
fn(*args, **kw)
return fn(*args, **kw)

def wrapper(*args, **kw):
if 'phase0' in phases:
run_with_spec_version(spec_phase0, *args, **kw)
if 'phase1' in phases:
run_with_spec_version(spec_phase1, *args, **kw)
run_phases = phases

# limit phases if one explicitly specified
if 'phase' in kw:
phase = kw.pop('phase')
if phase not in phases:
return
run_phases = [phase]

if 'phase0' in run_phases:
ret = run_with_spec_version(spec_phase0, *args, **kw)
if 'phase1' in run_phases:
ret = run_with_spec_version(spec_phase1, *args, **kw)
return ret
return wrapper
return decorator
44 changes: 22 additions & 22 deletions test_libs/pyspec/eth2spec/test/sanity/test_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from eth2spec.utils.bls import bls_sign

from eth2spec.test.helpers.state import get_balance
from eth2spec.test.helpers.transfers import get_valid_transfer
# from eth2spec.test.helpers.transfers import get_valid_transfer
from eth2spec.test.helpers.block import build_empty_block_for_next_slot, sign_block
from eth2spec.test.helpers.keys import privkeys, pubkeys
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing
Expand Down Expand Up @@ -303,38 +303,38 @@ def test_voluntary_exit(spec, state):
assert state.validator_registry[validator_index].exit_epoch < spec.FAR_FUTURE_EPOCH


@with_all_phases
@spec_state_test
def test_transfer(spec, state):
# @with_all_phases
# @spec_state_test
# def test_transfer(spec, state):
# overwrite default 0 to test
spec.MAX_TRANSFERS = 1
# spec.MAX_TRANSFERS = 1

sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
amount = get_balance(state, sender_index)
# sender_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
# amount = get_balance(state, sender_index)

transfer = get_valid_transfer(spec, state, state.slot + 1, sender_index, amount, signed=True)
recipient_index = transfer.recipient
pre_transfer_recipient_balance = get_balance(state, recipient_index)
# transfer = get_valid_transfer(spec, state, state.slot + 1, sender_index, amount, signed=True)
# recipient_index = transfer.recipient
# pre_transfer_recipient_balance = get_balance(state, recipient_index)

# un-activate so validator can transfer
state.validator_registry[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH
# state.validator_registry[sender_index].activation_eligibility_epoch = spec.FAR_FUTURE_EPOCH

yield 'pre', state
# yield 'pre', state

# Add to state via block transition
block = build_empty_block_for_next_slot(spec, state)
block.body.transfers.append(transfer)
sign_block(spec, state, block)
# block = build_empty_block_for_next_slot(spec, state)
# block.body.transfers.append(transfer)
# sign_block(spec, state, block)

yield 'blocks', [block], List[spec.BeaconBlock]
# yield 'blocks', [block], List[spec.BeaconBlock]

spec.state_transition(state, block)
yield 'post', state
# spec.state_transition(state, block)
# yield 'post', state

sender_balance = get_balance(state, sender_index)
recipient_balance = get_balance(state, recipient_index)
assert sender_balance == 0
assert recipient_balance == pre_transfer_recipient_balance + amount
# sender_balance = get_balance(state, sender_index)
# recipient_balance = get_balance(state, recipient_index)
# assert sender_balance == 0
# assert recipient_balance == pre_transfer_recipient_balance + amount


@with_all_phases
Expand Down
7 changes: 6 additions & 1 deletion test_libs/pyspec/eth2spec/test/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Dict, Any, Callable, Iterable
from eth2spec.debug.encode import encode
from eth2spec.utils.ssz.ssz_typing import Container


def spectest(description: str = None):
Expand Down Expand Up @@ -30,9 +31,13 @@ def entry(*args, **kw):
else:
# Otherwise, try to infer the type, but keep it as-is if it's not a SSZ container.
(key, value) = data
if hasattr(value.__class__, 'fields'):
if isinstance(value, Container):
out[key] = encode(value, value.__class__)
else:
# not a ssz value.
# It could be vector or bytes still, but it is a rare case,
# and lists can't be inferred fully (generics lose element type).
# In such cases, explicitly state the type of the yielded value as a third yielded object.
out[key] = value
if has_contents:
return out
Expand Down
25 changes: 24 additions & 1 deletion test_libs/pyspec/eth2spec/utils/hash_function.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
from hashlib import sha256

ZERO_BYTES32 = b'\x00' * 32

def hash(x):

def _hash(x):
return sha256(x).digest()


# Minimal collection of (key, value) pairs, for fast hash-retrieval, to save on repetitive computation cost.
# Key = the hash input
# Value = the hash output
hash_cache = []


def add_zero_hashes_to_cache():
zerohashes = [(None, ZERO_BYTES32)]
for layer in range(1, 32):
k = zerohashes[layer - 1][1] + zerohashes[layer - 1][1]
zerohashes.append((k, _hash(k)))
hash_cache.extend(zerohashes[1:])


def hash(x):
for (k, h) in hash_cache:
if x == k:
return h
return _hash(x)
4 changes: 1 addition & 3 deletions test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,13 +513,11 @@ def read_vector_elem_type(vector_typ: Type[Vector[T, L]]) -> T:


def read_elem_type(typ):
if typ == bytes:
if typ == bytes or (isinstance(typ, type) and issubclass(typ, bytes)): # bytes or bytesN
return byte
elif is_list_type(typ):
return read_list_elem_type(typ)
elif is_vector_type(typ):
return read_vector_elem_type(typ)
elif issubclass(typ, bytes): # bytes or bytesN
return byte
else:
raise TypeError("Unexpected type: {}".format(typ))