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

Update test vector generators #1238

Merged
merged 17 commits into from
Jun 30, 2019
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion specs/test_formats/bls/msg_hash_g2_compressed.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A BLS compressed-hash to G2.
```yaml
input:
message: bytes32,
domain: bytes -- any number
domain: uint64 -- the BLS domain
output: List[bytes48] -- length of two
```

Expand Down
4 changes: 2 additions & 2 deletions specs/test_formats/bls/msg_hash_g2_uncompressed.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ A BLS uncompressed-hash to G2.

```yaml
input:
message: bytes32,
domain: bytes -- any number
message: bytes32
domain: uint64 -- the BLS domain
output: List[List[bytes48]] -- 3 lists, each a length of two
```

Expand Down
2 changes: 1 addition & 1 deletion specs/test_formats/bls/sign_msg.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Message signing with BLS should produce a signature.
input:
privkey: bytes32 -- the private key used for signing
message: bytes32 -- input message to sign (a hash)
domain: bytes -- BLS domain
domain: uint64 -- the BLS domain
output: bytes96 -- expected signature
```

Expand Down
14 changes: 9 additions & 5 deletions specs/test_formats/epoch_processing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ post: BeaconState -- state after applying the epoch sub-transition.
## Condition

A handler of the `epoch_processing` test-runner should process these cases,
calling the corresponding processing implementation.
calling the corresponding processing implementation (same name, prefixed with `process_`).
This excludes the other parts of the epoch-transition.
The provided pre-state is already transitioned to just before the specific sub-transition of focus of the handler.

Sub-transitions:

| *`sub-transition-name`* | *`processing call`* |
|-------------------------|-----------------------------------|
| `crosslinks` | `process_crosslinks(state)` |
| `registry_updates` | `process_registry_updates(state)` |
- `justification_and_finalization`
- `crosslinks`
- *`rewards_and_penalties` - planned testing extension*
- `registry_updates`
- `slashings`
- `final_updates`

The resulting state should match the expected `post` state.
8 changes: 8 additions & 0 deletions specs/test_formats/genesis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Genesis tests

The aim of the genesis tests is to provide a baseline to test genesis-state initialization and test
if the proposed genesis-validity conditions are working.

There are two handlers, documented individually:
- [`validity`](./validity.md): Tests if a genesis state is valid, i.e. if it counts as trigger to launch.
- [`initialization`](./initialization.md): Tests the initialization of a genesis state based on Eth1 data.
22 changes: 22 additions & 0 deletions specs/test_formats/genesis/initialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Genesis creation testing

Tests the initialization of a genesis state based on Eth1 data.

## Test case format

```yaml
description: string -- description of test case, purely for debugging purposes
bls_setting: int -- see general test-format spec.
eth1_block_hash: Bytes32 -- the root of the Eth-1 block, hex encoded, with prefix 0x
eth1_timestamp: int -- the timestamp of the block, in seconds.
deposits: [Deposit] -- list of deposits to build the genesis state with
state: BeaconState -- the expected genesis state.
```

To process this test, build a genesis state with the provided `eth1_block_hash`, `eth1_timestamp` and `deposits`:
`initialize_beacon_state_from_eth1(eth1_block_hash, eth1_timestamp, deposits)`,
as described in the Beacon Chain specification.

## Condition

The resulting state should match the expected `state`.
19 changes: 19 additions & 0 deletions specs/test_formats/genesis/validity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Genesis validity testing

Tests if a genesis state is valid, i.e. if it counts as trigger to launch.

## Test case format

```yaml
description: string -- description of test case, purely for debugging purposes
bls_setting: int -- see general test-format spec.
genesis: BeaconState -- state to validate.
is_valid: bool -- true if the genesis state is deemed valid as to launch with, false otherwise.
```

To process the data, call `is_valid_genesis_state(genesis)`.


## Condition

The result of calling `is_valid_genesis_state(genesis)` should match the expected `is_valid` boolean.
5 changes: 3 additions & 2 deletions specs/test_formats/operations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ post: BeaconState -- state after applying the operation. No

A handler of the `operations` test-runner should process these cases,
calling the corresponding processing implementation.
This excludes the other parts of the block-transition.

Operations:

| *`operation-name`* | *`operation-object`* | *`input name`* | *`processing call`* |
|-------------------------|----------------------|----------------------|--------------------------------------------------------|
| `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` |
| `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` |
| `attestation` | `Attestation` | `attestation` | `process_attestation(state, attestation)` |
| `attester_slashing` | `AttesterSlashing` | `attester_slashing` | `process_attester_slashing(state, attester_slashing)` |
| `block_header` | `Block` | `block` | `process_block_header(state, block)` |
| `deposit` | `Deposit` | `deposit` | `process_deposit(state, deposit)` |
| `proposer_slashing` | `ProposerSlashing` | `proposer_slashing` | `process_proposer_slashing(state, proposer_slashing)` |
Expand Down
5 changes: 2 additions & 3 deletions specs/test_formats/sanity/slots.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ slots: N -- amount of slots to process, N being a positive number.
post: BeaconState -- state after applying all the transitions.
```

