Merge branch 'dev'
This commit is contained in:
commit
91f5e5684c
2
Makefile
2
Makefile
|
@ -173,7 +173,7 @@ define run_generator
|
|||
echo "generator $(1) finished"
|
||||
endef
|
||||
|
||||
# The tests dir itself is simply build by creating the directory (recursively creating deeper directories if necessary)
|
||||
# The tests dir itself is simply built by creating the directory (recursively creating deeper directories if necessary)
|
||||
$(TEST_VECTOR_DIR):
|
||||
$(info creating test output directory, for generators: ${GENERATOR_TARGETS})
|
||||
mkdir -p $@
|
||||
|
|
|
@ -45,7 +45,7 @@ The merge is still actively in development. The exact specification has not been
|
|||
* [Merge fork](specs/merge/fork.md)
|
||||
* [Fork Choice changes](specs/merge/fork-choice.md)
|
||||
* [Validator additions](specs/merge/validator.md)
|
||||
* [Client settings](specs/merge/client_settings.md)
|
||||
* [Client settings](specs/merge/client-settings.md)
|
||||
|
||||
### Sharding
|
||||
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
# Extends the mainnet preset
|
||||
PRESET_BASE: 'mainnet'
|
||||
|
||||
# Transition
|
||||
# ---------------------------------------------------------------
|
||||
# TBD, 2**256-1 is a placeholder
|
||||
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129639935
|
||||
|
||||
|
||||
# Genesis
|
||||
# ---------------------------------------------------------------
|
||||
# `2**14` (= 16,384)
|
||||
|
@ -31,9 +37,6 @@ MERGE_FORK_EPOCH: 18446744073709551615
|
|||
SHARDING_FORK_VERSION: 0x03000000
|
||||
SHARDING_FORK_EPOCH: 18446744073709551615
|
||||
|
||||
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
|
||||
MIN_ANCHOR_POW_BLOCK_DIFFICULTY: 4294967296
|
||||
|
||||
|
||||
# Time parameters
|
||||
# ---------------------------------------------------------------
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
# Extends the minimal preset
|
||||
PRESET_BASE: 'minimal'
|
||||
|
||||
# Transition
|
||||
# ---------------------------------------------------------------
|
||||
# TBD, 2**256-1 is a placeholder
|
||||
TERMINAL_TOTAL_DIFFICULTY: 115792089237316195423570985008687907853269984665640564039457584007913129639935
|
||||
|
||||
|
||||
# Genesis
|
||||
# ---------------------------------------------------------------
|
||||
# [customized]
|
||||
|
@ -30,9 +36,6 @@ MERGE_FORK_EPOCH: 18446744073709551615
|
|||
SHARDING_FORK_VERSION: 0x03000001
|
||||
SHARDING_FORK_EPOCH: 18446744073709551615
|
||||
|
||||
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
|
||||
MIN_ANCHOR_POW_BLOCK_DIFFICULTY: 4294967296
|
||||
|
||||
|
||||
# Time parameters
|
||||
# ---------------------------------------------------------------
|
||||
|
|
24
setup.py
24
setup.py
|
@ -32,7 +32,7 @@ except ImportError:
|
|||
from marko.block import Heading, FencedCode, LinkRefDef, BlankLine
|
||||
from marko.inline import CodeSpan
|
||||
from marko.ext.gfm import gfm
|
||||
from marko.ext.gfm.elements import Table, Paragraph
|
||||
from marko.ext.gfm.elements import Table
|
||||
|
||||
|
||||
# Definitions in context.py
|
||||
|
@ -509,8 +509,7 @@ ExecutionState = Any
|
|||
|
||||
|
||||
def get_pow_block(hash: Bytes32) -> PowBlock:
|
||||
return PowBlock(block_hash=hash, parent_hash=Bytes32(), is_valid=True, is_processed=True,
|
||||
total_difficulty=uint256(0), difficulty=uint256(0))
|
||||
return PowBlock(block_hash=hash, parent_hash=Bytes32(), total_difficulty=uint256(0), difficulty=uint256(0))
|
||||
|
||||
|
||||
def get_execution_state(execution_state_root: Bytes32) -> ExecutionState:
|
||||
|
@ -523,16 +522,23 @@ def get_pow_chain_head() -> PowBlock:
|
|||
|
||||
class NoopExecutionEngine(ExecutionEngine):
|
||||
|
||||
def on_payload(self, execution_payload: ExecutionPayload) -> bool:
|
||||
def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
|
||||
return True
|
||||
|
||||
def set_head(self, block_hash: Hash32) -> bool:
|
||||
return True
|
||||
def notify_consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None:
|
||||
pass
|
||||
|
||||
def finalize_block(self, block_hash: Hash32) -> bool:
|
||||
return True
|
||||
def notify_forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None:
|
||||
pass
|
||||
|
||||
def assemble_block(self, block_hash: Hash32, timestamp: uint64, random: Bytes32) -> ExecutionPayload:
|
||||
def prepare_payload(self: ExecutionEngine,
|
||||
parent_hash: Hash32,
|
||||
timestamp: uint64,
|
||||
random: Bytes32,
|
||||
feeRecipient: ExecutionAddress) -> PayloadId:
|
||||
raise NotImplementedError("no default block production")
|
||||
|
||||
def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload:
|
||||
raise NotImplementedError("no default block production")
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
- [Execution](#execution)
|
||||
- [Configuration](#configuration)
|
||||
- [Genesis testing settings](#genesis-testing-settings)
|
||||
- [Transition settings](#transition-settings)
|
||||
- [Containers](#containers)
|
||||
- [Extended containers](#extended-containers)
|
||||
- [`BeaconBlockBody`](#beaconblockbody)
|
||||
|
@ -30,7 +31,8 @@
|
|||
- [`compute_timestamp_at_slot`](#compute_timestamp_at_slot)
|
||||
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
||||
- [Execution engine](#execution-engine)
|
||||
- [`on_payload`](#on_payload)
|
||||
- [`execute_payload`](#execute_payload)
|
||||
- [`notify_consensus_validated`](#notify_consensus_validated)
|
||||
- [Block processing](#block-processing)
|
||||
- [Execution payload processing](#execution-payload-processing)
|
||||
- [`is_valid_gas_limit`](#is_valid_gas_limit)
|
||||
|
@ -52,6 +54,7 @@ This patch adds transaction execution to the beacon chain as part of the Merge f
|
|||
| - | - | - |
|
||||
| `OpaqueTransaction` | `ByteList[MAX_BYTES_PER_OPAQUE_TRANSACTION]` | a [typed transaction envelope](https://eips.ethereum.org/EIPS/eip-2718#opaque-byte-array-rather-than-an-rlp-array) structured as `TransactionType \|\| TransactionPayload` |
|
||||
| `Transaction` | `Union[OpaqueTransaction]` | a transaction |
|
||||
| `ExecutionAddress` | `Bytes20` | Address of account on the execution layer |
|
||||
|
||||
## Constants
|
||||
|
||||
|
@ -64,6 +67,7 @@ This patch adds transaction execution to the beacon chain as part of the Merge f
|
|||
| `BYTES_PER_LOGS_BLOOM` | `uint64(2**8)` (= 256) |
|
||||
| `GAS_LIMIT_DENOMINATOR` | `uint64(2**10)` (= 1,024) |
|
||||
| `MIN_GAS_LIMIT` | `uint64(5000)` (= 5,000) |
|
||||
| `MAX_EXTRA_DATA_BYTES` | `2**5` (= 32) |
|
||||
|
||||
## Configuration
|
||||
|
||||
|
@ -76,6 +80,12 @@ This patch adds transaction execution to the beacon chain as part of the Merge f
|
|||
| `GENESIS_GAS_LIMIT` | `uint64(30000000)` (= 30,000,000) |
|
||||
| `GENESIS_BASE_FEE_PER_GAS` | `Bytes32('0x00ca9a3b00000000000000000000000000000000000000000000000000000000')` (= 1,000,000,000) |
|
||||
|
||||
### Transition settings
|
||||
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `TERMINAL_TOTAL_DIFFICULTY` | **TBD** |
|
||||
|
||||
## Containers
|
||||
|
||||
### Extended containers
|
||||
|
@ -150,7 +160,7 @@ class BeaconState(Container):
|
|||
class ExecutionPayload(Container):
|
||||
# Execution block header fields
|
||||
parent_hash: Hash32
|
||||
coinbase: Bytes20 # 'beneficiary' in the yellow paper
|
||||
coinbase: ExecutionAddress # 'beneficiary' in the yellow paper
|
||||
state_root: Bytes32
|
||||
receipt_root: Bytes32 # 'receipts root' in the yellow paper
|
||||
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
|
||||
|
@ -159,6 +169,7 @@ class ExecutionPayload(Container):
|
|||
gas_limit: uint64
|
||||
gas_used: uint64
|
||||
timestamp: uint64
|
||||
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
|
||||
base_fee_per_gas: Bytes32 # base fee introduced in EIP-1559, little-endian serialized
|
||||
# Extra payload fields
|
||||
block_hash: Hash32 # Hash of execution block
|
||||
|
@ -171,7 +182,7 @@ class ExecutionPayload(Container):
|
|||
class ExecutionPayloadHeader(Container):
|
||||
# Execution block header fields
|
||||
parent_hash: Hash32
|
||||
coinbase: Bytes20
|
||||
coinbase: ExecutionAddress
|
||||
state_root: Bytes32
|
||||
receipt_root: Bytes32
|
||||
logs_bloom: ByteVector[BYTES_PER_LOGS_BLOOM]
|
||||
|
@ -180,6 +191,7 @@ class ExecutionPayloadHeader(Container):
|
|||
gas_limit: uint64
|
||||
gas_used: uint64
|
||||
timestamp: uint64
|
||||
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
|
||||
base_fee_per_gas: Bytes32
|
||||
# Extra payload fields
|
||||
block_hash: Hash32 # Hash of execution block
|
||||
|
@ -230,31 +242,52 @@ def compute_timestamp_at_slot(state: BeaconState, slot: Slot) -> uint64:
|
|||
The implementation-dependent `ExecutionEngine` protocol encapsulates the execution sub-system logic via:
|
||||
|
||||
* a state object `self.execution_state` of type `ExecutionState`
|
||||
* a state transition function `self.on_payload` which mutates `self.execution_state`
|
||||
* a state transition function `self.execute_payload` which applies changes to the `self.execution_state`
|
||||
* a function `self.notify_consensus_validated` which signals that the beacon block containing the execution payload
|
||||
is valid with respect to the consensus rule set
|
||||
|
||||
#### `on_payload`
|
||||
*Note*: `execute_payload` and `notify_consensus_validated` are functions accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol.
|
||||
|
||||
The body of each of these functions is implementation dependent.
|
||||
The Engine API may be used to implement them with an external execution engine.
|
||||
|
||||
#### `execute_payload`
|
||||
|
||||
```python
|
||||
def on_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
|
||||
def execute_payload(self: ExecutionEngine, execution_payload: ExecutionPayload) -> bool:
|
||||
"""
|
||||
Returns ``True`` iff ``execution_payload`` is valid with respect to ``self.execution_state``.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
The above function is accessed through the `EXECUTION_ENGINE` module which instantiates the `ExecutionEngine` protocol.
|
||||
#### `notify_consensus_validated`
|
||||
|
||||
```python
|
||||
def notify_consensus_validated(self: ExecutionEngine, block_hash: Hash32, valid: bool) -> None:
|
||||
...
|
||||
```
|
||||
|
||||
The inputs to this function depend on the result of the state transition. A call to `notify_consensus_validated` must be made after the [`state_transition`](../phase0/beacon-chain.md#beacon-chain-state-transition-function) function finishes. The value of the `valid` parameter must be set as follows:
|
||||
|
||||
* `True` if `state_transition` function call succeeds
|
||||
* `False` if `state_transition` function call fails
|
||||
|
||||
*Note*: The call of the `notify_consensus_validated` function with `valid = True` maps on the `POS_CONSENSUS_VALIDATED` event defined in the [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#definitions).
|
||||
|
||||
### Block processing
|
||||
|
||||
*Note*: The call to the `process_execution_payload` must happen before the call to the `process_randao` as the former depends on the `randao_mix` computed with the reveal of the previous block.
|
||||
|
||||
```python
|
||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
if is_execution_enabled(state, block.body):
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [New in Merge]
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body)
|
||||
process_sync_aggregate(state, block.body.sync_aggregate)
|
||||
if is_execution_enabled(state, block.body):
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) # [New in Merge]
|
||||
```
|
||||
|
||||
### Execution payload processing
|
||||
|
@ -284,20 +317,20 @@ def is_valid_gas_limit(payload: ExecutionPayload, parent: ExecutionPayloadHeader
|
|||
|
||||
#### `process_execution_payload`
|
||||
|
||||
*Note:* This function depends on `process_randao` function call as it retrieves the most recent randao mix from the `state`. Implementations that are considering parallel processing of execution payload with respect to beacon chain state transition function should work around this dependency.
|
||||
|
||||
```python
|
||||
def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
|
||||
# Verify consistency of the parent hash, block number, random, base fee per gas and gas limit
|
||||
# Verify consistency of the parent hash, block number, base fee per gas and gas limit
|
||||
# with respect to the previous execution payload header
|
||||
if is_merge_complete(state):
|
||||
assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||
assert payload.block_number == state.latest_execution_payload_header.block_number + uint64(1)
|
||||
assert payload.random == get_randao_mix(state, get_current_epoch(state))
|
||||
assert is_valid_gas_limit(payload, state.latest_execution_payload_header)
|
||||
# Verify random
|
||||
assert payload.random == get_randao_mix(state, get_current_epoch(state))
|
||||
# Verify timestamp
|
||||
assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
|
||||
# Verify the execution payload is valid
|
||||
assert execution_engine.on_payload(payload)
|
||||
assert execution_engine.execute_payload(payload)
|
||||
# Cache execution payload header
|
||||
state.latest_execution_payload_header = ExecutionPayloadHeader(
|
||||
parent_hash=payload.parent_hash,
|
||||
|
@ -310,6 +343,7 @@ def process_execution_payload(state: BeaconState, payload: ExecutionPayload, exe
|
|||
gas_limit=payload.gas_limit,
|
||||
gas_used=payload.gas_used,
|
||||
timestamp=payload.timestamp,
|
||||
extra_data=payload.extra_data,
|
||||
base_fee_per_gas=payload.base_fee_per_gas,
|
||||
block_hash=payload.block_hash,
|
||||
transactions_root=hash_tree_root(payload.transactions),
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
|
||||
|
||||
- [The Merge -- Client Settings](#the-merge----client-settings)
|
||||
- [Override terminal total difficulty](#override-terminal-total-difficulty)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# The Merge -- Client Settings
|
||||
|
||||
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||
|
||||
This document specifies configurable settings that clients must implement for the Merge.
|
||||
|
||||
### Override terminal total difficulty
|
||||
|
||||
To coordinate manual overrides to [`TERMINAL_TOTAL_DIFFICULTY`](./beacon-chain.md#Transition-settings) parameter, clients must provide `--terminal-total-difficulty-override` as a configurable setting. The value provided by this setting must take precedence over pre-configured `TERMINAL_TOTAL_DIFFICULTY` parameter.
|
||||
|
||||
Except under exceptional scenarios, this setting is expected to not be used. Sufficient warning to the user about this exceptional configurable setting should be provided.
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
|
||||
|
||||
- [The Merge -- Client Settings](#the-merge----client-settings)
|
||||
- [Override terminal total difficulty](#override-terminal-total-difficulty)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# The Merge -- Client Settings
|
||||
|
||||
**Notice**: This document is a work-in-progress for researchers and implementers.
|
||||
|
||||
This document specifies configurable settings that clients must implement for the Merge.
|
||||
|
||||
### Override terminal total difficulty
|
||||
|
||||
To coordinate manual overrides to [`terminal_total_difficulty`](fork-choice.md#transitionstore), clients
|
||||
must provide `--terminal-total-difficulty-override` as a configurable setting.
|
||||
|
||||
If `TransitionStore` has already [been initialized](./fork.md#initializing-transition-store), this alters the previously initialized value of
|
||||
`TransitionStore.terminal_total_difficulty`, otherwise this setting initializes `TransitionStore` with the specified, bypassing `compute_terminal_total_difficulty` and the use of an `anchor_pow_block`.
|
||||
`terminal_total_difficulty`.
|
||||
|
||||
Except under exceptional scenarios, this setting is expected to not be used, and `terminal_total_difficulty` will operate with [default functionality](./fork.md#initializing-transition-store). Sufficient warning to the user about this exceptional configurable setting should be provided.
|
||||
[here](fork.md#initializing-transition-store).
|
|
@ -10,10 +10,8 @@
|
|||
- [Introduction](#introduction)
|
||||
- [Protocols](#protocols)
|
||||
- [`ExecutionEngine`](#executionengine)
|
||||
- [`set_head`](#set_head)
|
||||
- [`finalize_block`](#finalize_block)
|
||||
- [`notify_forkchoice_updated`](#notify_forkchoice_updated)
|
||||
- [Helpers](#helpers)
|
||||
- [`TransitionStore`](#transitionstore)
|
||||
- [`PowBlock`](#powblock)
|
||||
- [`get_pow_block`](#get_pow_block)
|
||||
- [`is_valid_terminal_pow_block`](#is_valid_terminal_pow_block)
|
||||
|
@ -33,49 +31,27 @@ This is the modification of the fork choice according to the executable beacon c
|
|||
|
||||
### `ExecutionEngine`
|
||||
|
||||
The following methods are added to the `ExecutionEngine` protocol for use in the fork choice:
|
||||
|
||||
#### `set_head`
|
||||
|
||||
Re-organizes the execution payload chain and corresponding state to make `block_hash` the head.
|
||||
*Note*: The `notify_forkchoice_updated` function is added to the `ExecutionEngine` protocol to signal the fork choice updates.
|
||||
|
||||
The body of this function is implementation dependent.
|
||||
The Consensus API may be used to implement this with an external execution engine.
|
||||
The Engine API may be used to implement it with an external execution engine.
|
||||
|
||||
#### `notify_forkchoice_updated`
|
||||
|
||||
This function performs two actions *atomically*:
|
||||
* Re-organizes the execution payload chain and corresponding state to make `head_block_hash` the head.
|
||||
* Applies finality to the execution state: it irreversibly persists the chain of all execution payloads
|
||||
and corresponding state, up to and including `finalized_block_hash`.
|
||||
|
||||
```python
|
||||
def set_head(self: ExecutionEngine, block_hash: Hash32) -> bool:
|
||||
"""
|
||||
Returns True if the ``block_hash`` was successfully set as head of the execution payload chain.
|
||||
"""
|
||||
def notify_forkchoice_updated(self: ExecutionEngine, head_block_hash: Hash32, finalized_block_hash: Hash32) -> None:
|
||||
...
|
||||
```
|
||||
|
||||
#### `finalize_block`
|
||||
|
||||
Applies finality to the execution state: it irreversibly persists the chain of all execution payloads
|
||||
and corresponding state, up to and including `block_hash`.
|
||||
|
||||
The body of this function is implementation dependent.
|
||||
The Consensus API may be used to implement this with an external execution engine.
|
||||
|
||||
```python
|
||||
def finalize_block(self: ExecutionEngine, block_hash: Hash32) -> bool:
|
||||
"""
|
||||
Returns True if the data up to and including ``block_hash`` was successfully finalized.
|
||||
"""
|
||||
...
|
||||
```
|
||||
*Note*: The call of the `notify_forkchoice_updated` function maps on the `POS_FORKCHOICE_UPDATED` event defined in the [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#definitions).
|
||||
|
||||
## Helpers
|
||||
|
||||
### `TransitionStore`
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class TransitionStore(object):
|
||||
terminal_total_difficulty: uint256
|
||||
```
|
||||
|
||||
### `PowBlock`
|
||||
|
||||
```python
|
||||
|
@ -83,8 +59,6 @@ class TransitionStore(object):
|
|||
class PowBlock(object):
|
||||
block_hash: Hash32
|
||||
parent_hash: Hash32
|
||||
is_processed: boolean
|
||||
is_valid: boolean
|
||||
total_difficulty: uint256
|
||||
difficulty: uint256
|
||||
```
|
||||
|
@ -93,17 +67,17 @@ class PowBlock(object):
|
|||
|
||||
Let `get_pow_block(block_hash: Hash32) -> PowBlock` be the function that given the hash of the PoW block returns its data.
|
||||
|
||||
*Note*: The `eth_getBlockByHash` JSON-RPC method does not distinguish invalid blocks from blocks that haven't been processed yet. Either extending this existing method or implementing a new one is required.
|
||||
*Note*: The `eth_getBlockByHash` JSON-RPC method may be used to pull this information from an execution client.
|
||||
|
||||
### `is_valid_terminal_pow_block`
|
||||
|
||||
Used by fork-choice handler, `on_block`.
|
||||
|
||||
```python
|
||||
def is_valid_terminal_pow_block(transition_store: TransitionStore, block: PowBlock, parent: PowBlock) -> bool:
|
||||
is_total_difficulty_reached = block.total_difficulty >= transition_store.terminal_total_difficulty
|
||||
is_parent_total_difficulty_valid = parent.total_difficulty < transition_store.terminal_total_difficulty
|
||||
return block.is_valid and is_total_difficulty_reached and is_parent_total_difficulty_valid
|
||||
def is_valid_terminal_pow_block(block: PowBlock, parent: PowBlock) -> bool:
|
||||
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
|
||||
```
|
||||
|
||||
## Updated fork-choice handlers
|
||||
|
@ -113,7 +87,7 @@ def is_valid_terminal_pow_block(transition_store: TransitionStore, block: PowBlo
|
|||
*Note*: The only modification is the addition of the verification of transition block conditions.
|
||||
|
||||
```python
|
||||
def on_block(store: Store, signed_block: SignedBeaconBlock, transition_store: TransitionStore=None) -> None:
|
||||
def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
||||
block = signed_block.message
|
||||
# Parent block must be known
|
||||
assert block.parent_root in store.block_states
|
||||
|
@ -128,17 +102,16 @@ def on_block(store: Store, signed_block: SignedBeaconBlock, transition_store: Tr
|
|||
# Check block is a descendant of the finalized block at the checkpoint finalized slot
|
||||
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
||||
|
||||
# [New in Merge]
|
||||
if (transition_store is not None) and is_merge_block(pre_state, block.body):
|
||||
# Delay consideration of block until PoW block is processed by the PoW node
|
||||
pow_block = get_pow_block(block.body.execution_payload.parent_hash)
|
||||
pow_parent = get_pow_block(pow_block.parent_hash)
|
||||
assert pow_block.is_processed
|
||||
assert is_valid_terminal_pow_block(transition_store, pow_block, pow_parent)
|
||||
|
||||
# Check the block is valid and compute the post-state
|
||||
state = pre_state.copy()
|
||||
state_transition(state, signed_block, True)
|
||||
|
||||
# [New in Merge]
|
||||
if is_merge_block(pre_state, block.body):
|
||||
pow_block = get_pow_block(block.body.execution_payload.parent_hash)
|
||||
pow_parent = get_pow_block(pow_block.parent_hash)
|
||||
assert is_valid_terminal_pow_block(pow_block, pow_parent)
|
||||
|
||||
# Add new block to the store
|
||||
store.blocks[hash_tree_root(block)] = block
|
||||
# Add new state for this block to the store
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
- [Fork to Merge](#fork-to-merge)
|
||||
- [Fork trigger](#fork-trigger)
|
||||
- [Upgrading the state](#upgrading-the-state)
|
||||
- [Initializing transition store](#initializing-transition-store)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
|
@ -28,8 +27,6 @@ Warning: this configuration is not definitive.
|
|||
| - | - |
|
||||
| `MERGE_FORK_VERSION` | `Version('0x02000000')` |
|
||||
| `MERGE_FORK_EPOCH` | `Epoch(18446744073709551615)` **TBD** |
|
||||
| `MIN_ANCHOR_POW_BLOCK_DIFFICULTY` | **TBD** |
|
||||
| `TARGET_SECONDS_TO_MERGE` | `uint64(7 * 86400)` = (604,800) |
|
||||
|
||||
## Fork to Merge
|
||||
|
||||
|
@ -37,8 +34,6 @@ Warning: this configuration is not definitive.
|
|||
|
||||
TBD. Social consensus, along with state conditions such as epoch boundary, finality, deposits, active validator count, etc. may be part of the decision process to trigger the fork. For now we assume the condition will be triggered at epoch `MERGE_FORK_EPOCH`.
|
||||
|
||||
Since the Merge transition process relies on `Eth1Data` in the beacon state we do want to make sure that this data is fresh. This is achieved by forcing `MERGE_FORK_EPOCH` to point to eth1 voting period boundary, i.e. `MERGE_FORK_EPOCH` should satisfy the following condition `MERGE_FORK_EPOCH % EPOCHS_PER_ETH1_VOTING_PERIOD == 0`.
|
||||
|
||||
Note that for the pure Merge networks, we don't apply `upgrade_to_merge` since it starts with Merge version logic.
|
||||
|
||||
### Upgrading the state
|
||||
|
@ -100,33 +95,3 @@ def upgrade_to_merge(pre: altair.BeaconState) -> BeaconState:
|
|||
|
||||
return post
|
||||
```
|
||||
|
||||
### Initializing transition store
|
||||
|
||||
If `state.slot % SLOTS_PER_EPOCH == 0`, `compute_epoch_at_slot(state.slot) == MERGE_FORK_EPOCH`, and the transition store has not already been initialized, a transition store is initialized to be further utilized by the transition process of the Merge.
|
||||
|
||||
Transition store initialization occurs after the state has been modified by corresponding `upgrade_to_merge` function.
|
||||
|
||||
```python
|
||||
def compute_terminal_total_difficulty(anchor_pow_block: PowBlock) -> uint256:
|
||||
seconds_per_voting_period = EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH * SECONDS_PER_SLOT
|
||||
pow_blocks_per_voting_period = seconds_per_voting_period // SECONDS_PER_ETH1_BLOCK
|
||||
pow_blocks_to_merge = TARGET_SECONDS_TO_MERGE // SECONDS_PER_ETH1_BLOCK
|
||||
pow_blocks_after_anchor_block = ETH1_FOLLOW_DISTANCE + pow_blocks_per_voting_period + pow_blocks_to_merge
|
||||
anchor_difficulty = max(MIN_ANCHOR_POW_BLOCK_DIFFICULTY, anchor_pow_block.difficulty)
|
||||
|
||||
return anchor_pow_block.total_difficulty + anchor_difficulty * pow_blocks_after_anchor_block
|
||||
|
||||
|
||||
def get_transition_store(anchor_pow_block: PowBlock) -> TransitionStore:
|
||||
terminal_total_difficulty = compute_terminal_total_difficulty(anchor_pow_block)
|
||||
return TransitionStore(terminal_total_difficulty=terminal_total_difficulty)
|
||||
|
||||
|
||||
def initialize_transition_store(state: BeaconState) -> TransitionStore:
|
||||
pow_block = get_pow_block(state.eth1_data.block_hash)
|
||||
return get_transition_store(pow_block)
|
||||
```
|
||||
|
||||
*Note*: Transition store can also be initialized at client startup by [overriding terminal total
|
||||
difficulty](client_settings.md#override-terminal-total-difficulty).
|
||||
|
|
|
@ -68,14 +68,10 @@ See the Merge [state transition document](./beacon-chain.md#beaconblockbody) for
|
|||
In addition to the gossip validations for this topic from prior specifications,
|
||||
the following validations MUST pass before forwarding the `signed_beacon_block` on the network.
|
||||
Alias `block = signed_beacon_block.message`, `execution_payload = block.body.execution_payload`.
|
||||
- If the merge is complete with respect to the head state -- i.e. `is_merge_complete(state)` --
|
||||
then validate the following:
|
||||
- _[REJECT]_ The block's execution payload must be non-empty --
|
||||
i.e. `execution_payload != ExecutionPayload()`
|
||||
- If the execution is enabled for the block -- i.e. `is_execution_enabled(state, block.body)`
|
||||
then validate the following:
|
||||
- _[REJECT]_ The block's execution payload timestamp is correct with respect to the slot
|
||||
-- i.e. `execution_payload.timestamp == compute_time_at_slot(state, block.slot)`.
|
||||
-- i.e. `execution_payload.timestamp == compute_timestamp_at_slot(state, block.slot)`.
|
||||
- _[REJECT]_ Gas used is less than the gas limit --
|
||||
i.e. `execution_payload.gas_used <= execution_payload.gas_limit`.
|
||||
- _[REJECT]_ The execution payload block hash is not equal to the parent hash --
|
||||
|
@ -89,7 +85,7 @@ Alias `block = signed_beacon_block.message`, `execution_payload = block.body.exe
|
|||
|
||||
### Transitioning the gossip
|
||||
|
||||
See gossip transition details found in the [Altair document](../altair/p2p) for
|
||||
See gossip transition details found in the [Altair document](../altair/p2p-interface.md#transitioning-the-gossip) for
|
||||
details on how to handle transitioning gossip topics for the Merge.
|
||||
|
||||
## The Req/Resp domain
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
|
||||
- [Introduction](#introduction)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Custom types](#custom-types)
|
||||
- [Protocols](#protocols)
|
||||
- [`ExecutionEngine`](#executionengine)
|
||||
- [`assemble_block`](#assemble_block)
|
||||
- [`prepare_payload`](#prepare_payload)
|
||||
- [`get_payload`](#get_payload)
|
||||
- [Beacon chain responsibilities](#beacon-chain-responsibilities)
|
||||
- [Block proposal](#block-proposal)
|
||||
- [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody)
|
||||
- [Execution Payload](#execution-payload)
|
||||
- [ExecutionPayload](#executionpayload)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- /TOC -->
|
||||
|
@ -33,22 +35,48 @@ 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` | `uint64` | Identifier of a payload building process |
|
||||
|
||||
## Protocols
|
||||
|
||||
### `ExecutionEngine`
|
||||
|
||||
The following methods are added to the `ExecutionEngine` protocol for use as a validator:
|
||||
*Note*: `prepare_payload` and `get_payload` functions are added to the `ExecutionEngine` protocol for use as a validator.
|
||||
|
||||
#### `assemble_block`
|
||||
The body of each of these functions is implementation dependent.
|
||||
The Engine API may be used to implement them with an external execution engine.
|
||||
|
||||
Produces a new instance of an execution payload, with the specified `timestamp`,
|
||||
on top of the execution payload chain tip identified by `block_hash`.
|
||||
#### `prepare_payload`
|
||||
|
||||
The body of this function is implementation dependent.
|
||||
The Consensus API may be used to implement this with an external execution engine.
|
||||
Given the set of execution payload attributes, `prepare_payload` initiates a process of building an execution payload
|
||||
on top of the execution chain tip identified by `parent_hash`.
|
||||
|
||||
```python
|
||||
def assemble_block(self: ExecutionEngine, block_hash: Hash32, timestamp: uint64, random: Bytes32) -> ExecutionPayload:
|
||||
def prepare_payload(self: ExecutionEngine,
|
||||
parent_hash: Hash32,
|
||||
timestamp: uint64,
|
||||
random: Bytes32,
|
||||
fee_recipient: ExecutionAddress) -> PayloadId:
|
||||
"""
|
||||
Return ``payload_id`` that is used to obtain the execution payload in a subsequent ``get_payload`` call.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
#### `get_payload`
|
||||
|
||||
Given the `payload_id`, `get_payload` returns the most recent version of the execution payload that
|
||||
has been built since the corresponding call to `prepare_payload` method.
|
||||
|
||||
```python
|
||||
def get_payload(self: ExecutionEngine, payload_id: PayloadId) -> ExecutionPayload:
|
||||
"""
|
||||
Return ``execution_payload`` object.
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
|
@ -60,9 +88,14 @@ All validator responsibilities remain unchanged other than those noted below. Na
|
|||
|
||||
#### Constructing the `BeaconBlockBody`
|
||||
|
||||
##### Execution Payload
|
||||
##### ExecutionPayload
|
||||
|
||||
* Set `block.body.execution_payload = get_execution_payload(state, transition_store, execution_engine, pow_chain)` where:
|
||||
To obtain an execution payload, a block proposer building a block on top of a `state` must take the following actions:
|
||||
|
||||
1. Set `payload_id = prepare_execution_payload(state, pow_chain, fee_recipient, execution_engine)`, where:
|
||||
* `state` is the state object after applying `process_slots(state, slot)` transition to the resulting state of the parent block processing
|
||||
* `pow_chain` is a list that abstractly represents all blocks in the PoW chain
|
||||
* `fee_recipient` is the value suggested to be used for the `coinbase` field of the execution payload
|
||||
|
||||
```python
|
||||
def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequence[PowBlock]) -> Optional[PowBlock]:
|
||||
|
@ -75,35 +108,37 @@ def get_pow_block_at_total_difficulty(total_difficulty: uint256, pow_chain: Sequ
|
|||
return None
|
||||
|
||||
|
||||
def compute_randao_mix(state: BeaconState, randao_reveal: BLSSignature) -> Bytes32:
|
||||
epoch = get_current_epoch(state)
|
||||
return xor(get_randao_mix(state, epoch), hash(randao_reveal))
|
||||
|
||||
|
||||
def produce_execution_payload(state: BeaconState,
|
||||
parent_hash: Hash32,
|
||||
randao_reveal: BLSSignature,
|
||||
execution_engine: ExecutionEngine) -> ExecutionPayload:
|
||||
timestamp = compute_timestamp_at_slot(state, state.slot)
|
||||
randao_mix = compute_randao_mix(state, randao_reveal)
|
||||
return execution_engine.assemble_block(parent_hash, timestamp, randao_mix)
|
||||
|
||||
|
||||
def get_execution_payload(state: BeaconState,
|
||||
transition_store: TransitionStore,
|
||||
randao_reveal: BLSSignature,
|
||||
execution_engine: ExecutionEngine,
|
||||
pow_chain: Sequence[PowBlock]) -> ExecutionPayload:
|
||||
def prepare_execution_payload(state: BeaconState,
|
||||
pow_chain: Sequence[PowBlock],
|
||||
fee_recipient: ExecutionAddress,
|
||||
execution_engine: ExecutionEngine) -> Optional[PayloadId]:
|
||||
if not is_merge_complete(state):
|
||||
terminal_pow_block = get_pow_block_at_total_difficulty(transition_store.terminal_total_difficulty, pow_chain)
|
||||
terminal_pow_block = get_pow_block_at_total_difficulty(TERMINAL_TOTAL_DIFFICULTY, pow_chain)
|
||||
if terminal_pow_block is None:
|
||||
# Pre-merge, empty payload
|
||||
return ExecutionPayload()
|
||||
# Pre-merge, no prepare payload call is needed
|
||||
return None
|
||||
else:
|
||||
# Signify merge via producing on top of the last PoW block
|
||||
return produce_execution_payload(state, terminal_pow_block.block_hash, randao_reveal, execution_engine)
|
||||
parent_hash = terminal_pow_block.block_hash
|
||||
else:
|
||||
# Post-merge, normal payload
|
||||
parent_hash = state.latest_execution_payload_header.block_hash
|
||||
|
||||
# Post-merge, normal payload
|
||||
parent_hash = state.latest_execution_payload_header.block_hash
|
||||
return produce_execution_payload(state, parent_hash, randao_reveal, execution_engine)
|
||||
timestamp = compute_timestamp_at_slot(state, state.slot)
|
||||
random = get_randao_mix(state, get_current_epoch(state))
|
||||
return execution_engine.prepare_payload(parent_hash, timestamp, random, fee_recipient)
|
||||
```
|
||||
|
||||
2. Set `block.body.execution_payload = get_execution_payload(payload_id, execution_engine)`, where:
|
||||
|
||||
```python
|
||||
def get_execution_payload(payload_id: Optional[PayloadId], execution_engine: ExecutionEngine) -> ExecutionPayload:
|
||||
if payload_id is None:
|
||||
# Pre-merge, empty payload
|
||||
return ExecutionPayload()
|
||||
else:
|
||||
return execution_engine.get_payload(payload_id)
|
||||
```
|
||||
|
||||
*Note*: It is recommended for a validator to call `prepare_execution_payload` as soon as input parameters become known,
|
||||
and make subsequent calls to this function when any of these parameters gets updated.
|
||||
|
|
|
@ -270,8 +270,6 @@ class ShardBlobBody(Container):
|
|||
degree_proof: BLSCommitment
|
||||
# The actual data. Should match the commitment and degree proof.
|
||||
data: List[BLSPoint, POINTS_PER_SAMPLE * MAX_SAMPLES_PER_BLOB]
|
||||
# Latest block root of the Beacon Chain, before shard_blob.slot
|
||||
beacon_block_root: Root
|
||||
# fee payment fields (EIP 1559 like)
|
||||
# TODO: express in MWei instead?
|
||||
max_priority_fee_per_sample: Gwei
|
||||
|
@ -293,8 +291,6 @@ class ShardBlobBodySummary(Container):
|
|||
degree_proof: BLSCommitment
|
||||
# Hash-tree-root as summary of the data field
|
||||
data_root: Root
|
||||
# Latest block root of the Beacon Chain, before shard_blob.slot
|
||||
beacon_block_root: Root
|
||||
# fee payment fields (EIP 1559 like)
|
||||
# TODO: express in MWei instead?
|
||||
max_priority_fee_per_sample: Gwei
|
||||
|
@ -552,12 +548,12 @@ def compute_committee_index_from_shard(state: BeaconState, slot: Slot, shard: Sh
|
|||
```python
|
||||
def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||
process_block_header(state, block)
|
||||
# is_execution_enabled is omitted, execution is enabled by default.
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE)
|
||||
process_randao(state, block.body)
|
||||
process_eth1_data(state, block.body)
|
||||
process_operations(state, block.body) # [Modified in Sharding]
|
||||
process_sync_aggregate(state, block.body.sync_aggregate)
|
||||
# is_execution_enabled is omitted, execution is enabled by default.
|
||||
process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE)
|
||||
```
|
||||
|
||||
#### Operations
|
||||
|
@ -695,10 +691,6 @@ def process_shard_header(state: BeaconState, signed_header: SignedShardBlobHeade
|
|||
committees_per_slot = get_committee_count_per_slot(state, header_epoch)
|
||||
assert committee_index <= committees_per_slot
|
||||
|
||||
# Verify that the block root matches,
|
||||
# to ensure the header will only be included in this specific Beacon Chain sub-tree.
|
||||
assert header.body_summary.beacon_block_root == get_block_root_at_slot(state, slot - 1)
|
||||
|
||||
# Check that this data is still pending
|
||||
committee_work = state.shard_buffer[slot % SHARD_STATE_MEMORY_SLOTS][shard]
|
||||
assert committee_work.status.selector == SHARD_WORK_PENDING
|
||||
|
|
|
@ -98,7 +98,7 @@ on the horizontal subnet or creating samples for it. Alias `blob = signed_blob.m
|
|||
- _[REJECT]_ The blob signature, `signed_blob.signature`, is valid for the aggregate of proposer and builder --
|
||||
i.e. `bls.FastAggregateVerify([builder_pubkey, proposer_pubkey], blob_signing_root, signed_blob.signature)`.
|
||||
- _[REJECT]_ The blob is proposed by the expected `proposer_index` for the blob's `slot` and `shard`,
|
||||
in the context of the current shuffling (defined by `blob.body.beacon_block_root`/`slot`).
|
||||
in the context of the current shuffling (defined by the current node head state and `blob.slot`).
|
||||
If the `proposer_index` cannot immediately be verified against the expected shuffling,
|
||||
the blob MAY be queued for later processing while proposers for the blob's branch are calculated --
|
||||
in such a case _do not_ `REJECT`, instead `IGNORE` this message.
|
||||
|
@ -133,7 +133,7 @@ The following validations MUST pass before forwarding the `signed_blob_header` o
|
|||
- _[REJECT]_ The header signature, `signed_blob_header.signature`, is valid for the aggregate of proposer and builder --
|
||||
i.e. `bls.FastAggregateVerify([builder_pubkey, proposer_pubkey], blob_signing_root, signed_blob_header.signature)`.
|
||||
- _[REJECT]_ The header is proposed by the expected `proposer_index` for the blob's `header.slot` and `header.shard`
|
||||
in the context of the current shuffling (defined by `header.body_summary.beacon_block_root`/`slot`).
|
||||
in the context of the current shuffling (defined by the current node head state and `header.slot`).
|
||||
If the `proposer_index` cannot immediately be verified against the expected shuffling,
|
||||
the blob MAY be queued for later processing while proposers for the blob's branch are calculated --
|
||||
in such a case _do not_ `REJECT`, instead `IGNORE` this message.
|
||||
|
@ -161,7 +161,7 @@ The following validations MUST pass before forwarding the `signed_blob_header` o
|
|||
- _[REJECT]_ The header signature, `signed_blob_header.signature`, is valid for ONLY the builder --
|
||||
i.e. `bls.Verify(builder_pubkey, blob_signing_root, signed_blob_header.signature)`. The signature is not an aggregate with the proposer.
|
||||
- _[REJECT]_ The header is designated for proposal by the expected `proposer_index` for the blob's `header.slot` and `header.shard`
|
||||
in the context of the current shuffling (defined by `header.body_summary.beacon_block_root`/`slot`).
|
||||
in the context of the current shuffling (defined by the current node head state and `header.slot`).
|
||||
If the `proposer_index` cannot immediately be verified against the expected shuffling,
|
||||
the blob MAY be queued for later processing while proposers for the blob's branch are calculated --
|
||||
in such a case _do not_ `REJECT`, instead `IGNORE` this message.
|
||||
|
|
|
@ -1 +1 @@
|
|||
1.1.0-beta.4
|
||||
1.1.0-beta.5
|
||||
|
|
|
@ -9,9 +9,6 @@ from eth2spec.test.helpers.merkle import build_proof
|
|||
@with_phases([ALTAIR])
|
||||
@spec_state_test
|
||||
def test_next_sync_committee_tree(spec, state):
|
||||
state.next_sync_committee: object = spec.SyncCommittee(
|
||||
pubkeys=[state.validators[i]for i in range(spec.SYNC_COMMITTEE_SIZE)]
|
||||
)
|
||||
next_sync_committee_branch = build_proof(state.get_backing(), spec.NEXT_SYNC_COMMITTEE_INDEX)
|
||||
assert spec.is_valid_merkle_branch(
|
||||
leaf=state.next_sync_committee.hash_tree_root(),
|
||||
|
|
|
@ -52,7 +52,7 @@ def test_process_light_client_update_not_updated(spec, state):
|
|||
sync_committee_signature = compute_aggregate_sync_committee_signature(
|
||||
spec,
|
||||
state,
|
||||
block.slot,
|
||||
block_header.slot,
|
||||
committee,
|
||||
)
|
||||
next_sync_committee_branch = [spec.Bytes32() for _ in range(spec.floorlog2(spec.NEXT_SYNC_COMMITTEE_INDEX))]
|
||||
|
|
|
@ -99,8 +99,7 @@ def build_empty_block(spec, state, slot=None):
|
|||
empty_block.body.sync_aggregate.sync_committee_signature = spec.G2_POINT_AT_INFINITY
|
||||
|
||||
if is_post_merge(spec):
|
||||
randao_mix = spec.compute_randao_mix(state, empty_block.body.randao_reveal)
|
||||
empty_block.body.execution_payload = build_empty_execution_payload(spec, state, randao_mix)
|
||||
empty_block.body.execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
return empty_block
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None):
|
|||
|
||||
payload = spec.ExecutionPayload(
|
||||
parent_hash=latest.block_hash,
|
||||
coinbase=spec.Bytes20(),
|
||||
coinbase=spec.ExecutionAddress(),
|
||||
state_root=latest.state_root, # no changes to the state
|
||||
receipt_root=b"no receipts here" + b"\x00" * 16, # TODO: root of empty MPT may be better.
|
||||
logs_bloom=spec.ByteVector[spec.BYTES_PER_LOGS_BLOOM](), # TODO: zeroed logs bloom for empty logs ok?
|
||||
|
@ -20,6 +20,7 @@ def build_empty_execution_payload(spec, state, randao_mix=None):
|
|||
gas_limit=latest.gas_limit, # retain same limit
|
||||
gas_used=0, # empty block, 0 gas
|
||||
timestamp=timestamp,
|
||||
extra_data=spec.ByteList[spec.MAX_EXTRA_DATA_BYTES](),
|
||||
base_fee_per_gas=latest.base_fee_per_gas, # retain same base_fee
|
||||
block_hash=spec.Hash32(),
|
||||
transactions=empty_txs,
|
||||
|
@ -42,6 +43,7 @@ def get_execution_payload_header(spec, execution_payload):
|
|||
gas_limit=execution_payload.gas_limit,
|
||||
gas_used=execution_payload.gas_used,
|
||||
timestamp=execution_payload.timestamp,
|
||||
extra_data=execution_payload.extra_data,
|
||||
base_fee_per_gas=execution_payload.base_fee_per_gas,
|
||||
block_hash=execution_payload.block_hash,
|
||||
transactions_root=spec.hash_tree_root(execution_payload.transactions)
|
||||
|
|
|
@ -25,7 +25,7 @@ def run_execution_payload_processing(spec, state, execution_payload, valid=True,
|
|||
called_new_block = False
|
||||
|
||||
class TestEngine(spec.NoopExecutionEngine):
|
||||
def on_payload(self, payload) -> bool:
|
||||
def execute_payload(self, payload) -> bool:
|
||||
nonlocal called_new_block, execution_valid
|
||||
called_new_block = True
|
||||
assert payload == execution_payload
|
||||
|
@ -144,6 +144,34 @@ def test_bad_parent_hash_regular_payload(spec, state):
|
|||
yield from run_execution_payload_processing(spec, state, execution_payload, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_bad_random_first_payload(spec, state):
|
||||
# pre-state
|
||||
state = build_state_with_incomplete_transition(spec, state)
|
||||
next_slot(spec, state)
|
||||
|
||||
# execution payload
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
execution_payload.random = b'\x42' * 32
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_bad_random_regular_payload(spec, state):
|
||||
# pre-state
|
||||
state = build_state_with_complete_transition(spec, state)
|
||||
next_slot(spec, state)
|
||||
|
||||
# execution payload
|
||||
execution_payload = build_empty_execution_payload(spec, state)
|
||||
execution_payload.random = b'\x04' * 32
|
||||
|
||||
yield from run_execution_payload_processing(spec, state, execution_payload, valid=False)
|
||||
|
||||
|
||||
@with_merge_and_later
|
||||
@spec_state_test
|
||||
def test_bad_number_regular_payload(spec, state):
|
||||
|
|
|
@ -143,6 +143,9 @@ def process_and_sign_block_without_header_validations(spec, state, block):
|
|||
state_root=spec.Bytes32(),
|
||||
body_root=block.body.hash_tree_root(),
|
||||
)
|
||||
if is_post_merge(spec):
|
||||
if spec.is_execution_enabled(state, block.body):
|
||||
spec.process_execution_payload(state, block.body.execution_payload, spec.EXECUTION_ENGINE)
|
||||
|
||||
# Perform rest of process_block transitions
|
||||
spec.process_randao(state, block.body)
|
||||
|
@ -150,9 +153,6 @@ def process_and_sign_block_without_header_validations(spec, state, block):
|
|||
spec.process_operations(state, block.body)
|
||||
if is_post_altair(spec):
|
||||
spec.process_sync_aggregate(state, block.body.sync_aggregate)
|
||||
if is_post_merge(spec):
|
||||
if spec.is_execution_enabled(state, block.body):
|
||||
spec.process_execution_payload(state, block.body.execution_payload, spec.EXECUTION_ENGINE)
|
||||
|
||||
# Insert post-state rot
|
||||
block.state_root = state.hash_tree_root()
|
||||
|
@ -196,8 +196,7 @@ def test_parent_from_same_slot(spec, state):
|
|||
child_block.parent_root = state.latest_block_header.hash_tree_root()
|
||||
|
||||
if is_post_merge(spec):
|
||||
randao_mix = spec.compute_randao_mix(state, child_block.body.randao_reveal)
|
||||
child_block.body.execution_payload = build_empty_execution_payload(spec, state, randao_mix)
|
||||
child_block.body.execution_payload = build_empty_execution_payload(spec, state)
|
||||
|
||||
# Show that normal path through transition fails
|
||||
failed_state = state.copy()
|
||||
|
|
|
@ -45,8 +45,8 @@ MESSAGES = [
|
|||
SAMPLE_MESSAGE = b'\x12' * 32
|
||||
|
||||
PRIVKEYS = [
|
||||
# Curve order is 256 so private keys are 32 bytes at most.
|
||||
# Also not all integers is a valid private key, so using pre-generated keys
|
||||
# Curve order is 256, so private keys use 32 bytes at most.
|
||||
# Also, not all integers are valid private keys. Therefore, using pre-generated keys.
|
||||
hex_to_int('0x00000000000000000000000000000000263dbd792f5b1be47ed85f8938c0f29586af0d3ac7b977f21c278fe1462040e3'),
|
||||
hex_to_int('0x0000000000000000000000000000000047b8192d77bf871b62e87859d653922725724a5c031afeabc60bcef5ff665138'),
|
||||
hex_to_int('0x00000000000000000000000000000000328388aff0d4a5b7dc9205abd374e7e98f3cd9f3418edb4eafda5fb16473d216'),
|
||||
|
|
Loading…
Reference in New Issue