Get rid of state_transition.py

This commit is contained in:
Justin Drake 2019-05-01 13:14:10 +01:00
parent 591a2b47c8
commit 5df79d7565
8 changed files with 44 additions and 113 deletions

View File

@ -105,7 +105,6 @@
- [Registry updates](#registry-updates)
- [Slashings](#slashings)
- [Final updates](#final-updates)
- [Per-slot processing](#per-slot-processing)
- [Per-block processing](#per-block-processing)
- [Block header](#block-header)
- [RANDAO](#randao)
@ -1264,27 +1263,27 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit],
## Beacon chain state transition function
We now define the state transition function. At a high level, the state transition is made up of four parts:
The post-state corresponding to a pre-state `state` and a block `block` is defined as `state_transition(state, block)`.
1. State caching, which happens at the start of every slot.
2. The per-epoch transitions, which happens at the start of the first slot of every epoch.
3. The per-slot transitions, which happens at every slot.
4. The per-block transitions, which happens at every block.
```python
def state_transition(state: BeaconState, block: BeaconBlock) -> BeaconState:
assert state.slot < block.slot
while state.slot < block.slot:
# State caching at the start of every slot
cache_state(state)
# Per-epoch processing at the start of the first slot of every epoch
if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
process_epoch_transition(state)
# Slot incrementing
state.slot += 1
# Block processing at every block
process_block(state, block)
```
Transition section notes:
* The state caching caches the state root of the previous slot and updates block and state roots records.
* The per-epoch transitions focus on the [validator](#dfn-validator) registry, including adjusting balances and activating and exiting [validators](#dfn-validator), as well as processing crosslinks and managing block justification/finalization.
* The per-slot transitions focus on the slot counter.
* The per-block transitions generally focus on verifying aggregate signatures and saving temporary records relating to the per-block activity in the `BeaconState`.
Beacon blocks that trigger unhandled Python exceptions (e.g. out-of-range list accesses) and failed `assert`s during the state transition are considered invalid.
Note: If there are skipped slots between a block and its parent block, run the steps in the [state-root](#state-caching), [per-epoch](#per-epoch-processing), and [per-slot](#per-slot-processing) sections once for each skipped slot and then once for the slot containing the new block.
Note: Beacon blocks that trigger unhandled Python exceptions (e.g. out-of-range list accesses) and failed `assert`s during the state transition are considered invalid.
### State caching
At every `slot > GENESIS_SLOT` run the following function:
```python
def cache_state(state: BeaconState) -> None:
# Cache latest known state root (for previous slot)
@ -1302,12 +1301,18 @@ def cache_state(state: BeaconState) -> None:
### Per-epoch processing
The steps below happen when `state.slot > GENESIS_SLOT and (state.slot + 1) % SLOTS_PER_EPOCH == 0`.
```python
def process_epoch_transition(state: BeaconState) -> None:
process_justification_and_finalization(state)
process_crosslinks(state)
process_rewards_and_penalties(state)
process_registry_updates(state)
process_slashings(state)
process_final_updates(state)
```
#### Helper functions
We define epoch transition helper functions:
```python
def get_total_active_balance(state: BeaconState) -> Gwei:
return get_total_balance(state, get_active_validator_indices(state, get_current_epoch(state)))
@ -1387,8 +1392,6 @@ def get_earliest_attestation(state: BeaconState, attestations: List[PendingAttes
#### Justification and finalization
Run the following function:
```python
def process_justification_and_finalization(state: BeaconState) -> None:
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
@ -1436,8 +1439,6 @@ def process_justification_and_finalization(state: BeaconState) -> None:
#### Crosslinks
Run the following function:
```python
def process_crosslinks(state: BeaconState) -> None:
state.previous_crosslinks = [c for c in state.current_crosslinks]
@ -1453,8 +1454,6 @@ def process_crosslinks(state: BeaconState) -> None:
#### Rewards and penalties
First, we define additional helpers:
```python
def get_base_reward(state: BeaconState, index: ValidatorIndex) -> Gwei:
adjusted_quotient = integer_squareroot(get_total_active_balance(state)) // BASE_REWARD_QUOTIENT
@ -1526,8 +1525,6 @@ def get_crosslink_deltas(state: BeaconState) -> Tuple[List[Gwei], List[Gwei]]:
return [rewards, penalties]
```
Run the following function:
```python
def process_rewards_and_penalties(state: BeaconState) -> None:
if get_current_epoch(state) == GENESIS_EPOCH:
@ -1542,8 +1539,6 @@ def process_rewards_and_penalties(state: BeaconState) -> None:
#### Registry updates
Run the following function:
```python
def process_registry_updates(state: BeaconState) -> None:
# Process activation eligibility and ejections
@ -1568,8 +1563,6 @@ def process_registry_updates(state: BeaconState) -> None:
#### Slashings
Run the following function:
```python
def process_slashings(state: BeaconState) -> None:
current_epoch = get_current_epoch(state)
@ -1592,8 +1585,6 @@ def process_slashings(state: BeaconState) -> None:
#### Final updates
Run the following function:
```python
def process_final_updates(state: BeaconState) -> None:
current_epoch = get_current_epoch(state)
@ -1632,18 +1623,16 @@ def process_final_updates(state: BeaconState) -> None:
state.current_epoch_attestations = []
```
### Per-slot processing
At every `slot > GENESIS_SLOT` run the following function:
```python
def advance_slot(state: BeaconState) -> None:
state.slot += 1
```
### Per-block processing
For every `block` except the genesis block, run `process_block_header(state, block)`, `process_randao(state, block)` and `process_eth1_data(state, block)`.
```python
def process_block(state: BeaconState, block: BeaconBlock) -> None:
process_block_header(state, block)
process_randao(state, block)
process_eth1_data(state, block)
process_operations(state, block.body)
# verify_block_state_root(state, block)
```
#### Block header
@ -1691,8 +1680,6 @@ def process_eth1_data(state: BeaconState, block: BeaconBlock) -> None:
#### Operations
The sub-sections below define helper functions, one per operation type. The full processing of operations is done by running `process_operations(state, block.body)`.
```python
def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
assert len(body.deposits) == min(MAX_DEPOSITS, state.latest_eth1_data.deposit_count - state.deposit_index)
@ -1913,8 +1900,6 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None:
#### State root verification
Verify the block's `state_root` by running the following function:
```python
def verify_block_state_root(state: BeaconState, block: BeaconBlock) -> None:
assert block.state_root == hash_tree_root(state)

View File

@ -1,47 +0,0 @@
from . import spec
from typing import (
Any,
Callable,
List
)
from .spec import (
BeaconState,
BeaconBlock,
Slot,
)
def process_block(state: BeaconState, block: BeaconBlock, verify_state_root) -> None:
spec.process_block_header(state, block)
spec.process_randao(state, block)
spec.process_eth1_data(state, block)
spec.process_operations(state, block.body)
if verify_state_root:
spec.verify_block_state_root(state, block)
def process_epoch_transition(state: BeaconState) -> None:
spec.process_justification_and_finalization(state)
spec.process_crosslinks(state)
spec.process_rewards_and_penalties(state)
spec.process_registry_updates(state)
spec.process_slashings(state)
spec.process_final_updates(state)
def state_transition_to(state: BeaconState, up_to: Slot) -> BeaconState:
while state.slot < up_to:
spec.cache_state(state)
if (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0:
process_epoch_transition(state)
spec.advance_slot(state)
def state_transition(state: BeaconState,
block: BeaconBlock,
verify_state_root: bool=False) -> BeaconState:
state_transition_to(state, block.slot)
process_block(state, block, verify_state_root)

View File

@ -3,13 +3,11 @@ import pytest
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from eth2spec.phase0.spec import (
get_current_epoch,
process_attestation,
slot_to_epoch,
state_transition,
)
from tests.helpers import (
build_empty_block_for_next_slot,

View File

@ -5,10 +5,10 @@ import pytest
from eth2spec.phase0.spec import (
get_beacon_proposer_index,
cache_state,
advance_slot,
process_block_header,
)
from tests.helpers import (
advance_slot,
build_empty_block_for_next_slot,
next_slot,
)

View File

@ -3,13 +3,11 @@ import pytest
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from eth2spec.phase0.spec import (
cache_state,
get_crosslink_deltas,
process_crosslinks,
state_transition,
)
from tests.helpers import (
add_attestation_to_state,

View File

@ -2,9 +2,6 @@ from copy import deepcopy
from py_ecc import bls
from eth2spec.phase0.state_transition import (
state_transition,
)
import eth2spec.phase0.spec as spec
from eth2spec.utils.minimal_ssz import signing_root
from eth2spec.phase0.spec import (
@ -38,6 +35,7 @@ from eth2spec.phase0.spec import (
get_shard_delta,
hash_tree_root,
slot_to_epoch,
state_transition,
verify_merkle_branch,
hash,
)
@ -53,6 +51,10 @@ pubkeys = [bls.privtopub(privkey) for privkey in privkeys]
pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)}
def advance_slot(state) -> None:
state.slot += 1
def get_balance(state, index):
return state.balances[index]

View File

@ -4,9 +4,6 @@ import pytest
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from .helpers import (
build_empty_block_for_next_slot,
fill_aggregate_attestation,
@ -67,7 +64,7 @@ def next_epoch_with_attestations(state,
fill_aggregate_attestation(post_state, prev_attestation)
block.body.attestations.append(prev_attestation)
state_transition(post_state, block)
spec.state_transition(post_state, block)
blocks.append(block)
return state, blocks, post_state

View File

@ -20,13 +20,10 @@ from eth2spec.phase0.spec import (
get_state_root,
get_current_epoch,
get_domain,
advance_slot,
cache_state,
verify_merkle_branch,
hash,
)
from eth2spec.phase0.state_transition import (
state_transition,
hash,
)
from eth2spec.utils.merkle_minimal import (
calc_merkle_tree_from_leaves,
@ -34,6 +31,7 @@ from eth2spec.utils.merkle_minimal import (
get_merkle_root,
)
from .helpers import (
advance_slot,
get_balance,
build_deposit_data,
build_empty_block_for_next_slot,