prysm-pulse/beacon-chain/blockchain/head.go
terence tsao 16a0c9f463
Don't save nil head state (#4799)
* Don't save nil head state
* Update head
2020-02-09 05:08:21 +00:00

86 lines
2.4 KiB
Go

package blockchain
import (
"context"
"github.com/gogo/protobuf/proto"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"go.opencensus.io/trace"
)
// This gets head from the fork choice service and saves head related items
// (ie root, block, state) to the local service cache.
func (s *Service) updateHead(ctx context.Context, balances []uint64) error {
ctx, span := trace.StartSpan(ctx, "blockchain.updateHead")
defer span.End()
// To get the proper head update, a node first checks its best justified
// can become justified. This is designed to prevent bounce attack and
// ensure head gets its best justified info.
if s.bestJustifiedCheckpt.Epoch > s.justifiedCheckpt.Epoch {
s.justifiedCheckpt = s.bestJustifiedCheckpt
}
// Get head from the fork choice service.
f := s.finalizedCheckpt
j := s.justifiedCheckpt
headRoot, err := s.forkChoiceStore.Head(ctx, j.Epoch, bytesutil.ToBytes32(j.Root), balances, f.Epoch)
if err != nil {
return err
}
// Save head to the local service cache.
return s.saveHead(ctx, headRoot)
}
// This saves head info to the local service cache, it also saves the
// new head root to the DB.
func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
ctx, span := trace.StartSpan(ctx, "blockchain.saveHead")
defer span.End()
cachedHeadRoot, err := s.HeadRoot(ctx)
if err != nil {
return err
}
// Do nothing if head hasn't changed.
if headRoot == bytesutil.ToBytes32(cachedHeadRoot) {
return nil
}
// Get the new head block from DB.
newHead, err := s.beaconDB.Block(ctx, headRoot)
if err != nil {
return err
}
if newHead == nil || newHead.Block == nil {
return errors.New("cannot save nil head block")
}
// Get the new head state from DB.
headState, err := s.beaconDB.State(ctx, headRoot)
if err != nil {
return errors.Wrap(err, "could not retrieve head state in DB")
}
if headState == nil {
return errors.New("cannot save nil head state")
}
s.headLock.Lock()
defer s.headLock.Unlock()
// Cache the new head info.
s.headSlot = newHead.Block.Slot
s.canonicalRoots[newHead.Block.Slot] = headRoot[:]
s.headBlock = proto.Clone(newHead).(*ethpb.SignedBeaconBlock)
s.headState = headState
// Save the new head root to DB.
if err := s.beaconDB.SaveHeadBlockRoot(ctx, headRoot); err != nil {
return errors.Wrap(err, "could not save head root in DB")
}
return nil
}