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 random import Random
from eth_utils import encode_hex from eth_utils import encode_hex
from eth2spec.test.exceptions import BlockNotFoundException
from eth2spec.utils.ssz.ssz_typing import uint256 from eth2spec.utils.ssz.ssz_typing import uint256
from eth2spec.test.helpers.attestations import ( from eth2spec.test.helpers.attestations import (
next_epoch_with_attestations, 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, 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] 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 block_time = pre_state.genesis_time + signed_block.message.slot * spec.config.SECONDS_PER_SLOT
if merge_block: 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) on_tick_and_append_step(spec, store, block_time, test_steps)
post_state = yield from add_block( 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 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 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 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: if not valid:
try: try:
run_on_block(spec, store, signed_block, valid=True) 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({ test_steps.append({
'block': get_block_file_name(signed_block), 'block': get_block_file_name(signed_block),
'valid': False, 'valid': False,
@ -241,3 +246,12 @@ def prepare_empty_pow_block(spec, rng=Random(3131)):
total_difficulty=uint256(0), total_difficulty=uint256(0),
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.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 ( 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 ( from eth2spec.test.helpers.fork_choice import (
get_genesis_forkchoice_store_and_block, get_genesis_forkchoice_store_and_block,
@ -13,6 +14,7 @@ from eth2spec.test.helpers.state import (
) )
from eth2spec.test.helpers.fork_choice import ( from eth2spec.test.helpers.fork_choice import (
prepare_empty_pow_block, prepare_empty_pow_block,
add_pow_block,
) )
@ -21,7 +23,7 @@ def with_pow_block_patch(spec, blocks, func):
for block in blocks: for block in blocks:
if block.block_hash == hash: if block.block_hash == hash:
return block return block
raise Exception("Block not found") raise BlockNotFoundException()
get_pow_block_backup = spec.get_pow_block get_pow_block_backup = spec.get_pow_block
spec.get_pow_block = 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() is_called = AtomicBoolean()
def wrap(flag: AtomicBoolean): def wrap(flag: AtomicBoolean):
func() yield from func()
flag.value = True flag.value = True
try: try:
wrap(is_called) yield from wrap(is_called)
finally: finally:
spec.get_pow_block = get_pow_block_backup spec.get_pow_block = get_pow_block_backup
assert is_called.value assert is_called.value
@with_phases([MERGE]) @with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test @spec_state_test
def test_all_valid(spec, state): def test_all_valid(spec, state):
test_steps = [] test_steps = []
# Initialization # Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state) store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state yield 'anchor_state', state
yield 'anchor_block', anchor_block 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) on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time assert store.time == current_time
parent_block = prepare_empty_pow_block(spec) pow_block_parent = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1) pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
block = prepare_empty_pow_block(spec) pow_block = prepare_empty_pow_block(spec)
block.parent_hash = parent_block.block_hash pow_block.parent_hash = pow_block_parent.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_blocks = [block, parent_block] pow_blocks = [pow_block, pow_block_parent]
yield 'pow_blocks', pow_blocks for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func(): def run_func():
block = build_empty_block_for_next_slot(spec, state) 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) 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 # valid
assert spec.get_head(store) == signed_block.message.hash_tree_root() 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 yield 'steps', test_steps
@with_phases([MERGE]) @with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test @spec_state_test
def test_block_lookup_failed(spec, state): def test_block_lookup_failed(spec, state):
test_steps = [] test_steps = []
# Initialization # Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state) store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state yield 'anchor_state', state
yield 'anchor_block', anchor_block 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) on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time assert store.time == current_time
parent_block = prepare_empty_pow_block(spec) pow_block = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1) pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [parent_block] pow_blocks = [pow_block]
yield 'pow_blocks', pow_blocks for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func(): def run_func():
block = build_empty_block_for_next_slot(spec, state) 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) 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, valid=False, merge_block=True,
# invalid block_not_found=True)
assert spec.get_head(store) == anchor_block.state_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 yield 'steps', test_steps
@with_phases([MERGE]) @with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test @spec_state_test
def test_too_early_for_merge(spec, state): def test_too_early_for_merge(spec, state):
test_steps = [] test_steps = []
# Initialization # Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state) store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state yield 'anchor_state', state
yield 'anchor_block', anchor_block 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) on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time assert store.time == current_time
parent_block = prepare_empty_pow_block(spec) pow_block_parent = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2) pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
block = prepare_empty_pow_block(spec) pow_block = prepare_empty_pow_block(spec)
block.parent_hash = parent_block.block_hash pow_block.parent_hash = pow_block_parent.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1) pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [block, parent_block] pow_blocks = [pow_block, pow_block_parent]
yield 'pow_blocks', pow_blocks for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func(): def run_func():
block = build_empty_block_for_next_slot(spec, state) 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) 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, valid=False, merge_block=True)
# invalid
assert spec.get_head(store) == anchor_block.state_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 yield 'steps', test_steps
@with_phases([MERGE]) @with_phases([MERGE])
@with_presets([MINIMAL], reason="mainnet `TERMINAL_TOTAL_DIFFICULTY` stub would cause overflow")
@spec_state_test @spec_state_test
def test_too_late_for_merge(spec, state): def test_too_late_for_merge(spec, state):
test_steps = [] test_steps = []
# Initialization # Initialization
state.latest_execution_payload_header = spec.ExecutionPayloadHeader()
store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state) store, anchor_block = get_genesis_forkchoice_store_and_block(spec, state)
yield 'anchor_state', state yield 'anchor_state', state
yield 'anchor_block', anchor_block 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) on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time assert store.time == current_time
parent_block = prepare_empty_pow_block(spec) pow_block_parent = prepare_empty_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = prepare_empty_pow_block(spec) pow_block = prepare_empty_pow_block(spec)
block.parent_hash = parent_block.block_hash pow_block.parent_hash = pow_block_parent.block_hash
block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY + uint256(1) pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY + uint256(1)
pow_blocks = [block, parent_block] pow_blocks = [pow_block, pow_block_parent]
yield 'pow_blocks', pow_blocks for pb in pow_blocks:
yield from add_pow_block(spec, store, pb, test_steps)
def run_func(): def run_func():
block = build_empty_block_for_next_slot(spec, state) 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) 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, valid=False, merge_block=True)
# invalid
assert spec.get_head(store) == anchor_block.state_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 yield 'steps', test_steps

View File

@ -71,12 +71,16 @@ After this step, the `store` object may have been updated.
#### `on_merge_block` execution #### `on_merge_block` execution
Adds `PowBlock` data which is required for executing `on_block(store, block)`. 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`. ```yaml
The file is located in the same folder. {
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. PowBlocks should be used as return values for `get_pow_block(hash: Hash32) -> PowBlock` function if hashes match.
#### Checks step #### Checks step
The checks to verify the current status of `store`. The checks to verify the current status of `store`.