The transition with pure time, no blocks, is known as `state_transition_to(state, slot)` in the spec.
The transition with pure time, no blocks, is known as `process_slots(state, slot)` in the spec.
This runs state-caching (pure slot transition) and epoch processing (every E slots).

To process the data, call `state_transition_to(pre, pre.slot + N)`. And see if `pre` mutated into the equivalent of `post`.

To process the data, call `process_slots(pre, pre.slot + N)`.

## Condition

Expand Down
9 changes: 3 additions & 6 deletions test_generators/bls/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ def hex_to_int(x: str) -> int:
return int(x, 16)


# Note: even though a domain is only an uint64,
# To avoid issues with YAML parsers that are limited to 53-bit (JS language limit)
# It is serialized as an hex string as well.
DOMAINS = [
0,
1,
Expand Down Expand Up @@ -92,7 +89,7 @@ def case01_message_hash_G2_uncompressed():
yield {
'input': {
'message': '0x' + msg.hex(),
'domain': int_to_hex(domain)
'domain': domain
},
'output': hash_message(msg, domain)
}
Expand All @@ -104,7 +101,7 @@ def case02_message_hash_G2_compressed():
yield {
'input': {
'message': '0x' + msg.hex(),
'domain': int_to_hex(domain)
'domain': domain
},
'output': hash_message_compressed(msg, domain)
}
Expand All @@ -129,7 +126,7 @@ def case04_sign_messages():
'input': {
'privkey': int_to_hex(privkey),
'message': '0x' + message.hex(),
'domain': int_to_hex(domain)
'domain': domain
},
'output': '0x' + sig.hex()
}
Expand Down
13 changes: 12 additions & 1 deletion test_generators/epoch_processing/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from eth2spec.phase1 import spec as spec_phase1
from eth2spec.test.phase_0.epoch_processing import (
test_process_crosslinks,
test_process_registry_updates
test_process_final_updates,
test_process_justification_and_finalization,
test_process_registry_updates,
test_process_slashings
)
from gen_base import gen_runner, gen_suite, gen_typing
from gen_from_tests.gen import generate_from_tests
Expand Down Expand Up @@ -35,8 +38,16 @@ def suite_definition(configs_path: str) -> gen_typing.TestSuiteOutput:
gen_runner.run_generator("epoch_processing", [
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('final_updates', 'minimal', lambda: generate_from_tests(test_process_final_updates, 'phase0')),
create_suite('final_updates', 'mainnet', lambda: generate_from_tests(test_process_final_updates, 'phase0')),
create_suite('justification_and_finalization', 'minimal',
lambda: generate_from_tests(test_process_justification_and_finalization, 'phase0')),
create_suite('justification_and_finalization', 'mainnet',
lambda: generate_from_tests(test_process_justification_and_finalization, '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')),
create_suite('slashings', 'minimal', lambda: generate_from_tests(test_process_slashings, 'phase0')),
create_suite('slashings', 'mainnet', lambda: generate_from_tests(test_process_slashings, 'phase0')),
])
8 changes: 8 additions & 0 deletions test_generators/genesis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Genesis test generator

Genesis tests cover the initialization and validity-based launch trigger for the Beacon Chain genesis state.

Information on the format of the tests can be found in the [genesis test formats documentation](../../specs/test_formats/genesis/README.md).



33 changes: 33 additions & 0 deletions test_generators/genesis/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import Callable, Iterable

from eth2spec.test.genesis import test_initialization, test_validity

