Load ssz formatted genesis state (#3408)

* Preload ssz genesis state

* Log
This commit is contained in:
terence tsao
2019-09-04 15:32:38 -07:00
committed by Raul Jordan
parent 75c0b01932
commit c383b6a30c
5 changed files with 96 additions and 60 deletions

View File

@@ -7,6 +7,7 @@ import (
"context"
"encoding/hex"
"fmt"
"io/ioutil"
"runtime"
"sync"
"time"
@@ -55,6 +56,7 @@ type ChainService struct {
headState *pb.BeaconState
canonicalRoots map[uint64][]byte
canonicalRootsLock sync.RWMutex
preloadStatePath string
}
// Config options for the service.
@@ -66,6 +68,7 @@ type Config struct {
OpsPoolService operations.OperationFeeds
P2p p2p.Broadcaster
MaxRoutines int64
PreloadStatePath string
}
// NewChainService instantiates a new service instance that will
@@ -86,6 +89,7 @@ func NewChainService(ctx context.Context, cfg *Config) (*ChainService, error) {
p2p: cfg.P2p,
canonicalRoots: make(map[uint64][]byte),
maxRoutines: cfg.MaxRoutines,
preloadStatePath: cfg.PreloadStatePath,
}, nil
}
@@ -115,6 +119,21 @@ func (c *ChainService) Start() {
log.Fatalf("Could not start fork choice service: %v", err)
}
c.stateInitializedFeed.Send(c.genesisTime)
} else if c.preloadStatePath != "" {
log.Infof("Loading generated genesis state from %v", c.preloadStatePath)
s, err := ioutil.ReadFile(c.preloadStatePath)
if err != nil {
log.Fatalf("Could not read pre-loaded state: %v", err)
}
genesisState := &pb.BeaconState{}
if err := ssz.Unmarshal(s, genesisState); err != nil {
log.Fatalf("Could not unmarshal pre-loaded state: %v", err)
}
c.genesisTime = time.Unix(int64(genesisState.GenesisTime), 0)
if err := c.saveGenesisData(ctx, genesisState); err != nil {
log.Fatalf("Could not save genesis data: %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 {
@@ -159,6 +178,75 @@ func (c *ChainService) initializeBeaconChain(
if err != nil {
return errors.Wrap(err, "could not initialize genesis state")
}
if err := c.saveGenesisData(ctx, genesisState); err != nil {
return errors.Wrap(err, "could not save genesis data")
}
return nil
}
// Stop the blockchain service's main event loop and associated goroutines.
func (c *ChainService) Stop() error {
defer c.cancel()
log.Info("Stopping service")
return nil
}
// Status always returns nil.
// TODO(1202): Add service health checks.
func (c *ChainService) Status() error {
if runtime.NumGoroutine() > int(c.maxRoutines) {
return fmt.Errorf("too many goroutines %d", runtime.NumGoroutine())
}
return nil
}
// StateInitializedFeed returns a feed that is written to
// when the beacon state is first initialized.
func (c *ChainService) StateInitializedFeed() *event.Feed {
return c.stateInitializedFeed
}
// This gets called to update canonical root mapping.
func (c *ChainService) saveHead(ctx context.Context, b *ethpb.BeaconBlock, r [32]byte) error {
c.headSlot = b.Slot
c.canonicalRootsLock.Lock()
c.canonicalRoots[b.Slot] = r[:]
defer c.canonicalRootsLock.Unlock()
if err := c.beaconDB.SaveHeadBlockRoot(ctx, r); err != nil {
return errors.Wrap(err, "could not save head root in DB")
}
c.headBlock = b
s, err := c.beaconDB.State(ctx, r)
if err != nil {
return errors.Wrap(err, "could not retrieve head state in DB")
}
c.headState = s
log.WithFields(logrus.Fields{
"slots": b.Slot,
"root": hex.EncodeToString(r[:]),
}).Debug("Saved head info")
return nil
}
// This gets called when beacon chain is first initialized to save validator indices and pubkeys in db
func (c *ChainService) saveGenesisValidators(ctx context.Context, s *pb.BeaconState) error {
for i, v := range s.Validators {
if err := c.beaconDB.SaveValidatorIndex(ctx, bytesutil.ToBytes48(v.PublicKey), uint64(i)); err != nil {
return errors.Wrapf(err, "could not save validator index: %d", i)
}
}
return nil
}
// This gets called when beacon chain is first initialized to save genesis data (state, block, and more) in db
func (c *ChainService) saveGenesisData(ctx context.Context, genesisState *pb.BeaconState) error {
stateRoot, err := ssz.HashTreeRoot(genesisState)
if err != nil {
return errors.Wrap(err, "could not tree hash genesis state")
@@ -201,66 +289,6 @@ func (c *ChainService) initializeBeaconChain(
return nil
}
// Stop the blockchain service's main event loop and associated goroutines.
func (c *ChainService) Stop() error {
defer c.cancel()
log.Info("Stopping service")
return nil
}
// Status always returns nil.
// TODO(1202): Add service health checks.
func (c *ChainService) Status() error {
if runtime.NumGoroutine() > int(c.maxRoutines) {
return fmt.Errorf("too many goroutines %d", runtime.NumGoroutine())
}
return nil
}
// StateInitializedFeed returns a feed that is written to
// when the beacon state is first initialized.
func (c *ChainService) StateInitializedFeed() *event.Feed {
return c.stateInitializedFeed
}
// This gets called to update canonical root mapping.
func (c *ChainService) saveHead(ctx context.Context, b *ethpb.BeaconBlock, r [32]byte) error {
c.headSlot = b.Slot
c.canonicalRootsLock.Lock()
c.canonicalRoots[b.Slot] = r[:]
defer c.canonicalRootsLock.Unlock()
if err := c.beaconDB.SaveHeadBlockRoot(ctx, r); err != nil {
return errors.Wrap(err, "could not save head root in DB")
}
c.headBlock = b
s, err := c.beaconDB.State(ctx, r)
if err != nil {
return errors.Wrap(err, "could not retrieve head state in DB")
}
c.headState = s
log.WithFields(logrus.Fields{
"slots": b.Slot,
"root": hex.EncodeToString(r[:]),
}).Debug("Saved head info")
return nil
}
// This gets called when beacon chain is first initialized to save validator indices and pubkeys in db
func (c *ChainService) saveGenesisValidators(ctx context.Context, s *pb.BeaconState) error {
for i, v := range s.Validators {
if err := c.beaconDB.SaveValidatorIndex(ctx, bytesutil.ToBytes48(v.PublicKey), uint64(i)); err != nil {
return errors.Wrapf(err, "could not save validator index: %d", i)
}
}
return nil
}
// This gets called to initialize chain info variables using the head stored in DB
func (c *ChainService) initializeChainInfo(ctx context.Context) error {
headBlock, err := c.beaconDB.HeadBlock(ctx)

View File

@@ -53,4 +53,9 @@ var (
Name: "grpc-gateway-port",
Usage: "Enable gRPC gateway for JSON requests",
}
// GenesisState defines a flag for the beacon node to load genesis state via file.
GenesisState = cli.StringFlag{
Name: "load-genesis-state",
Usage: "The genesis state file (.SSZ) to load from",
}
)

View File

@@ -30,6 +30,7 @@ var appFlags = []cli.Flag{
flags.KeyFlag,
flags.EnableDBCleanup,
flags.GRPCGatewayPort,
flags.GenesisState,
cmd.BootstrapNode,
cmd.NoDiscovery,
cmd.StaticPeers,

View File

@@ -274,6 +274,7 @@ func (b *BeaconNode) registerBlockchainService(ctx *cli.Context) error {
OpsPoolService: opsService,
P2p: b.fetchP2P(ctx),
MaxRoutines: maxRoutines,
PreloadStatePath: ctx.GlobalString(flags.GenesisState.Name),
})
if err != nil {
return errors.Wrap(err, "could not register blockchain service")

View File

@@ -83,6 +83,7 @@ var appHelpFlagGroups = []flagGroup{
flags.EnableDBCleanup,
flags.GRPCGatewayPort,
flags.HTTPWeb3ProviderFlag,
flags.GenesisState,
},
},
{