Assimilated #649

This commit is contained in:
vbuterin 2019-03-03 05:04:28 -06:00 committed by GitHub
parent dcb0205adc
commit d0fc455a1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 156 additions and 97 deletions

View File

@ -41,8 +41,8 @@
- [`Transfer`](#transfer) - [`Transfer`](#transfer)
- [Beacon chain blocks](#beacon-chain-blocks) - [Beacon chain blocks](#beacon-chain-blocks)
- [`BeaconBlock`](#beaconblock) - [`BeaconBlock`](#beaconblock)
- [`BeaconBlockHeader`](#beaconblockheader)
- [`BeaconBlockBody`](#beaconblockbody) - [`BeaconBlockBody`](#beaconblockbody)
- [`Proposal`](#proposal)
- [Beacon chain state](#beacon-chain-state) - [Beacon chain state](#beacon-chain-state)
- [`BeaconState`](#beaconstate) - [`BeaconState`](#beaconstate)
- [`Validator`](#validator) - [`Validator`](#validator)
@ -56,6 +56,7 @@
- [`hash`](#hash) - [`hash`](#hash)
- [`hash_tree_root`](#hash_tree_root) - [`hash_tree_root`](#hash_tree_root)
- [`signed_root`](#signed_root) - [`signed_root`](#signed_root)
- [`get_temporary_block_header`](#get_temporary_block_header)
- [`slot_to_epoch`](#slot_to_epoch) - [`slot_to_epoch`](#slot_to_epoch)
- [`get_previous_epoch`](#get_previous_epoch) - [`get_previous_epoch`](#get_previous_epoch)
- [`get_current_epoch`](#get_current_epoch) - [`get_current_epoch`](#get_current_epoch)
@ -115,8 +116,7 @@
- [Slot](#slot) - [Slot](#slot)
- [Block roots](#block-roots) - [Block roots](#block-roots)
- [Per-block processing](#per-block-processing) - [Per-block processing](#per-block-processing)
- [Slot](#slot-1) - [Block header](#block-header)
- [Block signature](#block-signature)
- [RANDAO](#randao) - [RANDAO](#randao)
- [Eth1 data](#eth1-data) - [Eth1 data](#eth1-data)
- [Transactions](#transactions) - [Transactions](#transactions)
@ -185,7 +185,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code.
| `SHARD_COUNT` | `2**10` (= 1,024) | | `SHARD_COUNT` | `2**10` (= 1,024) |
| `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) | | `TARGET_COMMITTEE_SIZE` | `2**7` (= 128) |
| `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) | | `MAX_BALANCE_CHURN_QUOTIENT` | `2**5` (= 32) |
| `BEACON_CHAIN_SHARD_NUMBER` | `2**64 - 1` |
| `MAX_INDICES_PER_SLASHABLE_VOTE` | `2**12` (= 4,096) | | `MAX_INDICES_PER_SLASHABLE_VOTE` | `2**12` (= 4,096) |
| `MAX_EXIT_DEQUEUES_PER_EPOCH` | `2**2` (= 4) | | `MAX_EXIT_DEQUEUES_PER_EPOCH` | `2**2` (= 4) |
| `SHUFFLE_ROUND_COUNT` | 90 | | `SHUFFLE_ROUND_COUNT` | 90 |
@ -233,13 +232,13 @@ Code snippets appearing in `this style` are to be interpreted as Python code.
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes | | `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
| `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes | | `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes |
| `EPOCHS_PER_ETH1_VOTING_PERIOD` | `2**4` (= 16) | epochs | ~1.7 hours | | `EPOCHS_PER_ETH1_VOTING_PERIOD` | `2**4` (= 16) | epochs | ~1.7 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours | | `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
### State list lengths ### State list lengths
| Name | Value | Unit | Duration | | Name | Value | Unit | Duration |
| - | - | :-: | :-: | | - | - | :-: | :-: |
| `LATEST_BLOCK_ROOTS_LENGTH` | `2**13` (= 8,192) | slots | ~13 hours |
| `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | | `LATEST_RANDAO_MIXES_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
| `LATEST_ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | | `LATEST_ACTIVE_INDEX_ROOTS_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
| `LATEST_SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days | | `LATEST_SLASHED_EXIT_LENGTH` | `2**13` (= 8,192) | epochs | ~36 days |
@ -273,11 +272,11 @@ Code snippets appearing in `this style` are to be interpreted as Python code.
| Name | Value | | Name | Value |
| - | - | | - | - |
| `DOMAIN_DEPOSIT` | `0` | | `DOMAIN_BEACON_BLOCK` | `0` |
| `DOMAIN_ATTESTATION` | `1` | | `DOMAIN_RANDAO` | `1` |
| `DOMAIN_PROPOSAL` | `2` | | `DOMAIN_ATTESTATION` | `2` |
| `DOMAIN_EXIT` | `3` | | `DOMAIN_DEPOSIT` | `3` |
| `DOMAIN_RANDAO` | `4` | | `DOMAIN_VOLUNTARY_EXIT` | `4` |
| `DOMAIN_TRANSFER` | `5` | | `DOMAIN_TRANSFER` | `5` |
## Data structures ## Data structures
@ -294,10 +293,10 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git
{ {
# Proposer index # Proposer index
'proposer_index': 'uint64', 'proposer_index': 'uint64',
# First proposal # First block header
'proposal_1': Proposal, 'header_1': BeaconBlockHeader,
# Second proposal # Second block header
'proposal_2': Proposal, 'header_2': BeaconBlockHeader,
} }
``` ```
@ -467,14 +466,21 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git
{ {
# Header # Header
'slot': 'uint64', 'slot': 'uint64',
'parent_root': 'bytes32', 'previous_block_root': 'bytes32',
'state_root': 'bytes32', 'state_root': 'bytes32',
'randao_reveal': 'bytes96',
'eth1_data': Eth1Data,
# Body
'body': BeaconBlockBody, 'body': BeaconBlockBody,
# Signature 'signature': 'bytes96',
}
```
#### `BeaconBlockHeader`
```python
{
'slot': 'uint64',
'previous_block_root': 'bytes32',
'state_root': 'bytes32',
'block_body_root': 'bytes32',
'signature': 'bytes96', 'signature': 'bytes96',
} }
``` ```
@ -483,6 +489,8 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git
```python ```python
{ {
'randao_reveal': 'bytes96',
'eth1_data': Eth1Data,
'proposer_slashings': [ProposerSlashing], 'proposer_slashings': [ProposerSlashing],
'attester_slashings': [AttesterSlashing], 'attester_slashings': [AttesterSlashing],
'attestations': [Attestation], 'attestations': [Attestation],
@ -492,21 +500,6 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git
} }
``` ```
#### `Proposal`
```python
{
# Slot number
'slot': 'uint64',
# Shard number (`BEACON_CHAIN_SHARD_NUMBER` for beacon chain)
'shard': 'uint64',
# Block root
'block_root': 'bytes32',
# Signature
'signature': 'bytes96',
}
```
### Beacon chain state ### Beacon chain state
#### `BeaconState` #### `BeaconState`
@ -543,9 +536,11 @@ The following data structures are defined as [SimpleSerialize (SSZ)](https://git
# Recent state # Recent state
'latest_crosslinks': [Crosslink], 'latest_crosslinks': [Crosslink],
'latest_block_roots': ['bytes32'], 'latest_block_roots': ['bytes32'],
'latest_state_roots': ['bytes32'],
'latest_active_index_roots': ['bytes32'], 'latest_active_index_roots': ['bytes32'],
'latest_slashed_balances': ['uint64'], # Balances slashed at every withdrawal period 'latest_slashed_balances': ['uint64'], # Balances slashed at every withdrawal period
'batched_block_roots': ['bytes32'], 'latest_block_header': BeaconBlockHeader, # `latest_block_header.state_root == ZERO_HASH` temporarily
'historical_roots': ['bytes32'],
# Ethereum 1.0 chain data # Ethereum 1.0 chain data
'latest_eth1_data': Eth1Data, 'latest_eth1_data': Eth1Data,
@ -669,6 +664,22 @@ Note: We aim to migrate to a S[T/N]ARK-friendly hash function in a future Ethere
`def signed_root(object: SSZContainer) -> Bytes32` is a function defined in the [SimpleSerialize spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#signed-roots) to compute signed messages. `def signed_root(object: SSZContainer) -> Bytes32` is a function defined in the [SimpleSerialize spec](https://github.com/ethereum/eth2.0-specs/blob/master/specs/simple-serialize.md#signed-roots) to compute signed messages.
### `get_temporary_block_header`
```python
def get_temporary_block_header(block: BeaconBlock) -> BeaconBlockHeader:
"""
Return the block header corresponding to a block with ``state_root`` set to ``ZERO_HASH``.
"""
return BeaconBlockHeader(
slot=block.slot,
previous_block_root=block.previous_block_root,
state_root=ZERO_HASH,
block_body_root=hash_tree_root(block.body),
signature=block.signature,
)
```
### `slot_to_epoch` ### `slot_to_epoch`
```python ```python
@ -920,9 +931,8 @@ def get_block_root(state: BeaconState,
""" """
Return the block root at a recent ``slot``. Return the block root at a recent ``slot``.
""" """
assert state.slot <= slot + LATEST_BLOCK_ROOTS_LENGTH assert slot < state.slot <= slot + SLOTS_PER_HISTORICAL_ROOT
assert slot < state.slot return state.latest_block_roots[slot % SLOTS_PER_HISTORICAL_ROOT]
return state.latest_block_roots[slot % LATEST_BLOCK_ROOTS_LENGTH]
``` ```
`get_block_root(_, s)` should always return `hash_tree_root` of the block in the beacon chain at slot `s`, and `get_crosslink_committees_at_slot(_, s)` should not change unless the [validator](#dfn-validator) registry changes. `get_block_root(_, s)` should always return `hash_tree_root` of the block in the beacon chain at slot `s`, and `get_crosslink_committees_at_slot(_, s)` should not change unless the [validator](#dfn-validator) registry changes.
@ -1405,35 +1415,47 @@ For convenience, we provide the interface to the contract here:
## On genesis ## On genesis
A valid block with slot `GENESIS_SLOT` (a "genesis block") has the following values. Other validity rules (e.g. requiring a signature) do not apply. When enough full deposits have been made to the deposit contract, an `Eth2Genesis` log is emitted. Construct a corresponding `genesis_state` and `genesis_block` as follows:
* Let `genesis_validator_deposits` be the list of deposits, ordered chronologically, up to and including the deposit that triggered the `Eth2Genesis` log.
* Let `genesis_time` be the timestamp specified in the `Eth2Genesis` log.
* Let `genesis_eth1_data` be the `Eth1Data` object where:
* `genesis_eth1_data.deposit_root` is the `deposit_root` contained in the `Eth2Genesis` log.
* `genesis_eth1_data.block_hash` is the hash of the Ethereum 1.0 block that emitted the `Eth2Genesis` log.
* Let `genesis_state = get_genesis_beacon_state(genesis_validator_deposits, genesis_time, genesis_eth1_data)`.
* Let `genesis_block = get_empty_block()`.
* Set `genesis_block.state_root = hash_tree_root(genesis_state)`.
```python ```python
{ def get_empty_block() -> BeaconBlock:
slot=GENESIS_SLOT, """
parent_root=ZERO_HASH, Get an empty ``BeaconBlock``.
state_root=GENESIS_STATE_ROOT, """
randao_reveal=EMPTY_SIGNATURE, return BeaconBlock(
eth1_data=Eth1Data( slot=GENESIS_SLOT,
deposit_root=ZERO_HASH, previous_block_root=ZERO_HASH,
block_hash=ZERO_HASH state_root=ZERO_HASH,
), body=BeaconBlockBody(
signature=EMPTY_SIGNATURE, randao_reveal=EMPTY_SIGNATURE,
body=BeaconBlockBody( eth1_data=Eth1Data(
proposer_slashings=[], deposit_root=ZERO_HASH,
attester_slashings=[], block_hash=ZERO_HASH,
attestations=[], ),
deposits=[], proposer_slashings=[],
exits=[], attester_slashings=[],
), attestations=[],
} deposits=[],
exits=[],
transfers=[],
),
signature=EMPTY_SIGNATURE,
)
``` ```
`GENESIS_STATE_ROOT` (in the above "genesis block") is generated from the `get_genesis_beacon_state` function below. When enough full deposits have been made to the deposit contract and the `Eth2Genesis` log has been emitted, `get_genesis_beacon_state` will execute to compute the `hash_tree_root` of `BeaconState`.
```python ```python
def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit], def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit],
genesis_time: int, genesis_time: int,
latest_eth1_data: Eth1Data) -> BeaconState: genesis_eth1_data: Eth1Data) -> BeaconState:
""" """
Get the genesis ``BeaconState``. Get the genesis ``BeaconState``.
""" """
@ -1471,13 +1493,15 @@ def get_genesis_beacon_state(genesis_validator_deposits: List[Deposit],
# Recent state # Recent state
latest_crosslinks=[Crosslink(epoch=GENESIS_EPOCH, crosslink_data_root=ZERO_HASH) for _ in range(SHARD_COUNT)], latest_crosslinks=[Crosslink(epoch=GENESIS_EPOCH, crosslink_data_root=ZERO_HASH) for _ in range(SHARD_COUNT)],
latest_block_roots=[ZERO_HASH for _ in range(LATEST_BLOCK_ROOTS_LENGTH)], latest_block_roots=[ZERO_HASH for _ in range(SLOTS_PER_HISTORICAL_ROOT)],
latest_state_roots=[ZERO_HASH for _ in range(SLOTS_PER_HISTORICAL_ROOT)],
latest_active_index_roots=[ZERO_HASH for _ in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH)], latest_active_index_roots=[ZERO_HASH for _ in range(LATEST_ACTIVE_INDEX_ROOTS_LENGTH)],
latest_slashed_balances=[0 for _ in range(LATEST_SLASHED_EXIT_LENGTH)], latest_slashed_balances=[0 for _ in range(LATEST_SLASHED_EXIT_LENGTH)],
batched_block_roots=[], latest_block_header=get_temporary_block_header(get_empty_block()),
historical_roots=[],
# Ethereum 1.0 chain data # Ethereum 1.0 chain data
latest_eth1_data=latest_eth1_data, latest_eth1_data=genesis_eth1_data,
eth1_data_votes=[], eth1_data_votes=[],
deposit_index=len(genesis_validator_deposits) deposit_index=len(genesis_validator_deposits)
) )
@ -1511,7 +1535,7 @@ Processing the beacon chain is similar to processing the Ethereum 1.0 chain. Cli
For a beacon chain block, `block`, to be processed by a node, the following conditions must be met: For a beacon chain block, `block`, to be processed by a node, the following conditions must be met:
* The parent block with root `block.parent_root` has been processed and accepted. * The parent block with root `block.previous_block_root` has been processed and accepted.
* An Ethereum 1.0 block pointed to by the `state.latest_eth1_data.block_hash` has been processed and accepted. * An Ethereum 1.0 block pointed to by the `state.latest_eth1_data.block_hash` has been processed and accepted.
* The node's Unix time is greater than or equal to `state.genesis_time + (block.slot - GENESIS_SLOT) * SECONDS_PER_SLOT`. (Note that leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year.) * The node's Unix time is greater than or equal to `state.genesis_time + (block.slot - GENESIS_SLOT) * SECONDS_PER_SLOT`. (Note that leap seconds mean that slots will occasionally last `SECONDS_PER_SLOT + 1` or `SECONDS_PER_SLOT - 1` seconds, possibly several times a year.)
@ -1590,41 +1614,73 @@ _Note_: If there are skipped slots between a block and its parent block, run the
### Per-slot processing ### Per-slot processing
Below are the processing steps that happen at every slot. At every `slot > GENESIS_SLOT` run the following function:
#### Slot ```python
def advance_slot(state: BeaconState) -> None:
* Set `state.slot += 1`. state.latest_state_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = hash_tree_root(state)
state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = get_block_root(state, state.slot - 1)
#### Block roots if state.latest_block_header.state_root == ZERO_HASH:
state.latest_block_header.state_root = get_state_root(state, state.slot)
* Let `previous_block_root` be the `hash_tree_root` of the previous beacon block processed in the chain. state.slot += 1
* Set `state.latest_block_roots[(state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = previous_block_root`. ```
* If `state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0` append `merkle_root(state.latest_block_roots)` to `state.batched_block_roots`.
### Per-block processing ### Per-block processing
Below are the processing steps that happen at every `block`. For every `block` except the genesis block, run `process_block_header(state, block)`, `process_randao(state, block)` and `process_eth1_data(state, block)`.
#### Slot #### Block header
* Verify that `block.slot == state.slot`. ```python
def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
#### Block signature # Verify that the slots match
assert block.slot == state.slot
* Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`. # Verify that the parent matches
* Let `proposal = Proposal(block.slot, BEACON_CHAIN_SHARD_NUMBER, signed_root(block, "signature"), block.signature)`. assert block.previous_block_root == hash_tree_root(state.latest_block_header)
* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=signed_root(proposal, "signature"), signature=proposal.signature, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_PROPOSAL))`. # Save previous block root
state.latest_block_roots[(state.slot - 1) % SLOTS_PER_HISTORICAL_ROOT] = block.previous_block_root
# Save current block as the new latest block
state.latest_block_header = get_temporary_block_header(block)
# Verify proposer signature
proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]
assert bls_verify(
pubkey=proposer.pubkey,
message_hash=signed_root(block, "signature"),
signature=block.signature,
domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_BEACON_BLOCK)
)
```
#### RANDAO #### RANDAO
* Verify that `bls_verify(pubkey=proposer.pubkey, message_hash=hash_tree_root(get_current_epoch(state)), signature=block.randao_reveal, domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO))`. ```python
* Set `state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = xor(get_randao_mix(state, get_current_epoch(state)), hash(block.randao_reveal))`. def process_randao(state: BeaconState, block: BeaconBlock) -> None:
# Verify that the provided randao value is valid
assert bls_verify(
pubkey=proposer.pubkey,
message_hash=hash_tree_root(get_current_epoch(state)),
signature=block.body.randao_reveal,
domain=get_domain(state.fork, get_current_epoch(state), DOMAIN_RANDAO)
)
# Mix it in
state.latest_randao_mixes[get_current_epoch(state) % LATEST_RANDAO_MIXES_LENGTH] = (
xor(get_randao_mix(state, get_current_epoch(state)),
hash(block.body.randao_reveal))
)
```
#### Eth1 data #### Eth1 data
* If there exists an `eth1_data_vote` in `state.eth1_data_votes` for which `eth1_data_vote.eth1_data == block.eth1_data` (there will be at most one), set `eth1_data_vote.vote_count += 1`. ```python
* Otherwise, append to `state.eth1_data_votes` a new `Eth1DataVote(eth1_data=block.eth1_data, vote_count=1)`. def process_eth1_data(state: BeaconState, block: BeaconBlock) -> None:
for eth1_data_vote in state.eth1_data_votes:
# If someone else has already voted for the same hash, add to its counter
if eth1_data_vote.eth1_data == block.body.eth1_data:
eth1_data_vote.vote_count += 1
return
# If we're seeing this hash for the first time, make a new counter
state.eth1_data_votes.append(Eth1DataVote(eth1_data=block.body.eth1_data, vote_count=1))
```
#### Transactions #### Transactions
@ -1643,20 +1699,20 @@ def process_proposer_slashing(state: BeaconState,
""" """
proposer = state.validator_registry[proposer_slashing.proposer_index] proposer = state.validator_registry[proposer_slashing.proposer_index]
# Verify that the slot is the same # Verify that the slot is the same
assert proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot assert proposer_slashing.header_1.slot == proposer_slashing.header_2.slot
# Verify that the shard is the same (or that both proposals are beacon chain proposals) # Verify that the shard is the same (or that both proposals are beacon chain proposals)
assert proposer_slashing.proposal_1.shard == proposer_slashing.proposal_2.shard assert proposer_slashing.header_1.shard == proposer_slashing.header_2.shard
# But the roots are different! # But the roots are different!
assert proposer_slashing.proposal_1.block_root != proposer_slashing.proposal_2.block_root assert proposer_slashing.header_1.block_root != proposer_slashing.header_2.block_root
# Proposer is not yet slashed # Proposer is not yet slashed
assert proposer.slashed is False assert proposer.slashed is False
# Signatures are valid # Signatures are valid
for proposal in (proposer_slashing.proposal_1, proposer_slashing.proposal_2): for header in (proposer_slashing.header_1, proposer_slashing.header_2):
assert bls_verify( assert bls_verify(
pubkey=proposer.pubkey, pubkey=proposer.pubkey,
message_hash=signed_root(proposal, "signature"), message_hash=signed_root(header, "signature"),
signature=proposal.signature, signature=header.signature,
domain=get_domain(state.fork, slot_to_epoch(proposal.slot), DOMAIN_PROPOSAL) domain=get_domain(state.fork, slot_to_epoch(header.slot), DOMAIN_PROPOSAL)
) )
slash_validator(state, proposer_slashing.proposer_index) slash_validator(state, proposer_slashing.proposer_index)
``` ```
@ -1836,7 +1892,7 @@ def process_exit(state: BeaconState, exit: VoluntaryExit) -> None:
pubkey=validator.pubkey, pubkey=validator.pubkey,
message_hash=signed_root(exit, "signature"), message_hash=signed_root(exit, "signature"),
signature=exit.signature, signature=exit.signature,
domain=get_domain(state.fork, exit.epoch, DOMAIN_EXIT) domain=get_domain(state.fork, exit.epoch, DOMAIN_VOLUNTARY_EXIT)
) )
# Run the exit # Run the exit
initiate_validator_exit(state, exit.validator_index) initiate_validator_exit(state, exit.validator_index)
@ -2368,6 +2424,9 @@ def finish_epoch_update(state: BeaconState) -> None:
) )
# Set randao mix # Set randao mix
state.latest_randao_mixes[next_epoch % LATEST_RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch) state.latest_randao_mixes[next_epoch % LATEST_RANDAO_MIXES_LENGTH] = get_randao_mix(state, current_epoch)
# Set historical root accumulator
if next_epoch % (SLOTS_PER_HISTORICAL_ROOT // SLOTS_PER_EPOCH) == 0:
state.historical_roots.append(merkle_root(state.latest_block_roots + state.latest_state_roots))
# Rotate current/previous epoch attestations # Rotate current/previous epoch attestations
state.previous_epoch_attestations = state.current_epoch_attestations state.previous_epoch_attestations = state.current_epoch_attestations
state.current_epoch_attestations = [] state.current_epoch_attestations = []