---
tags: hard_fork_1
---
# Hard forking Beacon State
## Goal
* Background
* What issues do we need to solve?
* What solutions do we have?
## Background
Hardfork 1 is coming this summer. One of the biggest foreseeable issue is there will be two versions of beacon state. One for pre fork and one for post fork. Everything that uses the beacon state will have to adapt to the two variations. Example:
```
Before epoch N: use beacon state v1
After epoch N: use beacon state v2
```
Such changes if not planned carefully will become technical debts and cause lingering issues throughout Prysm's life time.
Assuming there's one hard fork per year, this topic is something we'll revisit time and time, it's important that we document our thoughts, feedbacks and solutions during this process.
## Refresher
Currently beacon state looks like:
```python=
class BeaconState(Container):
# Versioning
genesis_time: uint64
genesis_validators_root: Root
slot: Slot
fork: Fork
# History
latest_block_header: BeaconBlockHeader
block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT]
# Eth1
eth1_data: Eth1Data
eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH]
eth1_deposit_index: uint64
# Registry
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
# Randomness
randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR]
# Slashings
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
# Attestations
previous_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
current_epoch_attestations: List[PendingAttestation, MAX_ATTESTATIONS * SLOTS_PER_EPOCH]
# Finality
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch
previous_justified_checkpoint: Checkpoint # Previous epoch snapshot
current_justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint
```
After hard fork, the beacon state will looke like:
```python=
class BeaconState(Container):
# Versioning
genesis_time: uint64
genesis_validators_root: Root
slot: Slot
fork: Fork
# History
latest_block_header: BeaconBlockHeader
block_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
state_roots: Vector[Root, SLOTS_PER_HISTORICAL_ROOT]
historical_roots: List[Root, HISTORICAL_ROOTS_LIMIT]
# Eth1
eth1_data: Eth1Data
eth1_data_votes: List[Eth1Data, EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH]
eth1_deposit_index: uint64
# Registry
validators: List[Validator, VALIDATOR_REGISTRY_LIMIT]
balances: List[Gwei, VALIDATOR_REGISTRY_LIMIT]
# Randomness
randao_mixes: Vector[Bytes32, EPOCHS_PER_HISTORICAL_VECTOR]
# Slashings
slashings: Vector[Gwei, EPOCHS_PER_SLASHINGS_VECTOR] # Per-epoch sums of slashed effective balances
# Participation
previous_epoch_participation: List[ValidatorFlag, VALIDATOR_REGISTRY_LIMIT]
current_epoch_participation: List[ValidatorFlag, VALIDATOR_REGISTRY_LIMIT]
# Finality
justification_bits: Bitvector[JUSTIFICATION_BITS_LENGTH] # Bit set for every recent justified epoch
previous_justified_checkpoint: Checkpoint
current_justified_checkpoint: Checkpoint
finalized_checkpoint: Checkpoint
# Light client sync committees
current_sync_committee: SyncCommittee
next_sync_committee: SyncCommittee
```
As we can see, there's going to be *replacement* and *extension*.
* `current/previous_epoch_attestations` which is `List[PendingAttestation]` is getting replaced by `current/previous_epoch_participation` which is `List[ValidatorFlag]`
* The beacon state is also getting extended by new fields such as `current_sync_committee` and `next_sync_committee`
For designing, we should aim to design for both cases that is `replacement` and `extension`
## Solution
The most ideal solution is to implement a layer of abstraction with some wrappers around the two beacon state types. Since protobuf has getter/setter methods, we could use an interface which both states conform to. (e.g. `BeaconState` interface)
We want to avoid: `db.SaveStateV1(*BeaconStateV1)` and `db.SaveStateV2(*BeaconStateV2)`
We want `db.SaveState(BeaconState)` where `BeaconState` is an interface:
```go
type BeaconState interface {
Validators() []*ethpb.Validator
...
}
type BeaconStateV2 interface {
BeaconState
Eth1State() *ethpb.Eth1State // some new methods/fields added in the hard fork
}
```
Within `SaveState`, the function can use reflect and detect whether it's v1 or v2 then save it to the appropiate bucket.
## Affected area
`BeaconState` is heavily used across Prysm, this will impact not only in DB but in every service and every storage unit. Some notable ones:
* Core processing block using parent state
* Sync receiving beacon chain objects
* RPC server for serving validators
* RPC server for serving beacon block explorers
* Database for storage
* Cache for storage
## Side note
`BeaconBlockBody` will also be different post-hardfork. Whichever mechanism that came up with here, it should be reusable for the others.
## Proposal
1.) First, let's choose the location. I'm putting it under`beacon-chain/state/types` I think this is the best location given beacon state is not used in other pkgs such as `validator`, `slasher` and `shared`. It also lives next to it's implementation `beacon-chain/state`.
2.) We'll use folders `v0`, `v1`... to distingush beacon state internal changes due to network upgrade aka. hard fork.
3.) Each version `v0`, `v1`... has its own unique `struct.go`
```go=
package v0
type BeaconState struct {
GenesisTime uint64
Slot types.Slot
GenesisValidatorsRoot [32]byte
BlockRoots [][32]byte
Validators []*v1alpha1.Validator
PreviousJustifiedCheckpoint *v1alpha1.Checkpoint
}
```
4.) The `BeaconState` from above implements the interface that's defined in `interface.go` under `beacon-chain/state/types`. Which looks like:
```go=
package types
type BeaconStateVO interface {
GenesisTime() uint64
SetGenesisTime(time uint64)
}
type BeaconStateV1 interface {
BeaconStateVO
// Post HF1 state getters and setters.
}
```
5.) In `beacon-chain/state/` pkg, we replace pb with the interface
```go=
type BeaconState struct {
state *pbp2p.BeaconState
lock sync.RWMutex
dirtyFields map[fieldIndex]interface{}
...
```
```go=
type BeaconState struct {
state stateTypes.BeaconStateVO
lock sync.RWMutex
dirtyFields map[fieldIndex]interface{}
...
```
6.) Then we'll replace everywhere that was using pb's getter/setter
```go=
func (b *BeaconState) genesisTime() uint64 {
if !b.HasInnerState() {
return 0
}
return b.state.GenesisTime
}
```
```go=
func (b *BeaconState) genesisTime() uint64 {
if !b.HasInnerState() {
return 0
}
return b.state.GenesisTime()
}
```
The project structure looks like the following:

## Open questions
1.) For root are we using []byte or [32]byte?
```go=
type BeaconState struct {
GenesisValidatorsRoot [32]byte //or []byte
BlockRoots [][32]byte //or [][]byte
}
```
2.) What do we do with function that returns the underlying beacon state pb object? Do we just return the underlying native struct object?
```go=
// InnerStateUnsafe returns the pointer value of the underlying
// beacon state proto object, bypassing immutability. Use with care.
func (b *BeaconState) InnerStateUnsafe() *pbp2p.BeaconState {
if b == nil {
return nil
}
return b.state
}
```