from gen_base import gen_runner, gen_suite, gen_typing
from gen_from_tests.gen import generate_from_tests
from preset_loader import loader
from eth2spec.phase0 import spec as spec


def create_suite(handler_name: str, config_name: str, get_cases: Callable[[], Iterable[gen_typing.TestCase]]) \
-> Callable[[str], gen_typing.TestSuiteOutput]:
def suite_definition(configs_path: str) -> gen_typing.TestSuiteOutput:
presets = loader.load_presets(configs_path, config_name)
spec.apply_constants_preset(presets)

return ("genesis_%s_%s" % (handler_name, config_name), handler_name, gen_suite.render_suite(
title="genesis testing",
summary="Genesis test suite, %s type, generated from pytests" % handler_name,
forks_timeline="testing",
forks=["phase0"],
config=config_name,
runner="genesis",
handler=handler_name,
test_cases=get_cases()))
return suite_definition


if __name__ == "__main__":
gen_runner.run_generator("genesis", [
create_suite('initialization', 'minimal', lambda: generate_from_tests(test_initialization, 'phase0')),
create_suite('validity', 'minimal', lambda: generate_from_tests(test_validity, 'phase0')),
])
4 changes: 4 additions & 0 deletions test_generators/genesis/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
eth-utils==1.6.0
../../test_libs/gen_helpers
../../test_libs/config_helpers
../../test_libs/pyspec
4 changes: 3 additions & 1 deletion test_generators/operations/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ def suite_definition(configs_path: str) -> gen_typing.TestSuiteOutput:
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')),
# Disabled, due to the high amount of different transfer tests, this produces a shocking size of tests.
# Unnecessarily, as transfer are disabled currently, so not a priority.
# 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')),
])
2 changes: 1 addition & 1 deletion test_generators/shuffling/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
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)]
yield 'shuffled', [int(spec.get_shuffled_index(i, count, seed)) for i in range(count)]


@to_tuple
Expand Down
4 changes: 2 additions & 2 deletions test_libs/pyspec/eth2spec/debug/encode.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from eth2spec.utils.ssz.ssz_impl import hash_tree_root
from eth2spec.utils.ssz.ssz_typing import (
SSZValue, uint, Container, boolean
uint, Container, boolean
)


def encode(value: SSZValue, include_hash_tree_roots=False):
def encode(value, include_hash_tree_roots=False):
if isinstance(value, uint):
# Larger uints are boxed and the class declares their byte length
if value.type().byte_len > 8:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ def create_valid_beacon_state(spec):
def run_is_valid_genesis_state(spec, state, valid=True):
"""
Run ``is_valid_genesis_state``, yielding:
- state ('state')
- genesis ('state')
- is_valid ('is_valid')
If ``valid == False``, run expecting ``AssertionError``
"""
yield state
yield 'genesis', state
is_valid = spec.is_valid_genesis_state(state)
yield 'is_valid', is_valid
assert is_valid == valid


@with_phases(['phase0'])
Expand All @@ -39,7 +39,7 @@ def test_is_valid_genesis_state_false_invalid_timestamp(spec):
state = create_valid_beacon_state(spec)
state.genesis_time = spec.MIN_GENESIS_TIME - 1

yield from run_is_valid_genesis_state(spec, state, valid=True)
yield from run_is_valid_genesis_state(spec, state, valid=False)


@with_phases(['phase0'])
Expand All @@ -51,13 +51,14 @@ def test_is_valid_genesis_state_true_more_balance(spec):
yield from run_is_valid_genesis_state(spec, state, valid=True)


@with_phases(['phase0'])
@spectest_with_bls_switch
def test_is_valid_genesis_state_false_not_enough_balance(spec):
state = create_valid_beacon_state(spec)
state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE - 1

yield from run_is_valid_genesis_state(spec, state, valid=False)
# TODO: not part of the genesis function yet. Erroneously merged.
# @with_phases(['phase0'])
# @spectest_with_bls_switch
# def test_is_valid_genesis_state_false_not_enough_balance(spec):
# state = create_valid_beacon_state(spec)
# state.validators[0].effective_balance = spec.MAX_EFFECTIVE_BALANCE - 1
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
#
# yield from run_is_valid_genesis_state(spec, state, valid=False)


@with_phases(['phase0'])
Expand Down
Loading