Merge branch 'dev' into transition-reuse
This commit is contained in:
commit
e70da78377
2
setup.py
2
setup.py
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.1.3
|
||||
1.1.5
|
|
@ -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,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)
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
|
@ -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.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)
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue