Merge branch 'dev' into transition-reuse

This commit is contained in:
Hsiao-Wei Wang 2021-11-12 15:57:27 +08:00
commit e70da78377
No known key found for this signature in database
GPG Key ID: 1111A8A81778319E
13 changed files with 270 additions and 210 deletions

View File

@ -530,7 +530,7 @@ class NoopExecutionEngine(ExecutionEngine):
def notify_forkchoice_updated(self: ExecutionEngine,
head_block_hash: Hash32,
finalized_block_hash: Hash32,
payload_attributes: Optional[PayloadAttributes]) -> None:
payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]:
pass
def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload:

View File

@ -10,9 +10,8 @@
- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Constants](#constants)
- [Execution](#execution)
- [Preset](#preset)
- [Execution](#execution)
- [Updated penalty values](#updated-penalty-values)
- [Configuration](#configuration)
- [Transition settings](#transition-settings)
@ -63,7 +62,7 @@ Additionally, this upgrade introduces the following minor changes:
| `Transaction` | `ByteList[MAX_BYTES_PER_TRANSACTION]` | either a [typed transaction envelope](https://eips.ethereum.org/EIPS/eip-2718#opaque-byte-array-rather-than-an-rlp-array) or a legacy transaction|
| `ExecutionAddress` | `Bytes20` | Address of account on the execution layer |
## Constants
## Preset
### Execution
@ -74,8 +73,6 @@ Additionally, this upgrade introduces the following minor changes:
| `BYTES_PER_LOGS_BLOOM` | `uint64(2**8)` (= 256) |
| `MAX_EXTRA_DATA_BYTES` | `2**5` (= 32) |
## Preset
### Updated penalty values
The Merge updates a few configuration values to move penalty parameters to their final, maximum security values.

View File

@ -8,6 +8,7 @@
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Introduction](#introduction)
- [Custom types](#custom-types)
- [Protocols](#protocols)
- [`ExecutionEngine`](#executionengine)
- [`notify_forkchoice_updated`](#notify_forkchoice_updated)
@ -29,6 +30,12 @@ This is the modification of the fork choice according to the executable beacon c
*Note*: It introduces the process of transition from the last PoW block to the first PoS block.
## Custom types
| Name | SSZ equivalent | Description |
| - | - | - |
| `PayloadId` | `Bytes8` | Identifier of a payload building process |
## Protocols
### `ExecutionEngine`
@ -46,13 +53,13 @@ This function performs two actions *atomically*:
and corresponding state, up to and including `finalized_block_hash`.
Additionally, if `payload_attributes` is provided, this function sets in motion a payload build process on top of
`head_block_hash` with the result to be gathered by a followup call to `get_payload`.
`head_block_hash` and returns an identifier of initiated process.
```python
def notify_forkchoice_updated(self: ExecutionEngine,
head_block_hash: Hash32,
finalized_block_hash: Hash32,
payload_attributes: Optional[PayloadAttributes]) -> None:
payload_attributes: Optional[PayloadAttributes]) -> Optional[PayloadId]:
...
```
@ -96,9 +103,6 @@ Used by fork-choice handler, `on_block`.
```python
def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool:
if TERMINAL_BLOCK_HASH != Hash32():
return block.block_hash == TERMINAL_BLOCK_HASH
is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY
return is_total_difficulty_reached and is_parent_total_difficulty_valid
@ -115,6 +119,12 @@ def validate_merge_block(block: BeaconBlock) -> None:
and a client software MAY delay a call to ``validate_merge_block``
until the PoW block(s) become available.
"""
if TERMINAL_BLOCK_HASH != Hash32():
# If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
return
pow_block = get_pow_block(block.body.execution_payload.parent_hash)
# Check if `pow_block` is available
assert pow_block is not None
@ -123,10 +133,6 @@ def validate_merge_block(block: BeaconBlock) -> None:
assert pow_parent is not None
# Check if `pow_block` is a valid terminal PoW block
assert is_valid_terminal_pow_block(pow_block, pow_parent)
# If `TERMINAL_BLOCK_HASH` is used as an override, the activation epoch must be reached.
if TERMINAL_BLOCK_HASH != Hash32():
assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
```
## Updated fork-choice handlers

View File

@ -10,11 +10,9 @@
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Custom types](#custom-types)
- [Helpers](#helpers)
- [`get_pow_block_at_terminal_total_difficulty`](#get_pow_block_at_terminal_total_difficulty)
- [`get_terminal_pow_block`](#get_terminal_pow_block)
- [`get_payload_id`](#get_payload_id)
- [Protocols](#protocols)
- [`ExecutionEngine`](#executionengine)
- [`get_payload`](#get_payload)
@ -38,12 +36,6 @@ All behaviors and definitions defined in this document, and documents it extends
All terminology, constants, functions, and protocol mechanics defined in the updated Beacon Chain doc of [The Merge](./beacon-chain.md) are requisite for this document and used throughout.
Please see related Beacon Chain doc before continuing and use them as a reference throughout.
## Custom types
| Name | SSZ equivalent | Description |
| - | - | - |
| `PayloadId` | `Bytes8` | Identifier of a payload building process |
## Helpers
### `get_pow_block_at_terminal_total_difficulty`
@ -52,8 +44,11 @@ Please see related Beacon Chain doc before continuing and use them as a referenc
def get_pow_block_at_terminal_total_difficulty(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlock]:
# `pow_chain` abstractly represents all blocks in the PoW chain
for block in pow_chain:
parent = pow_chain[block.parent_hash]
block_reached_ttd = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
# If genesis block, no parent exists so reaching TTD alone qualifies as valid terminal block
if block_reached_ttd and block.parent_hash == Hash32():
return block
parent = pow_chain[block.parent_hash]
parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
if block_reached_ttd and not parent_reached_ttd:
return block
@ -75,24 +70,6 @@ def get_terminal_pow_block(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlo
return get_pow_block_at_terminal_total_difficulty(pow_chain)
```
### `get_payload_id`
Given the `head_block_hash` and the `payload_attributes` that were used to
initiate the build process via `notify_forkchoice_updated`, `get_payload_id()`
returns the `payload_id` used to retrieve the payload via `get_payload`.
```python
def get_payload_id(parent_hash: Hash32, payload_attributes: PayloadAttributes) -> PayloadId:
return PayloadId(
hash(
parent_hash
+ uint_to_bytes(payload_attributes.timestamp)
+ payload_attributes.random
+ payload_attributes.fee_recipient
)[0:8]
)
```
*Note*: This function does *not* use simple serialize `hash_tree_root` as to
avoid requiring simple serialize hashing capabilities in the Execution Layer.
@ -147,8 +124,8 @@ def prepare_execution_payload(state: BeaconState,
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
if not is_merge_complete(state):
is_terminal_block_hash_set = TERMINAL_BLOCK_HASH != Hash32()
is_activation_epoch_reached = get_current_epoch(state.slot) < TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
if is_terminal_block_hash_set and is_activation_epoch_reached:
is_activation_epoch_reached = get_current_epoch(state.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
if is_terminal_block_hash_set and not is_activation_epoch_reached:
# Terminal block hash is set but activation epoch is not yet reached, no prepare payload call is needed
return None
@ -168,8 +145,7 @@ def prepare_execution_payload(state: BeaconState,
random=get_randao_mix(state, get_current_epoch(state)),
fee_recipient=fee_recipient,
)
execution_engine.notify_forkchoice_updated(parent_hash, finalized_block_hash, payload_attributes)
return get_payload_id(parent_hash, payload_attributes)
return execution_engine.notify_forkchoice_updated(parent_hash, finalized_block_hash, payload_attributes)
```
2. Set `block.body.execution_payload = get_execution_payload(payload_id, execution_engine)`, where:

View File

@ -274,7 +274,7 @@ Specifically a validator should:
## Beacon chain responsibilities
A validator has two primary responsibilities to the beacon chain: [proposing blocks](#block-proposal) and [creating attestations](#attestations-1). Proposals happen infrequently, whereas attestations should be created once per epoch.
A validator has two primary responsibilities to the beacon chain: [proposing blocks](#block-proposal) and [creating attestations](#attesting). Proposals happen infrequently, whereas attestations should be created once per epoch.
### Block proposal

View File

@ -1 +1 @@
1.1.3
1.1.5

View File

@ -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)}"

View File

@ -0,0 +1,34 @@
from random import Random
from eth2spec.utils.ssz.ssz_typing import uint256
class PowChain:
blocks = []
def __init__(self, blocks):
self.blocks = blocks
def __iter__(self):
return iter(self.blocks)
def head(self, offset=0):
assert offset <= 0
return self.blocks[offset - 1]
def prepare_random_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)) -> PowChain:
assert length > 0
chain = [prepare_random_pow_block(spec, rng)]
for i in range(1, length):
chain.append(prepare_random_pow_block(spec, rng))
chain[i].parent_hash = chain[i - 1].block_hash
return PowChain(chain)

View File

@ -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_random_pow_block,
)
from eth2spec.test.helpers.execution_payload import (
build_state_with_incomplete_transition,
)
@ -58,9 +60,9 @@ def test_all_valid(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent = prepare_random_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_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]
@ -92,7 +94,7 @@ def test_block_lookup_failed(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_pow_block(spec)
pow_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_blocks = [pow_block]
for pb in pow_blocks:
@ -122,9 +124,9 @@ def test_too_early_for_merge(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent = prepare_random_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_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]
@ -154,9 +156,9 @@ def test_too_late_for_merge(spec, state):
on_tick_and_append_step(spec, store, current_time, test_steps)
assert store.time == current_time
pow_block_parent = prepare_empty_pow_block(spec)
pow_block_parent = prepare_random_pow_block(spec)
pow_block_parent.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_block = prepare_empty_pow_block(spec)
pow_block = prepare_random_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]

View File

@ -0,0 +1,44 @@
from eth2spec.utils.ssz.ssz_typing import uint256
from eth2spec.test.helpers.pow_block import (
prepare_random_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_random_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
block = prepare_random_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_random_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
block = prepare_random_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_random_pow_block(spec)
parent_block.total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = prepare_random_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)

View File

@ -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)

View File

@ -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.head(-1).total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_chain.head().total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_chain.head().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.head(-1).total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_chain.head().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.head().total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_chain.head().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.head(-1).total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_chain.head().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.head().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.head(-1).total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(2)
pow_chain.head().total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_chain.head().block_hash = TERMINAL_BLOCK_HASH
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_chain.head().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.head(-1).total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_chain.head().total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_chain.head().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.head(-1).total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_chain.head().total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
pow_chain.head().block_hash = TERMINAL_BLOCK_HASH
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_chain.head().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.head(-1).total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY - uint256(1)
pow_chain.head().total_difficulty = spec.config.TERMINAL_TOTAL_DIFFICULTY
block = build_empty_block_for_next_slot(spec, state)
block.body.execution_payload.parent_hash = pow_chain.head().block_hash
run_validate_merge_block(spec, pow_chain, block, valid=False)

View File

@ -564,6 +564,7 @@ def test_new_justified_is_later_than_store_justified(spec, state):
@with_all_phases
@spec_state_test
@with_presets([MINIMAL], reason="too slow")
def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
"""
J: Justified
@ -641,6 +642,7 @@ def test_new_finalized_slot_is_not_justified_checkpoint_ancestor(spec, state):
@with_all_phases
@spec_state_test
@with_presets([MINIMAL], reason="too slow")
def test_new_finalized_slot_is_justified_checkpoint_ancestor(spec, state):
"""
J: Justified