mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-08 10:41:19 +00:00
7a46cc0681
* Enforce stronger head state operations * fix genesis state generation * one test left to fix * all tests passing now * gofmt * Update beacon-chain/db/kv/state_test.go Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com> * Update beacon-chain/db/kv/state.go Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com> * fix tests
177 lines
5.0 KiB
Go
177 lines
5.0 KiB
Go
package kv
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
|
|
"github.com/boltdb/bolt"
|
|
"github.com/pkg/errors"
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
"go.opencensus.io/trace"
|
|
)
|
|
|
|
// State returns the saved state using block's signing root,
|
|
// this particular block was used to generate the state.
|
|
func (k *Store) State(ctx context.Context, blockRoot [32]byte) (*pb.BeaconState, error) {
|
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.State")
|
|
defer span.End()
|
|
var s *pb.BeaconState
|
|
err := k.db.View(func(tx *bolt.Tx) error {
|
|
bucket := tx.Bucket(stateBucket)
|
|
enc := bucket.Get(blockRoot[:])
|
|
if enc == nil {
|
|
return nil
|
|
}
|
|
|
|
var err error
|
|
s, err = createState(enc)
|
|
return err
|
|
})
|
|
return s, err
|
|
}
|
|
|
|
// HeadState returns the latest canonical state in beacon chain.
|
|
func (k *Store) HeadState(ctx context.Context) (*pb.BeaconState, error) {
|
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.HeadState")
|
|
defer span.End()
|
|
var s *pb.BeaconState
|
|
err := k.db.View(func(tx *bolt.Tx) error {
|
|
// Retrieve head block's signing root from blocks bucket,
|
|
// to look up what the head state is.
|
|
bucket := tx.Bucket(blocksBucket)
|
|
headBlkRoot := bucket.Get(headBlockRootKey)
|
|
|
|
bucket = tx.Bucket(stateBucket)
|
|
enc := bucket.Get(headBlkRoot)
|
|
if enc == nil {
|
|
return nil
|
|
}
|
|
|
|
var err error
|
|
s, err = createState(enc)
|
|
return err
|
|
})
|
|
span.AddAttributes(trace.BoolAttribute("exists", s != nil))
|
|
if s != nil {
|
|
span.AddAttributes(trace.Int64Attribute("slot", int64(s.Slot)))
|
|
}
|
|
return s, err
|
|
}
|
|
|
|
// GenesisState returns the genesis state in beacon chain.
|
|
func (k *Store) GenesisState(ctx context.Context) (*pb.BeaconState, error) {
|
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.GenesisState")
|
|
defer span.End()
|
|
var s *pb.BeaconState
|
|
err := k.db.View(func(tx *bolt.Tx) error {
|
|
// Retrieve genesis block's signing root from blocks bucket,
|
|
// to look up what the genesis state is.
|
|
bucket := tx.Bucket(blocksBucket)
|
|
genesisBlockRoot := bucket.Get(genesisBlockRootKey)
|
|
|
|
bucket = tx.Bucket(stateBucket)
|
|
enc := bucket.Get(genesisBlockRoot)
|
|
if enc == nil {
|
|
return nil
|
|
}
|
|
|
|
var err error
|
|
s, err = createState(enc)
|
|
return err
|
|
})
|
|
return s, err
|
|
}
|
|
|
|
// SaveState stores a state to the db using block's signing root which was used to generate the state.
|
|
func (k *Store) SaveState(ctx context.Context, state *pb.BeaconState, blockRoot [32]byte) error {
|
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveState")
|
|
defer span.End()
|
|
enc, err := encode(state)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return k.db.Update(func(tx *bolt.Tx) error {
|
|
bucket := tx.Bucket(stateBucket)
|
|
return bucket.Put(blockRoot[:], enc)
|
|
})
|
|
}
|
|
|
|
// DeleteState by block root.
|
|
func (k *Store) DeleteState(ctx context.Context, blockRoot [32]byte) error {
|
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteState")
|
|
defer span.End()
|
|
|
|
return k.db.Batch(func(tx *bolt.Tx) error {
|
|
bkt := tx.Bucket(blocksBucket)
|
|
genesisBlockRoot := bkt.Get(genesisBlockRootKey)
|
|
|
|
bkt = tx.Bucket(checkpointBucket)
|
|
enc := bkt.Get(finalizedCheckpointKey)
|
|
checkpoint := ðpb.Checkpoint{}
|
|
if enc == nil {
|
|
checkpoint = ðpb.Checkpoint{Root: genesisBlockRoot}
|
|
} else if err := decode(enc, checkpoint); err != nil {
|
|
return err
|
|
}
|
|
|
|
bkt = tx.Bucket(blocksBucket)
|
|
headBlkRoot := bkt.Get(headBlockRootKey)
|
|
|
|
// Safe guard against deleting genesis, finalized, head state.
|
|
if bytes.Equal(blockRoot[:], checkpoint.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], headBlkRoot) {
|
|
return errors.New("cannot delete genesis, finalized, or head state")
|
|
}
|
|
|
|
bkt = tx.Bucket(stateBucket)
|
|
return bkt.Delete(blockRoot[:])
|
|
})
|
|
}
|
|
|
|
// DeleteStates by block roots.
|
|
func (k *Store) DeleteStates(ctx context.Context, blockRoots [][32]byte) error {
|
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteStates")
|
|
defer span.End()
|
|
|
|
return k.db.Batch(func(tx *bolt.Tx) error {
|
|
bkt := tx.Bucket(blocksBucket)
|
|
genesisBlockRoot := bkt.Get(genesisBlockRootKey)
|
|
|
|
bkt = tx.Bucket(checkpointBucket)
|
|
enc := bkt.Get(finalizedCheckpointKey)
|
|
checkpoint := ðpb.Checkpoint{}
|
|
if enc == nil {
|
|
checkpoint = ðpb.Checkpoint{Root: genesisBlockRoot}
|
|
} else if err := decode(enc, checkpoint); err != nil {
|
|
return err
|
|
}
|
|
|
|
bkt = tx.Bucket(blocksBucket)
|
|
headBlkRoot := bkt.Get(headBlockRootKey)
|
|
|
|
for _, blockRoot := range blockRoots {
|
|
// Safe guard against deleting genesis, finalized, or head state.
|
|
if bytes.Equal(blockRoot[:], checkpoint.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], headBlkRoot) {
|
|
return errors.New("could not delete genesis, finalized, or head state")
|
|
}
|
|
|
|
bkt = tx.Bucket(stateBucket)
|
|
if err := bkt.Delete(blockRoot[:]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// creates state from marshaled proto state bytes.
|
|
func createState(enc []byte) (*pb.BeaconState, error) {
|
|
protoState := &pb.BeaconState{}
|
|
err := decode(enc, protoState)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to unmarshal encoding")
|
|
}
|
|
return protoState, nil
|
|
}
|