Refine validate_merge_block unit tests
This commit is contained in:
parent
116017d4cb
commit
56bb393eb5
|
@ -1,7 +1,5 @@
|
|||
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,
|
||||
next_slots_with_attestations,
|
||||
|
@ -247,15 +245,6 @@ def apply_next_slots_with_attestations(spec,
|
|||
return post_state, store, last_signed_block
|
||||
|
||||
|
||||
def prepare_empty_pow_block(spec, rng=Random(3131)):
|
||||
return spec.PowBlock(
|
||||
block_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
|
||||
parent_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
|
||||
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)}"
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
from random import Random
|
||||
from eth2spec.utils.ssz.ssz_typing import uint256
|
||||
|
||||
|
||||
def prepare_empty_pow_block(spec, rng=Random(3131)):
|
||||
return spec.PowBlock(
|
||||
block_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
|
||||
parent_hash=spec.Hash32(spec.hash(bytearray(rng.getrandbits(8) for _ in range(32)))),
|
||||
total_difficulty=uint256(0),
|
||||
difficulty=uint256(0)
|
||||
)
|
||||
|
||||
|
||||
def prepare_random_pow_chain(spec, length, rng=Random(3131)):
|
||||
assert length > 0
|
||||
chain = [prepare_empty_pow_block(spec, rng)]
|
||||
for i in range(1, length):
|
||||
chain.append(prepare_empty_pow_block(spec, rng))
|
||||
chain[i].parent_hash = chain[i - 1].block_hash
|
||||
return chain
|
|
@ -13,9 +13,11 @@ from eth2spec.test.helpers.state import (
|
|||
state_transition_and_sign_block,
|
||||
)
|
||||
from eth2spec.test.helpers.fork_choice import (
|
||||
prepare_empty_pow_block,
|
||||
add_pow_block,
|
||||
)
|
||||
from eth2spec.test.helpers.pow_block import (
|
||||
prepare_empty_pow_block,
|
||||
)
|
||||
from eth2spec.test.helpers.execution_payload import (
|
||||
build_state_with_incomplete_transition,
|
||||
)
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
from eth2spec.utils.ssz.ssz_typing import uint256
|
||||
from eth2spec.test.helpers.pow_block import (
|
||||
prepare_empty_pow_block,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_merge_and_later,
|
||||
)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_is_valid_terminal_pow_block_success_valid(spec, state):
|
||||
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
|
||||
|
||||
assert spec.is_valid_terminal_pow_block(block, parent_block)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_is_valid_terminal_pow_block_fail_before_terminal(spec, state):
|
||||
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)
|
||||
|
||||
assert not spec.is_valid_terminal_pow_block(block, parent_block)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_is_valid_terminal_pow_block_fail_just_after_terminal(spec, state):
|
||||
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)
|
||||
|
||||
assert not spec.is_valid_terminal_pow_block(block, parent_block)
|
|
@ -1,143 +0,0 @@
|
|||
from eth2spec.test.exceptions import BlockNotFoundException
|
||||
from eth2spec.utils.ssz.ssz_typing import uint256
|
||||
from eth2spec.test.helpers.fork_choice import (
|
||||
prepare_empty_pow_block,
|
||||
)
|
||||
from eth2spec.test.context import spec_state_test, with_merge_and_later
|
||||
|
||||
|
||||
# Copy of conditional merge part of `on_block(store: Store, signed_block: SignedBeaconBlock)` handler
|
||||
def validate_transition_execution_payload(spec, execution_payload):
|
||||
pow_block = spec.get_pow_block(execution_payload.parent_hash)
|
||||
pow_parent = spec.get_pow_block(pow_block.parent_hash)
|
||||
assert spec.is_valid_terminal_pow_block(pow_block, pow_parent)
|
||||
|
||||
|
||||
def run_validate_transition_execution_payload(spec, block, parent_block, payload,
|
||||
valid=True, block_lookup_success=True):
|
||||
"""
|
||||
Run ``validate_transition_execution_payload``
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
If ``block_lookup_success == False``, run expecting ``BlockNotFoundException``
|
||||
"""
|
||||
|
||||
def get_pow_block(hash: spec.Bytes32) -> spec.PowBlock:
|
||||
if hash == block.block_hash:
|
||||
return block
|
||||
elif hash == parent_block.block_hash:
|
||||
return parent_block
|
||||
else:
|
||||
raise BlockNotFoundException()
|
||||
save_pow_block = spec.get_pow_block
|
||||
|
||||
# Guido authorized everyone to do this
|
||||
spec.get_pow_block = get_pow_block
|
||||
exception_caught = False
|
||||
block_not_found_exception_caught = False
|
||||
try:
|
||||
validate_transition_execution_payload(spec, payload)
|
||||
except BlockNotFoundException:
|
||||
block_not_found_exception_caught = True
|
||||
except AssertionError:
|
||||
exception_caught = True
|
||||
except Exception as e:
|
||||
spec.get_pow_block = save_pow_block
|
||||
raise e
|
||||
spec.get_pow_block = save_pow_block
|
||||
|
||||
if block_lookup_success:
|
||||
assert not block_not_found_exception_caught
|
||||
else:
|
||||
assert block_not_found_exception_caught
|
||||
if valid:
|
||||
assert not exception_caught
|
||||
else:
|
||||
assert exception_caught
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_valid_terminal_pow_block_success_valid(spec, state):
|
||||
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
|
||||
|
||||
assert spec.is_valid_terminal_pow_block(block, parent_block)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_valid_terminal_pow_block_fail_before_terminal(spec, state):
|
||||
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)
|
||||
|
||||
assert not spec.is_valid_terminal_pow_block(block, parent_block)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_valid_terminal_pow_block_fail_just_after_terminal(spec, state):
|
||||
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)
|
||||
|
||||
assert not spec.is_valid_terminal_pow_block(block, parent_block)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_transition_execution_payload_success(spec, state):
|
||||
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
|
||||
payload = spec.ExecutionPayload()
|
||||
payload.parent_hash = block.block_hash
|
||||
run_validate_transition_execution_payload(spec, block, parent_block, payload)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_transition_execution_payload_fail_block_lookup(spec, state):
|
||||
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
|
||||
payload = spec.ExecutionPayload()
|
||||
run_validate_transition_execution_payload(spec, block, parent_block, payload,
|
||||
block_lookup_success=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_transition_execution_payload_fail_parent_block_lookup(spec, state):
|
||||
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.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
payload = spec.ExecutionPayload()
|
||||
payload.parent_hash = block.block_hash
|
||||
run_validate_transition_execution_payload(spec, block, parent_block, payload,
|
||||
block_lookup_success=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_transition_execution_payload_fail_after_terminal(spec, state):
|
||||
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 + 1
|
||||
payload = spec.ExecutionPayload()
|
||||
payload.parent_hash = block.block_hash
|
||||
run_validate_transition_execution_payload(spec, block, parent_block, payload, valid=False)
|
|
@ -0,0 +1,153 @@
|
|||
from typing import Optional
|
||||
from eth2spec.utils.ssz.ssz_typing import uint256, Bytes32
|
||||
from eth2spec.test.helpers.block import (
|
||||
build_empty_block_for_next_slot,
|
||||
)
|
||||
from eth2spec.test.helpers.pow_block import (
|
||||
prepare_random_pow_chain,
|
||||
)
|
||||
from eth2spec.test.context import (
|
||||
spec_state_test,
|
||||
with_merge_and_later,
|
||||
spec_configured_state_test
|
||||
)
|
||||
|
||||
|
||||
TERMINAL_BLOCK_HASH_CONFIG_VAR = '0x0000000000000000000000000000000000000000000000000000000000000001'
|
||||
TERMINAL_BLOCK_HASH = Bytes32(TERMINAL_BLOCK_HASH_CONFIG_VAR)
|
||||
|
||||
|
||||
def run_validate_merge_block(spec, pow_chain, beacon_block, valid=True):
|
||||
"""
|
||||
Run ``validate_merge_block``
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
|
||||
def get_pow_block(hash: spec.Bytes32) -> Optional[spec.PowBlock]:
|
||||
for block in pow_chain:
|
||||
if block.block_hash == hash:
|
||||
return block
|
||||
return None
|
||||
|
||||
get_pow_block_backup = spec.get_pow_block
|
||||
|
||||
# Guido authorized everyone to do this
|
||||
spec.get_pow_block = get_pow_block
|
||||
assertion_error_caught = False
|
||||
try:
|
||||
spec.validate_merge_block(beacon_block)
|
||||
except AssertionError:
|
||||
assertion_error_caught = True
|
||||
except Exception as e:
|
||||
spec.get_pow_block = get_pow_block_backup
|
||||
raise e
|
||||
spec.get_pow_block = get_pow_block_backup
|
||||
|
||||
if valid:
|
||||
assert not assertion_error_caught
|
||||
else:
|
||||
assert assertion_error_caught
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_merge_block_success(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 2)
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
|
||||
pow_chain[1].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.parent_hash = pow_chain[1].block_hash
|
||||
run_validate_merge_block(spec, pow_chain, block)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_merge_block_fail_block_lookup(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 2)
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
|
||||
pow_chain[1].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
run_validate_merge_block(spec, pow_chain, block, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_merge_block_fail_parent_block_lookup(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 1)
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.parent_hash = pow_chain[0].block_hash
|
||||
run_validate_merge_block(spec, pow_chain, block, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_validate_merge_block_fail_after_terminal(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 2)
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
pow_chain[1].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY + uint256(1)
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.parent_hash = pow_chain[1].block_hash
|
||||
run_validate_merge_block(spec, pow_chain, block, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_configured_state_test({
|
||||
'TERMINAL_BLOCK_HASH': TERMINAL_BLOCK_HASH_CONFIG_VAR,
|
||||
'TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH': '0'
|
||||
})
|
||||
def test_validate_merge_block_tbh_override_success(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 2)
|
||||
# should fail if TTD check is reached
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
|
||||
pow_chain[1].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
|
||||
pow_chain[1].block_hash = TERMINAL_BLOCK_HASH
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.parent_hash = pow_chain[1].block_hash
|
||||
run_validate_merge_block(spec, pow_chain, block)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_configured_state_test({
|
||||
'TERMINAL_BLOCK_HASH': TERMINAL_BLOCK_HASH_CONFIG_VAR,
|
||||
'TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH': '0'
|
||||
})
|
||||
def test_validate_merge_block_fail_parent_hash_is_not_tbh(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 2)
|
||||
# shouldn't fail if TTD check is reached
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
|
||||
pow_chain[1].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.parent_hash = pow_chain[1].block_hash
|
||||
run_validate_merge_block(spec, pow_chain, block, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_configured_state_test({
|
||||
'TERMINAL_BLOCK_HASH': TERMINAL_BLOCK_HASH_CONFIG_VAR,
|
||||
'TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH': '1'
|
||||
})
|
||||
def test_validate_merge_block_terminal_block_hash_fail_activation_not_reached(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 2)
|
||||
# shouldn't fail if TTD check is reached
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
|
||||
pow_chain[1].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
pow_chain[1].block_hash = TERMINAL_BLOCK_HASH
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.parent_hash = pow_chain[1].block_hash
|
||||
run_validate_merge_block(spec, pow_chain, block, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_configured_state_test({
|
||||
'TERMINAL_BLOCK_HASH': TERMINAL_BLOCK_HASH_CONFIG_VAR,
|
||||
'TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH': '1'
|
||||
})
|
||||
def test_validate_merge_block_fail_activation_not_reached_parent_hash_is_not_tbh(spec, state):
|
||||
pow_chain = prepare_random_pow_chain(spec, 2)
|
||||
# shouldn't fail if TTD check is reached
|
||||
pow_chain[0].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
|
||||
pow_chain[1].total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.execution_payload.parent_hash = pow_chain[1].block_hash
|
||||
run_validate_merge_block(spec, pow_chain, block, valid=False)
|
Loading…
Reference in New Issue