prysm-pulse/beacon-chain/state/setters.go
Raul Jordan abe679e90e
Create New Beacon State Data Structure (#4602)
* begin state service

* begin on the state trie idea

* created beacon state structure

* add in the full clone getter

* return by value instead

* add all setters

* new state setters are being completed

* arrays roots exposed

*  close to finishing all these headerssss

* functionality complete

* added in proto benchmark test

* test for compatibility

* add test for compat

* comments fixed

* add clone

* add clone

* remove underlying copies

* make it immutable

* integrate it into chainservice

* revert

* wrap up comments for package

* address all comments and godocs

* address all comments

* clone the pending attestation properly

* properly clone remaining items

* tests pass fixed bug

* prevent nil pointer exceptions

* fixed up some bugs in the clone comparisons

Co-authored-by: Nishant Das <nish1993@hotmail.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2020-01-21 22:36:12 -06:00

354 lines
9.8 KiB
Go

package state
import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-bitfield"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/stateutil"
)
type fieldIndex int
// Below we define a set of useful enum values for the field
// indices of the beacon state. For example, genesisTime is the
// 0th field of the beacon state. This is helpful when we are
// updating the Merkle branches up the trie representation
// of the beacon state.
const (
genesisTime fieldIndex = iota
slot
fork
latestBlockHeader
blockRoots
stateRoots
historicalRoots
eth1Data
eth1DataVotes
eth1DepositIndex
validators
balances
randaoMixes
slashings
previousEpochAttestations
currentEpochAttestations
justificationBits
previousJustifiedCheckpoint
currentJustifiedCheckpoint
finalizedCheckpoint
)
// SetGenesisTime for the beacon state.
func (b *BeaconState) SetGenesisTime(val uint64) error {
b.state.GenesisTime = val
root := stateutil.Uint64Root(val)
b.lock.Lock()
b.merkleLayers[0][genesisTime] = root[:]
b.recomputeRoot(int(genesisTime))
b.lock.Unlock()
return nil
}
// SetSlot for the beacon state.
func (b *BeaconState) SetSlot(val uint64) error {
b.state.Slot = val
root := stateutil.Uint64Root(val)
b.lock.Lock()
b.merkleLayers[0][slot] = root[:]
b.recomputeRoot(int(slot))
b.lock.Unlock()
return nil
}
// SetFork version for the beacon chain.
func (b *BeaconState) SetFork(val *pbp2p.Fork) error {
root, err := stateutil.ForkRoot(val)
if err != nil {
return err
}
b.state.Fork = val
b.lock.Lock()
b.merkleLayers[0][fork] = root[:]
b.recomputeRoot(int(fork))
b.lock.Unlock()
return nil
}
// SetLatestBlockHeader in the beacon state.
func (b *BeaconState) SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error {
root, err := stateutil.BlockHeaderRoot(val)
if err != nil {
return err
}
b.state.LatestBlockHeader = val
b.lock.Lock()
b.merkleLayers[0][latestBlockHeader] = root[:]
b.recomputeRoot(int(latestBlockHeader))
b.lock.Unlock()
return nil
}
// SetBlockRoots for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetBlockRoots(val [][]byte) error {
root, err := stateutil.RootsArrayHashTreeRoot(val, params.BeaconConfig().SlotsPerHistoricalRoot, "BlockRoots")
if err != nil {
return err
}
b.state.BlockRoots = val
b.lock.Lock()
b.merkleLayers[0][blockRoots] = root[:]
b.recomputeRoot(int(blockRoots))
b.lock.Unlock()
return nil
}
// SetStateRoots for the beacon state. This PR updates the entire
// to a new value by overwriting the previous one.
func (b *BeaconState) SetStateRoots(val [][]byte) error {
root, err := stateutil.RootsArrayHashTreeRoot(val, params.BeaconConfig().SlotsPerHistoricalRoot, "StateRoots")
if err != nil {
return err
}
b.state.StateRoots = val
b.lock.Lock()
b.merkleLayers[0][stateRoots] = root[:]
b.recomputeRoot(int(stateRoots))
b.lock.Unlock()
return nil
}
// SetHistoricalRoots for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetHistoricalRoots(val [][]byte) error {
root, err := stateutil.HistoricalRootsRoot(val)
if err != nil {
return err
}
b.state.HistoricalRoots = val
b.lock.Lock()
b.merkleLayers[0][historicalRoots] = root[:]
b.recomputeRoot(int(historicalRoots))
b.lock.Unlock()
return nil
}
// SetEth1Data for the beacon state.
func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error {
root, err := stateutil.Eth1Root(val)
if err != nil {
return err
}
b.state.Eth1Data = val
b.lock.Lock()
b.merkleLayers[0][eth1Data] = root[:]
b.recomputeRoot(int(eth1Data))
b.lock.Unlock()
return nil
}
// SetEth1DataVotes for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error {
root, err := stateutil.Eth1DataVotesRoot(val)
if err != nil {
return err
}
b.state.Eth1DataVotes = val
b.lock.Lock()
b.merkleLayers[0][eth1DataVotes] = root[:]
b.recomputeRoot(int(eth1DataVotes))
b.lock.Unlock()
return nil
}
// SetEth1DepositIndex for the beacon state.
func (b *BeaconState) SetEth1DepositIndex(val uint64) error {
b.state.Eth1DepositIndex = val
root := stateutil.Uint64Root(val)
b.lock.Lock()
b.merkleLayers[0][eth1DepositIndex] = root[:]
b.recomputeRoot(int(eth1DepositIndex))
b.lock.Unlock()
return nil
}
// SetValidators for the beacon state. This PR updates the entire
// to a new value by overwriting the previous one.
func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
root, err := stateutil.ValidatorRegistryRoot(val)
if err != nil {
return err
}
b.state.Validators = val
b.lock.Lock()
b.merkleLayers[0][validators] = root[:]
b.recomputeRoot(int(validators))
b.lock.Unlock()
return nil
}
// SetBalances for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetBalances(val []uint64) error {
root, err := stateutil.ValidatorBalancesRoot(val)
if err != nil {
return err
}
b.state.Balances = val
b.lock.Lock()
b.merkleLayers[0][balances] = root[:]
b.recomputeRoot(int(balances))
b.lock.Unlock()
return nil
}
// SetRandaoMixes for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
root, err := stateutil.RootsArrayHashTreeRoot(val, params.BeaconConfig().EpochsPerHistoricalVector, "RandaoMixes")
if err != nil {
return err
}
b.state.RandaoMixes = val
b.lock.Lock()
b.merkleLayers[0][randaoMixes] = root[:]
b.recomputeRoot(int(randaoMixes))
b.lock.Unlock()
return nil
}
// SetSlashings for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetSlashings(val []uint64) error {
root, err := stateutil.SlashingsRoot(val)
if err != nil {
return err
}
b.state.Slashings = val
b.lock.Lock()
b.merkleLayers[0][slashings] = root[:]
b.recomputeRoot(int(slashings))
b.lock.Unlock()
return nil
}
// SetPreviousEpochAttestations for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetPreviousEpochAttestations(val []*pbp2p.PendingAttestation) error {
root, err := stateutil.EpochAttestationsRoot(val)
if err != nil {
return err
}
b.state.PreviousEpochAttestations = val
b.lock.Lock()
b.merkleLayers[0][previousEpochAttestations] = root[:]
b.recomputeRoot(int(previousEpochAttestations))
b.lock.Unlock()
return nil
}
// SetCurrentEpochAttestations for the beacon state. This PR updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetCurrentEpochAttestations(val []*pbp2p.PendingAttestation) error {
root, err := stateutil.EpochAttestationsRoot(val)
if err != nil {
return err
}
b.state.CurrentEpochAttestations = val
b.lock.Lock()
b.merkleLayers[0][currentEpochAttestations] = root[:]
b.recomputeRoot(int(currentEpochAttestations))
b.lock.Unlock()
return nil
}
// SetJustificationBits for the beacon state.
func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error {
root := bytesutil.ToBytes32(b.state.JustificationBits)
b.state.JustificationBits = val
b.lock.Lock()
b.merkleLayers[0][justificationBits] = root[:]
b.recomputeRoot(int(justificationBits))
b.lock.Unlock()
return nil
}
// SetPreviousJustifiedCheckpoint for the beacon state.
func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) error {
root, err := stateutil.CheckpointRoot(val)
if err != nil {
return err
}
b.state.PreviousJustifiedCheckpoint = val
b.lock.Lock()
b.merkleLayers[0][previousJustifiedCheckpoint] = root[:]
b.recomputeRoot(int(previousJustifiedCheckpoint))
b.lock.Unlock()
return nil
}
// SetCurrentJustifiedCheckpoint for the beacon state.
func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error {
root, err := stateutil.CheckpointRoot(val)
if err != nil {
return err
}
b.state.CurrentJustifiedCheckpoint = val
b.lock.Lock()
b.merkleLayers[0][currentJustifiedCheckpoint] = root[:]
b.recomputeRoot(int(currentJustifiedCheckpoint))
b.lock.Unlock()
return nil
}
// SetFinalizedCheckpoint for the beacon state.
func (b *BeaconState) SetFinalizedCheckpoint(val *ethpb.Checkpoint) error {
root, err := stateutil.CheckpointRoot(val)
if err != nil {
return err
}
b.state.FinalizedCheckpoint = val
b.lock.Lock()
b.merkleLayers[0][finalizedCheckpoint] = root[:]
b.recomputeRoot(int(finalizedCheckpoint))
b.lock.Unlock()
return nil
}
// Recomputes the branch up the index in the Merkle trie representation
// of the beacon state. This method performs map reads and the caller MUST
// hold the lock before calling this method.
func (b *BeaconState) recomputeRoot(idx int) {
layers := b.merkleLayers
// The merkle tree structure looks as follows:
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
// Using information about the index which changed, idx, we recompute
// only its branch up the tree.
currentIndex := idx
root := b.merkleLayers[0][idx]
for i := 0; i < len(layers)-1; i++ {
isLeft := currentIndex%2 == 0
neighborIdx := currentIndex ^ 1
neighbor := make([]byte, 32)
if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) {
neighbor = layers[i][neighborIdx]
}
if isLeft {
parentHash := hashutil.Hash(append(root, neighbor...))
root = parentHash[:]
} else {
parentHash := hashutil.Hash(append(neighbor, root...))
root = parentHash[:]
}
parentIdx := currentIndex / 2
// Update the cached layers at the parent index.
layers[i+1][parentIdx] = root
currentIndex = parentIdx
}
b.merkleLayers = layers
}