Implement TransitionStore and transition total difficulty computation

This commit is contained in:
Mikhail Kalinin 2021-06-01 16:28:30 +06:00
parent fd4369dc7c
commit 6226be9e1e
7 changed files with 56 additions and 32 deletions

View File

@ -32,7 +32,7 @@ SHARDING_FORK_VERSION: 0x03000000
SHARDING_FORK_EPOCH: 18446744073709551615
# 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

View File

@ -31,7 +31,7 @@ SHARDING_FORK_VERSION: 0x03000001
SHARDING_FORK_EPOCH: 18446744073709551615
# 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

View File

@ -509,7 +509,7 @@ ExecutionState = Any
def get_pow_block(hash: Bytes32) -> PowBlock:
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:

View File

@ -70,7 +70,7 @@ Warning: this configuration is not definitive.
| Name | Value |
| - | - |
| `TRANSITION_TOTAL_DIFFICULTY` | **TBD** |
| `TRANSITION_TOTAL_DIFFICULTY_OFFSET` | **TBD** |
## Containers

View File

@ -12,13 +12,14 @@
- [`ExecutionEngine`](#executionengine)
- [`set_head`](#set_head)
- [`finalize_block`](#finalize_block)
- [Containers](#containers)
- [`PowBlock`](#powblock)
- [Helper functions](#helper-functions)
- [`get_pow_block`](#get_pow_block)
- [`is_valid_transition_block`](#is_valid_transition_block)
- [Helpers](#helpers)
- [`TransitionStore`](#transitionstore)
- [`PowBlock`](#powblock)
- [`get_pow_block`](#get_pow_block)
- [`get_transition_store`](#get_transition_store)
- [`is_valid_transition_block`](#is_valid_transition_block)
- [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 -->
<!-- /TOC -->
@ -66,44 +67,59 @@ def finalize_block(self: ExecutionEngine, block_hash: Hash32) -> bool:
...
```
## Containers
## Helpers
#### `PowBlock`
### `TransitionStore`
```python
class PowBlock(Container):
@dataclass
class TransitionStore(object):
transition_total_difficulty: uint256
```
### `PowBlock`
```python
@dataclass
class PowBlock(object):
block_hash: Hash32
is_processed: boolean
is_valid: boolean
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.
*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`.
```python
def is_valid_transition_block(block: PowBlock) -> bool:
is_total_difficulty_reached = block.total_difficulty >= TRANSITION_TOTAL_DIFFICULTY
def is_valid_transition_block(transition_store: TransitionStore, block: PowBlock) -> bool:
is_total_difficulty_reached = block.total_difficulty >= transition_store.transition_total_difficulty
return block.is_valid and is_total_difficulty_reached
```
## Updated fork-choice handlers
#### `on_block`
### `on_block`
*Note*: The only modification is the addition of the verification of transition block conditions.
```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
# Parent block must be known
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
# [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
pow_block = get_pow_block(block.body.execution_payload.parent_hash)
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
state = pre_state.copy()

View File

@ -12,6 +12,7 @@
- [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 -->
@ -87,3 +88,15 @@ def upgrade_to_merge(pre: phase0.BeaconState) -> BeaconState:
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)
```

View File

@ -20,7 +20,6 @@
- [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody)
- [Execution Payload](#execution-payload)
- [`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 -->
<!-- /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.
###### `produce_execution_payload`
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:
* Set `block.body.execution_payload = get_execution_payload(state, transition_store, execution_engine)` where:
```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):
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
return ExecutionPayload()
else: