github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/blockchain/head.go (about)

     1  package blockchain
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  
     8  	"github.com/pkg/errors"
     9  	types "github.com/prysmaticlabs/eth2-types"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
    11  	statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    13  	"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
    14  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    15  	ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
    16  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    17  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    18  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    19  	"github.com/prysmaticlabs/prysm/shared/params"
    20  	"github.com/prysmaticlabs/prysm/shared/slotutil"
    21  	"github.com/sirupsen/logrus"
    22  	"go.opencensus.io/trace"
    23  )
    24  
    25  // This defines the current chain service's view of head.
    26  type head struct {
    27  	slot  types.Slot                   // current head slot.
    28  	root  [32]byte                     // current head root.
    29  	block interfaces.SignedBeaconBlock // current head block.
    30  	state iface.BeaconState            // current head state.
    31  }
    32  
    33  // Determined the head from the fork choice service and saves its new data
    34  // (head root, head block, and head state) to the local service cache.
    35  func (s *Service) updateHead(ctx context.Context, balances []uint64) error {
    36  	ctx, span := trace.StartSpan(ctx, "blockChain.updateHead")
    37  	defer span.End()
    38  
    39  	// To get the proper head update, a node first checks its best justified
    40  	// can become justified. This is designed to prevent bounce attack and
    41  	// ensure head gets its best justified info.
    42  	if s.bestJustifiedCheckpt.Epoch > s.justifiedCheckpt.Epoch {
    43  		s.justifiedCheckpt = s.bestJustifiedCheckpt
    44  		if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
    45  			return err
    46  		}
    47  	}
    48  
    49  	// Get head from the fork choice service.
    50  	f := s.finalizedCheckpt
    51  	j := s.justifiedCheckpt
    52  	// To get head before the first justified epoch, the fork choice will start with genesis root
    53  	// instead of zero hashes.
    54  	headStartRoot := bytesutil.ToBytes32(j.Root)
    55  	if headStartRoot == params.BeaconConfig().ZeroHash {
    56  		headStartRoot = s.genesisRoot
    57  	}
    58  
    59  	// In order to process head, fork choice store requires justified info.
    60  	// If the fork choice store is missing justified block info, a node should
    61  	// re-initiate fork choice store using the latest justified info.
    62  	// This recovers a fatal condition and should not happen in run time.
    63  	if !s.cfg.ForkChoiceStore.HasNode(headStartRoot) {
    64  		jb, err := s.cfg.BeaconDB.Block(ctx, headStartRoot)
    65  		if err != nil {
    66  			return err
    67  		}
    68  		s.cfg.ForkChoiceStore = protoarray.New(j.Epoch, f.Epoch, bytesutil.ToBytes32(f.Root))
    69  		if err := s.insertBlockToForkChoiceStore(ctx, jb.Block(), headStartRoot, f, j); err != nil {
    70  			return err
    71  		}
    72  	}
    73  
    74  	headRoot, err := s.cfg.ForkChoiceStore.Head(ctx, j.Epoch, headStartRoot, balances, f.Epoch)
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	// Save head to the local service cache.
    80  	return s.saveHead(ctx, headRoot)
    81  }
    82  
    83  // This saves head info to the local service cache, it also saves the
    84  // new head root to the DB.
    85  func (s *Service) saveHead(ctx context.Context, headRoot [32]byte) error {
    86  	ctx, span := trace.StartSpan(ctx, "blockChain.saveHead")
    87  	defer span.End()
    88  
    89  	// Do nothing if head hasn't changed.
    90  	r, err := s.HeadRoot(ctx)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	if headRoot == bytesutil.ToBytes32(r) {
    95  		return nil
    96  	}
    97  
    98  	// If the head state is not available, just return nil.
    99  	// There's nothing to cache
   100  	if !s.cfg.BeaconDB.HasStateSummary(ctx, headRoot) {
   101  		return nil
   102  	}
   103  
   104  	// Get the new head block from DB.
   105  	newHeadBlock, err := s.cfg.BeaconDB.Block(ctx, headRoot)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	if newHeadBlock == nil || newHeadBlock.IsNil() || newHeadBlock.Block().IsNil() {
   110  		return errors.New("cannot save nil head block")
   111  	}
   112  
   113  	// Get the new head state from cached state or DB.
   114  	newHeadState, err := s.cfg.StateGen.StateByRoot(ctx, headRoot)
   115  	if err != nil {
   116  		return errors.Wrap(err, "could not retrieve head state in DB")
   117  	}
   118  	if newHeadState == nil || newHeadState.IsNil() {
   119  		return errors.New("cannot save nil head state")
   120  	}
   121  
   122  	// A chain re-org occurred, so we fire an event notifying the rest of the services.
   123  	headSlot := s.HeadSlot()
   124  	newHeadSlot := newHeadBlock.Block().Slot()
   125  	oldHeadRoot := s.headRoot()
   126  	oldStateRoot := s.headBlock().Block().StateRoot()
   127  	newStateRoot := newHeadBlock.Block().StateRoot()
   128  	if bytesutil.ToBytes32(newHeadBlock.Block().ParentRoot()) != bytesutil.ToBytes32(r) {
   129  		log.WithFields(logrus.Fields{
   130  			"newSlot": fmt.Sprintf("%d", newHeadSlot),
   131  			"oldSlot": fmt.Sprintf("%d", headSlot),
   132  		}).Debug("Chain reorg occurred")
   133  		absoluteSlotDifference := slotutil.AbsoluteValueSlotDifference(newHeadSlot, headSlot)
   134  		s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   135  			Type: statefeed.Reorg,
   136  			Data: &ethpbv1.EventChainReorg{
   137  				Slot:         newHeadSlot,
   138  				Depth:        absoluteSlotDifference,
   139  				OldHeadBlock: oldHeadRoot[:],
   140  				NewHeadBlock: headRoot[:],
   141  				OldHeadState: oldStateRoot,
   142  				NewHeadState: newStateRoot,
   143  				Epoch:        helpers.SlotToEpoch(newHeadSlot),
   144  			},
   145  		})
   146  
   147  		if err := s.saveOrphanedAtts(ctx, bytesutil.ToBytes32(r)); err != nil {
   148  			return err
   149  		}
   150  
   151  		reorgCount.Inc()
   152  	}
   153  
   154  	// Cache the new head info.
   155  	s.setHead(headRoot, newHeadBlock, newHeadState)
   156  
   157  	// Save the new head root to DB.
   158  	if err := s.cfg.BeaconDB.SaveHeadBlockRoot(ctx, headRoot); err != nil {
   159  		return errors.Wrap(err, "could not save head root in DB")
   160  	}
   161  
   162  	// Forward an event capturing a new chain head over a common event feed
   163  	// done in a goroutine to avoid blocking the critical runtime main routine.
   164  	go func() {
   165  		if err := s.notifyNewHeadEvent(newHeadSlot, newHeadState, newStateRoot, headRoot[:]); err != nil {
   166  			log.WithError(err).Error("Could not notify event feed of new chain head")
   167  		}
   168  	}()
   169  
   170  	return nil
   171  }
   172  
   173  // This gets called to update canonical root mapping. It does not save head block
   174  // root in DB. With the inception of initial-sync-cache-state flag, it uses finalized
   175  // check point as anchors to resume sync therefore head is no longer needed to be saved on per slot basis.
   176  func (s *Service) saveHeadNoDB(ctx context.Context, b interfaces.SignedBeaconBlock, r [32]byte, hs iface.BeaconState) error {
   177  	if err := helpers.VerifyNilBeaconBlock(b); err != nil {
   178  		return err
   179  	}
   180  	cachedHeadRoot, err := s.HeadRoot(ctx)
   181  	if err != nil {
   182  		return errors.Wrap(err, "could not get head root from cache")
   183  	}
   184  	if bytes.Equal(r[:], cachedHeadRoot) {
   185  		return nil
   186  	}
   187  
   188  	s.setHeadInitialSync(r, b.Copy(), hs)
   189  	return nil
   190  }
   191  
   192  // This sets head view object which is used to track the head slot, root, block and state.
   193  func (s *Service) setHead(root [32]byte, block interfaces.SignedBeaconBlock, state iface.BeaconState) {
   194  	s.headLock.Lock()
   195  	defer s.headLock.Unlock()
   196  
   197  	// This does a full copy of the block and state.
   198  	s.head = &head{
   199  		slot:  block.Block().Slot(),
   200  		root:  root,
   201  		block: block.Copy(),
   202  		state: state.Copy(),
   203  	}
   204  }
   205  
   206  // This sets head view object which is used to track the head slot, root, block and state. The method
   207  // assumes that state being passed into the method will not be modified by any other alternate
   208  // caller which holds the state's reference.
   209  func (s *Service) setHeadInitialSync(root [32]byte, block interfaces.SignedBeaconBlock, state iface.BeaconState) {
   210  	s.headLock.Lock()
   211  	defer s.headLock.Unlock()
   212  
   213  	// This does a full copy of the block only.
   214  	s.head = &head{
   215  		slot:  block.Block().Slot(),
   216  		root:  root,
   217  		block: block.Copy(),
   218  		state: state,
   219  	}
   220  }
   221  
   222  // This returns the head slot.
   223  // This is a lock free version.
   224  func (s *Service) headSlot() types.Slot {
   225  	return s.head.slot
   226  }
   227  
   228  // This returns the head root.
   229  // It does a full copy on head root for immutability.
   230  // This is a lock free version.
   231  func (s *Service) headRoot() [32]byte {
   232  	if s.head == nil {
   233  		return params.BeaconConfig().ZeroHash
   234  	}
   235  
   236  	return s.head.root
   237  }
   238  
   239  // This returns the head block.
   240  // It does a full copy on head block for immutability.
   241  // This is a lock free version.
   242  func (s *Service) headBlock() interfaces.SignedBeaconBlock {
   243  	return s.head.block.Copy()
   244  }
   245  
   246  // This returns the head state.
   247  // It does a full copy on head state for immutability.
   248  // This is a lock free version.
   249  func (s *Service) headState(ctx context.Context) iface.BeaconState {
   250  	ctx, span := trace.StartSpan(ctx, "blockChain.headState")
   251  	defer span.End()
   252  
   253  	return s.head.state.Copy()
   254  }
   255  
   256  // This returns the genesis validator root of the head state.
   257  // This is a lock free version.
   258  func (s *Service) headGenesisValidatorRoot() [32]byte {
   259  	return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot())
   260  }
   261  
   262  // Returns true if head state exists.
   263  // This is the lock free version.
   264  func (s *Service) hasHeadState() bool {
   265  	return s.head != nil && s.head.state != nil
   266  }
   267  
   268  // This caches justified state balances to be used for fork choice.
   269  func (s *Service) cacheJustifiedStateBalances(ctx context.Context, justifiedRoot [32]byte) error {
   270  	if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
   271  		return err
   272  	}
   273  
   274  	s.clearInitSyncBlocks()
   275  
   276  	var justifiedState iface.BeaconState
   277  	var err error
   278  	if justifiedRoot == s.genesisRoot {
   279  		justifiedState, err = s.cfg.BeaconDB.GenesisState(ctx)
   280  		if err != nil {
   281  			return err
   282  		}
   283  	} else {
   284  		justifiedState, err = s.cfg.StateGen.StateByRoot(ctx, justifiedRoot)
   285  		if err != nil {
   286  			return err
   287  		}
   288  	}
   289  	if justifiedState == nil || justifiedState.IsNil() {
   290  		return errors.New("justified state can't be nil")
   291  	}
   292  
   293  	epoch := helpers.CurrentEpoch(justifiedState)
   294  
   295  	justifiedBalances := make([]uint64, justifiedState.NumValidators())
   296  	if err := justifiedState.ReadFromEveryValidator(func(idx int, val iface.ReadOnlyValidator) error {
   297  		if helpers.IsActiveValidatorUsingTrie(val, epoch) {
   298  			justifiedBalances[idx] = val.EffectiveBalance()
   299  		} else {
   300  			justifiedBalances[idx] = 0
   301  		}
   302  		return nil
   303  	}); err != nil {
   304  		return err
   305  	}
   306  
   307  	s.justifiedBalancesLock.Lock()
   308  	defer s.justifiedBalancesLock.Unlock()
   309  	s.justifiedBalances = justifiedBalances
   310  	return nil
   311  }
   312  
   313  func (s *Service) getJustifiedBalances() []uint64 {
   314  	s.justifiedBalancesLock.RLock()
   315  	defer s.justifiedBalancesLock.RUnlock()
   316  	return s.justifiedBalances
   317  }
   318  
   319  // Notifies a common event feed of a new chain head event. Called right after a new
   320  // chain head is determined, set, and saved to disk.
   321  func (s *Service) notifyNewHeadEvent(
   322  	newHeadSlot types.Slot,
   323  	newHeadState iface.BeaconState,
   324  	newHeadStateRoot,
   325  	newHeadRoot []byte,
   326  ) error {
   327  	previousDutyDependentRoot := s.genesisRoot[:]
   328  	currentDutyDependentRoot := s.genesisRoot[:]
   329  
   330  	var previousDutyEpoch types.Epoch
   331  	currentDutyEpoch := helpers.SlotToEpoch(newHeadSlot)
   332  	if currentDutyEpoch > 0 {
   333  		previousDutyEpoch = currentDutyEpoch.Sub(1)
   334  	}
   335  	currentDutySlot, err := helpers.StartSlot(currentDutyEpoch)
   336  	if err != nil {
   337  		return errors.Wrap(err, "could not get duty slot")
   338  	}
   339  	previousDutySlot, err := helpers.StartSlot(previousDutyEpoch)
   340  	if err != nil {
   341  		return errors.Wrap(err, "could not get duty slot")
   342  	}
   343  	if currentDutySlot > 0 {
   344  		currentDutyDependentRoot, err = helpers.BlockRootAtSlot(newHeadState, currentDutySlot-1)
   345  		if err != nil {
   346  			return errors.Wrap(err, "could not get duty dependent root")
   347  		}
   348  	}
   349  	if previousDutySlot > 0 {
   350  		previousDutyDependentRoot, err = helpers.BlockRootAtSlot(newHeadState, previousDutySlot-1)
   351  		if err != nil {
   352  			return errors.Wrap(err, "could not get duty dependent root")
   353  		}
   354  	}
   355  	s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   356  		Type: statefeed.NewHead,
   357  		Data: &ethpbv1.EventHead{
   358  			Slot:                      newHeadSlot,
   359  			Block:                     newHeadRoot,
   360  			State:                     newHeadStateRoot,
   361  			EpochTransition:           helpers.IsEpochEnd(newHeadSlot),
   362  			PreviousDutyDependentRoot: previousDutyDependentRoot,
   363  			CurrentDutyDependentRoot:  currentDutyDependentRoot,
   364  		},
   365  	})
   366  	return nil
   367  }
   368  
   369  // This saves the attestations inside the beacon block with respect to root `orphanedRoot` back into the
   370  // attestation pool. It also filters out the attestations that is one epoch older as a
   371  // defense so invalid attestations don't flow into the attestation pool.
   372  func (s *Service) saveOrphanedAtts(ctx context.Context, orphanedRoot [32]byte) error {
   373  	if !featureconfig.Get().CorrectlyInsertOrphanedAtts {
   374  		return nil
   375  	}
   376  
   377  	orphanedBlk, err := s.cfg.BeaconDB.Block(ctx, orphanedRoot)
   378  	if err != nil {
   379  		return err
   380  	}
   381  
   382  	if orphanedBlk == nil || orphanedBlk.IsNil() {
   383  		return errors.New("orphaned block can't be nil")
   384  	}
   385  
   386  	for _, a := range orphanedBlk.Block().Body().Attestations() {
   387  		// Is the attestation one epoch older.
   388  		if a.Data.Slot+params.BeaconConfig().SlotsPerEpoch < s.CurrentSlot() {
   389  			continue
   390  		}
   391  		if helpers.IsAggregated(a) {
   392  			if err := s.cfg.AttPool.SaveAggregatedAttestation(a); err != nil {
   393  				return err
   394  			}
   395  		} else {
   396  			if err := s.cfg.AttPool.SaveUnaggregatedAttestation(a); err != nil {
   397  				return err
   398  			}
   399  		}
   400  		saveOrphanedAttCount.Inc()
   401  	}
   402  
   403  	return nil
   404  }