Implement TransitionStore and transition total difficulty computation
This commit is contained in:
parent
fd4369dc7c
commit
6226be9e1e
|
@ -32,7 +32,7 @@ SHARDING_FORK_VERSION: 0x03000000
|
||||||
SHARDING_FORK_EPOCH: 18446744073709551615
|
SHARDING_FORK_EPOCH: 18446744073709551615
|
||||||
|
|
||||||
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
|
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
|
||||||
TRANSITION_TOTAL_DIFFICULTY: 4294967296
|
TRANSITION_TOTAL_DIFFICULTY_OFFSET: 4294967296
|
||||||
|
|
||||||
|
|
||||||
# Time parameters
|
# Time parameters
|
||||||
|
|
|
@ -31,7 +31,7 @@ SHARDING_FORK_VERSION: 0x03000001
|
||||||
SHARDING_FORK_EPOCH: 18446744073709551615
|
SHARDING_FORK_EPOCH: 18446744073709551615
|
||||||
|
|
||||||
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
|
# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D.
|
||||||
TRANSITION_TOTAL_DIFFICULTY: 4294967296
|
TRANSITION_TOTAL_DIFFICULTY_OFFSET: 4294967296
|
||||||
|
|
||||||
|
|
||||||
# Time parameters
|
# Time parameters
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -509,7 +509,7 @@ ExecutionState = Any
|
||||||
|
|
||||||
def get_pow_block(hash: Bytes32) -> PowBlock:
|
def get_pow_block(hash: Bytes32) -> PowBlock:
|
||||||
return PowBlock(block_hash=hash, is_valid=True, is_processed=True,
|
return PowBlock(block_hash=hash, is_valid=True, is_processed=True,
|
||||||
total_difficulty=config.TRANSITION_TOTAL_DIFFICULTY)
|
total_difficulty=uint256(0))
|
||||||
|
|
||||||
|
|
||||||
def get_execution_state(execution_state_root: Bytes32) -> ExecutionState:
|
def get_execution_state(execution_state_root: Bytes32) -> ExecutionState:
|
||||||
|
|
|
@ -70,7 +70,7 @@ Warning: this configuration is not definitive.
|
||||||
|
|
||||||
| Name | Value |
|
| Name | Value |
|
||||||
| - | - |
|
| - | - |
|
||||||
| `TRANSITION_TOTAL_DIFFICULTY` | **TBD** |
|
| `TRANSITION_TOTAL_DIFFICULTY_OFFSET` | **TBD** |
|
||||||
|
|
||||||
## Containers
|
## Containers
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,14 @@
|
||||||
- [`ExecutionEngine`](#executionengine)
|
- [`ExecutionEngine`](#executionengine)
|
||||||
- [`set_head`](#set_head)
|
- [`set_head`](#set_head)
|
||||||
- [`finalize_block`](#finalize_block)
|
- [`finalize_block`](#finalize_block)
|
||||||
- [Containers](#containers)
|
- [Helpers](#helpers)
|
||||||
- [`PowBlock`](#powblock)
|
- [`TransitionStore`](#transitionstore)
|
||||||
- [Helper functions](#helper-functions)
|
- [`PowBlock`](#powblock)
|
||||||
- [`get_pow_block`](#get_pow_block)
|
- [`get_pow_block`](#get_pow_block)
|
||||||
- [`is_valid_transition_block`](#is_valid_transition_block)
|
- [`get_transition_store`](#get_transition_store)
|
||||||
|
- [`is_valid_transition_block`](#is_valid_transition_block)
|
||||||
- [Updated fork-choice handlers](#updated-fork-choice-handlers)
|
- [Updated fork-choice handlers](#updated-fork-choice-handlers)
|
||||||
- [`on_block`](#on_block)
|
- [`on_block`](#on_block)
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
<!-- /TOC -->
|
<!-- /TOC -->
|
||||||
|
@ -66,44 +67,59 @@ def finalize_block(self: ExecutionEngine, block_hash: Hash32) -> bool:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Containers
|
## Helpers
|
||||||
|
|
||||||
#### `PowBlock`
|
### `TransitionStore`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
class PowBlock(Container):
|
@dataclass
|
||||||
|
class TransitionStore(object):
|
||||||
|
transition_total_difficulty: uint256
|
||||||
|
```
|
||||||
|
|
||||||
|
### `PowBlock`
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class PowBlock(object):
|
||||||
block_hash: Hash32
|
block_hash: Hash32
|
||||||
is_processed: boolean
|
is_processed: boolean
|
||||||
is_valid: boolean
|
is_valid: boolean
|
||||||
total_difficulty: uint256
|
total_difficulty: uint256
|
||||||
```
|
```
|
||||||
|
|
||||||
## Helper functions
|
### `get_pow_block`
|
||||||
|
|
||||||
#### `get_pow_block`
|
|
||||||
|
|
||||||
Let `get_pow_block(block_hash: Hash32) -> PowBlock` be the function that given the hash of the PoW block returns its data.
|
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 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.
|
||||||
|
|
||||||
#### `is_valid_transition_block`
|
### `get_transition_store`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_transition_store(anchor_pow_block: PowBlock):
|
||||||
|
transition_total_difficulty = pow_block.total_difficulty + TRANSITION_TOTAL_DIFFICULTY_OFFSET
|
||||||
|
return TransitionStore(transition_total_difficulty=transition_total_difficulty)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `is_valid_transition_block`
|
||||||
|
|
||||||
Used by fork-choice handler, `on_block`.
|
Used by fork-choice handler, `on_block`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def is_valid_transition_block(block: PowBlock) -> bool:
|
def is_valid_transition_block(transition_store: TransitionStore, block: PowBlock) -> bool:
|
||||||
is_total_difficulty_reached = block.total_difficulty >= TRANSITION_TOTAL_DIFFICULTY
|
is_total_difficulty_reached = block.total_difficulty >= transition_store.transition_total_difficulty
|
||||||
return block.is_valid and is_total_difficulty_reached
|
return block.is_valid and is_total_difficulty_reached
|
||||||
```
|
```
|
||||||
|
|
||||||
## Updated fork-choice handlers
|
## Updated fork-choice handlers
|
||||||
|
|
||||||
#### `on_block`
|
### `on_block`
|
||||||
|
|
||||||
*Note*: The only modification is the addition of the verification of transition block conditions.
|
*Note*: The only modification is the addition of the verification of transition block conditions.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
def on_block(store: Store, signed_block: SignedBeaconBlock, transition_store: TransitionStore=None) -> None:
|
||||||
block = signed_block.message
|
block = signed_block.message
|
||||||
# Parent block must be known
|
# Parent block must be known
|
||||||
assert block.parent_root in store.block_states
|
assert block.parent_root in store.block_states
|
||||||
|
@ -119,11 +135,12 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:
|
||||||
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
assert get_ancestor(store, block.parent_root, finalized_slot) == store.finalized_checkpoint.root
|
||||||
|
|
||||||
# [New in Merge]
|
# [New in Merge]
|
||||||
if is_transition_block(pre_state, block):
|
is_transition_store_initialized = transition_store is not None
|
||||||
|
if is_transition_store_initialized and is_transition_block(pre_state, block):
|
||||||
# Delay consideration of block until PoW block is processed by the PoW node
|
# 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_block = get_pow_block(block.body.execution_payload.parent_hash)
|
||||||
assert pow_block.is_processed
|
assert pow_block.is_processed
|
||||||
assert is_valid_transition_block(pow_block)
|
assert is_valid_transition_block(transition_store, pow_block)
|
||||||
|
|
||||||
# Check the block is valid and compute the post-state
|
# Check the block is valid and compute the post-state
|
||||||
state = pre_state.copy()
|
state = pre_state.copy()
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
- [Fork to Merge](#fork-to-merge)
|
- [Fork to Merge](#fork-to-merge)
|
||||||
- [Fork trigger](#fork-trigger)
|
- [Fork trigger](#fork-trigger)
|
||||||
- [Upgrading the state](#upgrading-the-state)
|
- [Upgrading the state](#upgrading-the-state)
|
||||||
|
- [Initializing transition store](#initializing-transition-store)
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
@ -87,3 +88,15 @@ def upgrade_to_merge(pre: phase0.BeaconState) -> BeaconState:
|
||||||
|
|
||||||
return post
|
return post
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Initializing transition store
|
||||||
|
|
||||||
|
If `state.slot % SLOTS_PER_EPOCH == 0` and `compute_epoch_at_slot(state.slot) == MERGE_FORK_EPOCH`, 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 initialize_transition_store(state: BeaconState) -> TransitionStore:
|
||||||
|
pow_block = get_pow_block(state.eth1_data.block_hash)
|
||||||
|
return get_transition_store(pow_block)
|
||||||
|
```
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
- [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody)
|
- [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody)
|
||||||
- [Execution Payload](#execution-payload)
|
- [Execution Payload](#execution-payload)
|
||||||
- [`get_pow_chain_head`](#get_pow_chain_head)
|
- [`get_pow_chain_head`](#get_pow_chain_head)
|
||||||
- [`produce_execution_payload`](#produce_execution_payload)
|
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
<!-- /TOC -->
|
<!-- /TOC -->
|
||||||
|
@ -68,18 +67,13 @@ All validator responsibilities remain unchanged other than those noted below. Na
|
||||||
|
|
||||||
Let `get_pow_chain_head() -> PowBlock` be the function that returns the head of the PoW chain. The body of the function is implementation specific.
|
Let `get_pow_chain_head() -> PowBlock` be the function that returns the head of the PoW chain. The body of the function is implementation specific.
|
||||||
|
|
||||||
###### `produce_execution_payload`
|
* Set `block.body.execution_payload = get_execution_payload(state, transition_store, execution_engine)` where:
|
||||||
|
|
||||||
Let `produce_execution_payload(parent_hash: Hash32, timestamp: uint64) -> ExecutionPayload` be the function that produces new instance of execution payload.
|
|
||||||
The `ExecutionEngine` protocol is used for the implementation specific part of execution payload proposals.
|
|
||||||
|
|
||||||
* Set `block.body.execution_payload = get_execution_payload(state)` where:
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_execution_payload(state: BeaconState, execution_engine: ExecutionEngine) -> ExecutionPayload:
|
def get_execution_payload(state: BeaconState, transition_store: TransitionStore, execution_engine: ExecutionEngine) -> ExecutionPayload:
|
||||||
if not is_transition_completed(state):
|
if not is_transition_completed(state):
|
||||||
pow_block = get_pow_chain_head()
|
pow_block = get_pow_chain_head()
|
||||||
if not is_valid_transition_block(pow_block):
|
if not is_valid_transition_block(transition_store, pow_block):
|
||||||
# Pre-merge, empty payload
|
# Pre-merge, empty payload
|
||||||
return ExecutionPayload()
|
return ExecutionPayload()
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue