Save genesis state in DB (#3359)

* Done

* Test

* Fixed test

* emit state initialized
This commit is contained in:
terence tsao
2019-08-29 15:32:35 -07:00
committed by Preston Van Loon
parent 1f0aad31d2
commit f0332e1131
9 changed files with 100 additions and 1 deletions

View File

@@ -99,6 +99,14 @@ func (c *ChainService) Start() {
if beaconState != nil {
log.Info("Beacon chain data already exists, starting service")
c.genesisTime = time.Unix(int64(beaconState.GenesisTime), 0)
genesisState, err := c.beaconDB.GenesisState(c.ctx)
if err != nil {
log.Fatalf("Could not retrieve genesis state from db: %v", err)
}
if err := c.forkChoiceStore.GenesisStore(c.ctx, genesisState); err != nil {
log.Fatalf("Could not start fork choice service: %v", err)
}
c.stateInitializedFeed.Send(c.genesisTime)
} else {
log.Info("Waiting for ChainStart log from the Validator Deposit Contract to start the beacon chain...")
if c.web3Service == nil {
@@ -158,10 +166,13 @@ func (c *ChainService) initializeBeaconChain(
return errors.Wrap(err, "could not start genesis store for fork choice")
}
if err := c.beaconDB.SaveGenesisBlockRoot(ctx, bytesutil.ToBytes32(c.FinalizedCheckpt().Root)); err != nil {
return errors.Wrap(err, "could save genesis block root")
}
c.headBlock = genesisBlk
c.headState = genesisState
c.canonicalRoots[genesisState.Slot] = c.FinalizedCheckpt().Root
c.canonicalRoots[genesisState.Slot] = c.FinalizedCheckpt().Root
return nil
}

View File

@@ -281,6 +281,9 @@ func TestChainStartStop_Initialized(t *testing.T) {
if err := db.SaveHeadBlockRoot(ctx, blkRoot); err != nil {
t.Fatal(err)
}
if err := db.SaveGenesisBlockRoot(ctx, blkRoot); err != nil {
t.Fatal(err)
}
if err := db.SaveState(ctx, &pb.BeaconState{Slot: 1}, blkRoot); err != nil {
t.Fatal(err)
}

View File

@@ -154,6 +154,11 @@ func (db *BeaconDB) SaveHeadBlockRoot(_ context.Context, root [32]byte) error {
return errors.New("not implemented")
}
// SaveGenesisBlockRoot is not implemented.
func (db *BeaconDB) SaveGenesisBlockRoot(_ context.Context, root [32]byte) error {
return errors.New("not implemented")
}
// SaveBlocks in db.
func (db *BeaconDB) SaveBlocks(ctx context.Context, blocks []*ethpb.BeaconBlock) error {
for _, blk := range blocks {

View File

@@ -43,6 +43,7 @@ type Database interface {
SaveBlock(ctx context.Context, block *ethpb.BeaconBlock) error
SaveBlocks(ctx context.Context, blocks []*ethpb.BeaconBlock) error
SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error
SaveGenesisBlockRoot(ctx context.Context, blockRoot [32]byte) error
// Validator related methods.
ValidatorLatestVote(ctx context.Context, validatorIdx uint64) (*pb.ValidatorLatestVote, error)
HasValidatorLatestVote(ctx context.Context, validatorIdx uint64) bool
@@ -55,6 +56,7 @@ type Database interface {
// State related methods.
State(ctx context.Context, blockRoot [32]byte) (*pb.BeaconState, error)
HeadState(ctx context.Context) (*pb.BeaconState, error)
GenesisState(ctx context.Context) (*pb.BeaconState, error)
SaveState(ctx context.Context, state *pb.BeaconState, blockRoot [32]byte) error
// Slashing operations.
ProposerSlashing(ctx context.Context, slashingRoot [32]byte) (*ethpb.ProposerSlashing, error)

View File

@@ -259,6 +259,16 @@ func (k *Store) SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error
})
}
// SaveGenesisBlockRoot to the db.
func (k *Store) SaveGenesisBlockRoot(ctx context.Context, blockRoot [32]byte) error {
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveGenesisBlockRoot")
defer span.End()
return k.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(blocksBucket)
return bucket.Put(genesisBlockRootKey, blockRoot[:])
})
}
// fetchBlockRootsBySlotRange looks into a boltDB bucket and performs a binary search
// range scan using sorted left-padded byte keys using a start slot and an end slot.
// If both the start and end slot are the same, and are 0, the function returns nil.

View File

@@ -26,5 +26,6 @@ var (
// Specific item keys.
headBlockRootKey = []byte("head-root")
genesisBlockRootKey = []byte("genesis-root")
depositContractAddressKey = []byte("deposit-contract")
)

View File

@@ -54,6 +54,30 @@ func (k *Store) HeadState(ctx context.Context) (*pb.BeaconState, error) {
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")

View File

@@ -75,3 +75,41 @@ func TestHeadState_CanSaveRetrieve(t *testing.T) {
t.Error("unsaved head state should've been nil")
}
}
func TestGenesisState_CanSaveRetrieve(t *testing.T) {
db := setupDB(t)
defer teardownDB(t, db)
s := &pb.BeaconState{Slot: 1}
headRoot := [32]byte{'B'}
if err := db.SaveGenesisBlockRoot(context.Background(), headRoot); err != nil {
t.Fatal(err)
}
if err := db.SaveState(context.Background(), s, headRoot); err != nil {
t.Fatal(err)
}
savedGenesisS, err := db.GenesisState(context.Background())
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(s, savedGenesisS) {
t.Error("did not retrieve saved state")
}
if err := db.SaveGenesisBlockRoot(context.Background(), [32]byte{'C'}); err != nil {
t.Fatal(err)
}
savedGenesisS, err = db.HeadState(context.Background())
if err != nil {
t.Fatal(err)
}
if savedGenesisS != nil {
t.Error("unsaved genesis state should've been nil")
}
}

View File

@@ -150,6 +150,11 @@ func (db *BeaconDB) HeadState(ctx context.Context) (*pb.BeaconState, error) {
return beaconState, err
}
// GenesisState is not implemented.
func (db *BeaconDB) GenesisState(ctx context.Context) (*pb.BeaconState, error) {
return nil, errors.New("not implemented")
}
// HeadStateRoot returns the root of the current state from the db.
func (db *BeaconDB) HeadStateRoot() [32]byte {
return db.stateHash