Fixed test_on_merge_block tests

This commit is contained in:
Dmitrii Shmatko 2021-09-24 21:06:02 +03:00
parent 457b0396dd
commit f8b3a67152
3 changed files with 83 additions and 52 deletions

View File

@ -1,5 +1,6 @@
from random import Random
from eth_utils import encode_hex
from eth2spec.test.exceptions import BlockNotFoundException
from eth2spec.utils.ssz.ssz_typing import uint256
from eth2spec.test.helpers.attestations import (
next_epoch_with_attestations,
@ -25,7 +26,7 @@ def add_block_to_store(spec, store, signed_block):
def tick_and_add_block(spec, store, signed_block, test_steps, valid=True, allow_invalid_attestations=False,
merge_block=False):
merge_block=False, block_not_found=False):
pre_state = store.block_states[signed_block.message.parent_root]
block_time = pre_state.genesis_time + signed_block.message.slot * spec.config.SECONDS_PER_SLOT
if merge_block:
@ -35,7 +36,8 @@ def tick_and_add_block(spec, store, signed_block, test_steps, valid=True, allow_
on_tick_and_append_step(spec, store, block_time, test_steps)
post_state = yield from add_block(
spec, store, signed_block, test_steps, valid=valid, allow_invalid_attestations=allow_invalid_attestations)
spec, store, signed_block, test_steps, valid=valid, allow_invalid_attestations=allow_invalid_attestations,
block_not_found=block_not_found)
return post_state
@ -123,7 +125,8 @@ def run_on_block(spec, store, signed_block, valid=True):
assert store.blocks[signed_block.message.hash_tree_root()] == signed_block.message
def add_block(spec, store, signed_block, test_steps, valid=True, allow_invalid_attestations=False):
def add_block(spec, store, signed_block, test_steps, valid=True, allow_invalid_attestations=False,
block_not_found=False):
"""
Run on_block and on_attestation
"""
@ -132,7 +135,9 @@ def add_block(spec, store, signed_block, test_steps, valid=True, allow_invalid_a
if not valid:
try:
run_on_block(spec, store, signed_block, valid=True)
except AssertionError:
except (AssertionError, BlockNotFoundException) as e:
if isinstance(e, BlockNotFoundException) and not block_not_found:
assert False
test_steps.append({
'block': get_block_file_name(signed_block),
'valid': False,
@ -241,3 +246,12 @@ def prepare_empty_pow_block(spec, rng=Random(3131)):
total_difficulty=uint256(0),
difficulty=uint256(0)
)
def get_pow_block_file_name(pow_block):
return f"pow_block_{encode_hex(pow_block.block_hash)}"
def add_pow_block(spec, store, pow_block, test_steps):
yield get_pow_block_file_name(pow_block), pow_block
test_steps.append({'pow_block': get_pow_block_file_name(pow_block)})

View File

@ -1,7 +1,8 @@
from eth2spec.utils.ssz.ssz_typing import uint256
from eth2spec.test.context import spec_state_test, with_phases, MERGE
from eth2spec.test.exceptions import BlockNotFoundException
from eth2spec.test.context import spec_state_test, with_phases, with_presets, MERGE, MINIMAL
from eth2spec.test.helpers.block import (
build_empty_block_for_next_slot
build_empty_block_for_next_slot,
)
from eth2spec.test.helpers.fork_choice import (
get_genesis_forkchoice_store_and_block,
@ -13,6 +14,7 @@ from eth2spec.test.helpers.state import (
)
from eth2spec.test.helpers.fork_choice import (
prepare_empty_pow_block,
add_pow_block,
)
@ -21,7 +23,7 @@ def with_pow_block_patch(spec, blocks, func):
for block in blocks:
if block.block_hash == hash:
return block
raise Exception("Block not found")
raise BlockNotFoundException()
get_pow_block_backup = spec.get_pow_block
spec.get_pow_block = get_pow_block
@ -30,21 +32,23 @@ def with_pow_block_patch(spec, blocks, func):
is_called = AtomicBoolean()
def wrap(flag: AtomicBoolean):
func()
yield from func()
flag.value = True
try:
wrap(is_called)
yield from wrap(is_called)
finally:
spec.get_pow_block = get_pow_block_backup
assert is_called.value
@with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test
def test_all_valid(spec, state):
test_steps = []
# Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state
yield 'anchor_block', anchor_block
@ -52,30 +56,34 @@ def test_all_valid(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
parent_block = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
block = prepare_empty_pow_block(spec)
block.parent_hash = parent_block.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_blocks = [block, parent_block]
yield 'pow_blocks', pow_blocks
pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_block = prepare_empty_pow_block(spec)
pow_block.parent_hash = pow_block_parent.block_hash
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_blocks = [pow_block, pow_block_parent]
for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func():
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_block.block_hash
signed_block = state_transition_and_sign_block(spec, state, block)
yield from tick_and_add_block(spec, store, signed_block, test_steps)
yield from tick_and_add_block(spec, store, signed_block, test_steps, merge_block=True)
# valid
assert spec.get_head(store) == signed_block.message.hash_tree_root()
with_pow_block_patch(spec, pow_blocks, run_func)
yield from with_pow_block_patch(spec, pow_blocks, run_func)
yield 'steps', test_steps
@with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test
def test_block_lookup_failed(spec, state):
test_steps = []
# Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state
yield 'anchor_block', anchor_block
@ -83,27 +91,30 @@ def test_block_lookup_failed(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
parent_block = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [parent_block]
yield 'pow_blocks', pow_blocks
pow_block = prepare_empty_pow_block(spec)
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [pow_block]
for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func():
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_block.block_hash
signed_block = state_transition_and_sign_block(spec, state, block)
yield from tick_and_add_block(spec, store, signed_block, test_steps)
# invalid
assert spec.get_head(store) == anchor_block.state_root
yield from tick_and_add_block(spec, store, signed_block, test_steps, valid=False, merge_block=True,
block_not_found=True)
with_pow_block_patch(spec, pow_blocks, run_func)
yield from with_pow_block_patch(spec, pow_blocks, run_func)
yield 'steps', test_steps
@with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test
def test_too_early_for_merge(spec, state):
test_steps = []
# Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state
yield 'anchor_block', anchor_block
@ -111,30 +122,32 @@ def test_too_early_for_merge(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
parent_block = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
block = prepare_empty_pow_block(spec)
block.parent_hash = parent_block.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [block, parent_block]
yield 'pow_blocks', pow_blocks
pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
pow_block = prepare_empty_pow_block(spec)
pow_block.parent_hash = pow_block_parent.block_hash
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [pow_block, pow_block_parent]
for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func():
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_block.block_hash
signed_block = state_transition_and_sign_block(spec, state, block)
yield from tick_and_add_block(spec, store, signed_block, test_steps)
# invalid
assert spec.get_head(store) == anchor_block.state_root
yield from tick_and_add_block(spec, store, signed_block, test_steps, valid=False, merge_block=True)
with_pow_block_patch(spec, pow_blocks, run_func)
yield from with_pow_block_patch(spec, pow_blocks, run_func)
yield 'steps', test_steps
@with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test
def test_too_late_for_merge(spec, state):
test_steps = []
# Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state
yield 'anchor_block', anchor_block
@ -142,20 +155,20 @@ def test_too_late_for_merge(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
parent_block = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = prepare_empty_pow_block(spec)
block.parent_hash = parent_block.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY + uint256(1)
pow_blocks = [block, parent_block]
yield 'pow_blocks', pow_blocks
pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_block = prepare_empty_pow_block(spec)
pow_block.parent_hash = pow_block_parent.block_hash
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY + uint256(1)
pow_blocks = [pow_block, pow_block_parent]
for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func():
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_block.block_hash
signed_block = state_transition_and_sign_block(spec, state, block)
yield from tick_and_add_block(spec, store, signed_block, test_steps)
# invalid
assert spec.get_head(store) == anchor_block.state_root
yield from tick_and_add_block(spec, store, signed_block, test_steps, valid=False, merge_block=True)
with_pow_block_patch(spec, pow_blocks, run_func)
yield from with_pow_block_patch(spec, pow_blocks, run_func)
yield 'steps', test_steps

View File

@ -71,12 +71,16 @@ After this step, the `store` object may have been updated.
#### `on_merge_block` execution
Adds `PowBlock` data which is required for executing `on_block(store, block)`.
Number of blocks is stored in `meta.yaml`, block file names are `pow_block_<number>.ssz_snappy`.
The file is located in the same folder.
Adds `PowBlock` data which is required for executing `on_block(store, block)`.
```yaml
{
pow_block: string -- the name of the `pow_block_<32-byte-root>.ssz_snappy` file.
To be used in `get_pow_block` lookup
}
```
The file is located in the same folder (see below).
PowBlocks should be used as return values for `get_pow_block(hash: Hash32) -> PowBlock` function if hashes match.
#### Checks step
The checks to verify the current status of `store`.