github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/blockchain/process_block_helpers.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/helpers"
    11  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    12  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    13  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    14  	"github.com/prysmaticlabs/prysm/shared/attestationutil"
    15  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    16  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    17  	"github.com/prysmaticlabs/prysm/shared/params"
    18  	"github.com/prysmaticlabs/prysm/shared/traceutil"
    19  	"go.opencensus.io/trace"
    20  )
    21  
    22  // CurrentSlot returns the current slot based on time.
    23  func (s *Service) CurrentSlot() types.Slot {
    24  	return helpers.CurrentSlot(uint64(s.genesisTime.Unix()))
    25  }
    26  
    27  // getBlockPreState returns the pre state of an incoming block. It uses the parent root of the block
    28  // to retrieve the state in DB. It verifies the pre state's validity and the incoming block
    29  // is in the correct time window.
    30  func (s *Service) getBlockPreState(ctx context.Context, b interfaces.BeaconBlock) (iface.BeaconState, error) {
    31  	ctx, span := trace.StartSpan(ctx, "blockChain.getBlockPreState")
    32  	defer span.End()
    33  
    34  	// Verify incoming block has a valid pre state.
    35  	if err := s.verifyBlkPreState(ctx, b); err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	preState, err := s.cfg.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(b.ParentRoot()))
    40  	if err != nil {
    41  		return nil, errors.Wrapf(err, "could not get pre state for slot %d", b.Slot())
    42  	}
    43  	if preState == nil || preState.IsNil() {
    44  		return nil, errors.Wrapf(err, "nil pre state for slot %d", b.Slot())
    45  	}
    46  
    47  	// Verify block slot time is not from the future.
    48  	if err := helpers.VerifySlotTime(preState.GenesisTime(), b.Slot(), params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	// Verify block is later than the finalized epoch slot.
    53  	if err := s.verifyBlkFinalizedSlot(b); err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	return preState, nil
    58  }
    59  
    60  // verifyBlkPreState validates input block has a valid pre-state.
    61  func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.BeaconBlock) error {
    62  	ctx, span := trace.StartSpan(ctx, "blockChain.verifyBlkPreState")
    63  	defer span.End()
    64  
    65  	parentRoot := bytesutil.ToBytes32(b.ParentRoot())
    66  	// Loosen the check to HasBlock because state summary gets saved in batches
    67  	// during initial syncing. There's no risk given a state summary object is just a
    68  	// a subset of the block object.
    69  	if !s.cfg.BeaconDB.HasStateSummary(ctx, parentRoot) && !s.cfg.BeaconDB.HasBlock(ctx, parentRoot) {
    70  		return errors.New("could not reconstruct parent state")
    71  	}
    72  
    73  	if err := s.VerifyBlkDescendant(ctx, bytesutil.ToBytes32(b.ParentRoot())); err != nil {
    74  		return err
    75  	}
    76  
    77  	has, err := s.cfg.StateGen.HasState(ctx, parentRoot)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	if !has {
    82  		if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
    83  			return errors.Wrap(err, "could not save initial sync blocks")
    84  		}
    85  		s.clearInitSyncBlocks()
    86  	}
    87  	return nil
    88  }
    89  
    90  // VerifyBlkDescendant validates input block root is a descendant of the
    91  // current finalized block root.
    92  func (s *Service) VerifyBlkDescendant(ctx context.Context, root [32]byte) error {
    93  	ctx, span := trace.StartSpan(ctx, "blockChain.VerifyBlkDescendant")
    94  	defer span.End()
    95  	fRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.finalizedCheckpt.Root))
    96  	finalizedBlkSigned, err := s.cfg.BeaconDB.Block(ctx, fRoot)
    97  	if err != nil {
    98  		return err
    99  	}
   100  	if finalizedBlkSigned == nil || finalizedBlkSigned.IsNil() || finalizedBlkSigned.Block().IsNil() {
   101  		return errors.New("nil finalized block")
   102  	}
   103  	finalizedBlk := finalizedBlkSigned.Block()
   104  	bFinalizedRoot, err := s.ancestor(ctx, root[:], finalizedBlk.Slot())
   105  	if err != nil {
   106  		return errors.Wrap(err, "could not get finalized block root")
   107  	}
   108  	if bFinalizedRoot == nil {
   109  		return fmt.Errorf("no finalized block known for block %#x", bytesutil.Trunc(root[:]))
   110  	}
   111  
   112  	if !bytes.Equal(bFinalizedRoot, fRoot[:]) {
   113  		err := fmt.Errorf("block %#x is not a descendent of the current finalized block slot %d, %#x != %#x",
   114  			bytesutil.Trunc(root[:]), finalizedBlk.Slot(), bytesutil.Trunc(bFinalizedRoot),
   115  			bytesutil.Trunc(fRoot[:]))
   116  		traceutil.AnnotateError(span, err)
   117  		return err
   118  	}
   119  	return nil
   120  }
   121  
   122  // verifyBlkFinalizedSlot validates input block is not less than or equal
   123  // to current finalized slot.
   124  func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error {
   125  	finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
   126  	if err != nil {
   127  		return err
   128  	}
   129  	if finalizedSlot >= b.Slot() {
   130  		return fmt.Errorf("block is equal or earlier than finalized block, slot %d < slot %d", b.Slot(), finalizedSlot)
   131  	}
   132  	return nil
   133  }
   134  
   135  // shouldUpdateCurrentJustified prevents bouncing attack, by only update conflicting justified
   136  // checkpoints in the fork choice if in the early slots of the epoch.
   137  // Otherwise, delay incorporation of new justified checkpoint until next epoch boundary.
   138  // See https://ethresear.ch/t/prevention-of-bouncing-attack-on-ffg/6114 for more detailed analysis and discussion.
   139  func (s *Service) shouldUpdateCurrentJustified(ctx context.Context, newJustifiedCheckpt *ethpb.Checkpoint) (bool, error) {
   140  	if helpers.SlotsSinceEpochStarts(s.CurrentSlot()) < params.BeaconConfig().SafeSlotsToUpdateJustified {
   141  		return true, nil
   142  	}
   143  	var newJustifiedBlockSigned interfaces.SignedBeaconBlock
   144  	justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(newJustifiedCheckpt.Root))
   145  	var err error
   146  	if s.hasInitSyncBlock(justifiedRoot) {
   147  		newJustifiedBlockSigned = s.getInitSyncBlock(justifiedRoot)
   148  	} else {
   149  		newJustifiedBlockSigned, err = s.cfg.BeaconDB.Block(ctx, justifiedRoot)
   150  		if err != nil {
   151  			return false, err
   152  		}
   153  	}
   154  	if newJustifiedBlockSigned == nil || newJustifiedBlockSigned.IsNil() || newJustifiedBlockSigned.Block().IsNil() {
   155  		return false, errors.New("nil new justified block")
   156  	}
   157  
   158  	newJustifiedBlock := newJustifiedBlockSigned.Block()
   159  	jSlot, err := helpers.StartSlot(s.justifiedCheckpt.Epoch)
   160  	if err != nil {
   161  		return false, err
   162  	}
   163  	if newJustifiedBlock.Slot() <= jSlot {
   164  		return false, nil
   165  	}
   166  	var justifiedBlockSigned interfaces.SignedBeaconBlock
   167  	cachedJustifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
   168  	if s.hasInitSyncBlock(cachedJustifiedRoot) {
   169  		justifiedBlockSigned = s.getInitSyncBlock(cachedJustifiedRoot)
   170  	} else {
   171  		justifiedBlockSigned, err = s.cfg.BeaconDB.Block(ctx, cachedJustifiedRoot)
   172  		if err != nil {
   173  			return false, err
   174  		}
   175  	}
   176  
   177  	if justifiedBlockSigned == nil || justifiedBlockSigned.IsNil() || justifiedBlockSigned.Block().IsNil() {
   178  		return false, errors.New("nil justified block")
   179  	}
   180  	justifiedBlock := justifiedBlockSigned.Block()
   181  	b, err := s.ancestor(ctx, justifiedRoot[:], justifiedBlock.Slot())
   182  	if err != nil {
   183  		return false, err
   184  	}
   185  	if !bytes.Equal(b, s.justifiedCheckpt.Root) {
   186  		return false, nil
   187  	}
   188  	return true, nil
   189  }
   190  
   191  func (s *Service) updateJustified(ctx context.Context, state iface.ReadOnlyBeaconState) error {
   192  	cpt := state.CurrentJustifiedCheckpoint()
   193  	if cpt.Epoch > s.bestJustifiedCheckpt.Epoch {
   194  		s.bestJustifiedCheckpt = cpt
   195  	}
   196  	canUpdate, err := s.shouldUpdateCurrentJustified(ctx, cpt)
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	if canUpdate {
   202  		s.prevJustifiedCheckpt = s.justifiedCheckpt
   203  		s.justifiedCheckpt = cpt
   204  		if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
   205  			return err
   206  		}
   207  	}
   208  
   209  	return s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, cpt)
   210  }
   211  
   212  // This caches input checkpoint as justified for the service struct. It rotates current justified to previous justified,
   213  // caches justified checkpoint balances for fork choice and save justified checkpoint in DB.
   214  // This method does not have defense against fork choice bouncing attack, which is why it's only recommend to be used during initial syncing.
   215  func (s *Service) updateJustifiedInitSync(ctx context.Context, cp *ethpb.Checkpoint) error {
   216  	s.prevJustifiedCheckpt = s.justifiedCheckpt
   217  	s.justifiedCheckpt = cp
   218  	if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
   219  		return err
   220  	}
   221  
   222  	return s.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, cp)
   223  }
   224  
   225  func (s *Service) updateFinalized(ctx context.Context, cp *ethpb.Checkpoint) error {
   226  	// Blocks need to be saved so that we can retrieve finalized block from
   227  	// DB when migrating states.
   228  	if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
   229  		return err
   230  	}
   231  	s.clearInitSyncBlocks()
   232  
   233  	if err := s.cfg.BeaconDB.SaveFinalizedCheckpoint(ctx, cp); err != nil {
   234  		return err
   235  	}
   236  	if !featureconfig.Get().UpdateHeadTimely {
   237  		s.prevFinalizedCheckpt = s.finalizedCheckpt
   238  		s.finalizedCheckpt = cp
   239  	}
   240  
   241  	fRoot := bytesutil.ToBytes32(cp.Root)
   242  	if err := s.cfg.StateGen.MigrateToCold(ctx, fRoot); err != nil {
   243  		return errors.Wrap(err, "could not migrate to cold")
   244  	}
   245  
   246  	return nil
   247  }
   248  
   249  // ancestor returns the block root of an ancestry block from the input block root.
   250  //
   251  // Spec pseudocode definition:
   252  //   def get_ancestor(store: Store, root: Root, slot: Slot) -> Root:
   253  //    block = store.blocks[root]
   254  //    if block.slot > slot:
   255  //        return get_ancestor(store, block.parent_root, slot)
   256  //    elif block.slot == slot:
   257  //        return root
   258  //    else:
   259  //        # root is older than queried slot, thus a skip slot. Return most recent root prior to slot
   260  //        return root
   261  func (s *Service) ancestor(ctx context.Context, root []byte, slot types.Slot) ([]byte, error) {
   262  	ctx, span := trace.StartSpan(ctx, "blockChain.ancestor")
   263  	defer span.End()
   264  
   265  	r := bytesutil.ToBytes32(root)
   266  	// Get ancestor root from fork choice store instead of recursively looking up blocks in DB.
   267  	// This is most optimal outcome.
   268  	ar, err := s.ancestorByForkChoiceStore(ctx, r, slot)
   269  	if err != nil {
   270  		// Try getting ancestor root from DB when failed to retrieve from fork choice store.
   271  		// This is the second line of defense for retrieving ancestor root.
   272  		ar, err = s.ancestorByDB(ctx, r, slot)
   273  		if err != nil {
   274  			return nil, err
   275  		}
   276  	}
   277  
   278  	return ar, nil
   279  }
   280  
   281  // This retrieves an ancestor root using fork choice store. The look up is looping through the a flat array structure.
   282  func (s *Service) ancestorByForkChoiceStore(ctx context.Context, r [32]byte, slot types.Slot) ([]byte, error) {
   283  	ctx, span := trace.StartSpan(ctx, "blockChain.ancestorByForkChoiceStore")
   284  	defer span.End()
   285  
   286  	if !s.cfg.ForkChoiceStore.HasParent(r) {
   287  		return nil, errors.New("could not find root in fork choice store")
   288  	}
   289  	return s.cfg.ForkChoiceStore.AncestorRoot(ctx, r, slot)
   290  }
   291  
   292  // This retrieves an ancestor root using DB. The look up is recursively looking up DB. Slower than `ancestorByForkChoiceStore`.
   293  func (s *Service) ancestorByDB(ctx context.Context, r [32]byte, slot types.Slot) ([]byte, error) {
   294  	ctx, span := trace.StartSpan(ctx, "blockChain.ancestorByDB")
   295  	defer span.End()
   296  
   297  	// Stop recursive ancestry lookup if context is cancelled.
   298  	if ctx.Err() != nil {
   299  		return nil, ctx.Err()
   300  	}
   301  
   302  	signed, err := s.cfg.BeaconDB.Block(ctx, r)
   303  	if err != nil {
   304  		return nil, errors.Wrap(err, "could not get ancestor block")
   305  	}
   306  
   307  	if s.hasInitSyncBlock(r) {
   308  		signed = s.getInitSyncBlock(r)
   309  	}
   310  
   311  	if signed == nil || signed.IsNil() || signed.Block().IsNil() {
   312  		return nil, errors.New("nil block")
   313  	}
   314  	b := signed.Block()
   315  	if b.Slot() == slot || b.Slot() < slot {
   316  		return r[:], nil
   317  	}
   318  
   319  	return s.ancestorByDB(ctx, bytesutil.ToBytes32(b.ParentRoot()), slot)
   320  }
   321  
   322  // This updates justified check point in store, if the new justified is later than stored justified or
   323  // the store's justified is not in chain with finalized check point.
   324  //
   325  // Spec definition:
   326  //   # Potentially update justified if different from store
   327  //        if store.justified_checkpoint != state.current_justified_checkpoint:
   328  //            # Update justified if new justified is later than store justified
   329  //            if state.current_justified_checkpoint.epoch > store.justified_checkpoint.epoch:
   330  //                store.justified_checkpoint = state.current_justified_checkpoint
   331  //                return
   332  //            # Update justified if store justified is not in chain with finalized checkpoint
   333  //            finalized_slot = compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)
   334  //            ancestor_at_finalized_slot = get_ancestor(store, store.justified_checkpoint.root, finalized_slot)
   335  //            if ancestor_at_finalized_slot != store.finalized_checkpoint.root:
   336  //                store.justified_checkpoint = state.current_justified_checkpoint
   337  func (s *Service) finalizedImpliesNewJustified(ctx context.Context, state iface.BeaconState) error {
   338  	// Update justified if it's different than the one cached in the store.
   339  	if !attestationutil.CheckPointIsEqual(s.justifiedCheckpt, state.CurrentJustifiedCheckpoint()) {
   340  		if state.CurrentJustifiedCheckpoint().Epoch > s.justifiedCheckpt.Epoch {
   341  			s.justifiedCheckpt = state.CurrentJustifiedCheckpoint()
   342  			return s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root))
   343  		}
   344  
   345  		// Update justified if store justified is not in chain with finalized check point.
   346  		finalizedSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
   347  		if err != nil {
   348  			return err
   349  		}
   350  		justifiedRoot := s.ensureRootNotZeros(bytesutil.ToBytes32(s.justifiedCheckpt.Root))
   351  		anc, err := s.ancestor(ctx, justifiedRoot[:], finalizedSlot)
   352  		if err != nil {
   353  			return err
   354  		}
   355  		if !bytes.Equal(anc, s.finalizedCheckpt.Root) {
   356  			s.justifiedCheckpt = state.CurrentJustifiedCheckpoint()
   357  			if err := s.cacheJustifiedStateBalances(ctx, bytesutil.ToBytes32(s.justifiedCheckpt.Root)); err != nil {
   358  				return err
   359  			}
   360  		}
   361  	}
   362  	return nil
   363  }
   364  
   365  // This retrieves missing blocks from DB (ie. the blocks that couldn't be received over sync) and inserts them to fork choice store.
   366  // This is useful for block tree visualizer and additional vote accounting.
   367  func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfaces.BeaconBlock,
   368  	fCheckpoint, jCheckpoint *ethpb.Checkpoint) error {
   369  	pendingNodes := make([]interfaces.BeaconBlock, 0)
   370  	pendingRoots := make([][32]byte, 0)
   371  
   372  	parentRoot := bytesutil.ToBytes32(blk.ParentRoot())
   373  	slot := blk.Slot()
   374  	// Fork choice only matters from last finalized slot.
   375  	fSlot, err := helpers.StartSlot(s.finalizedCheckpt.Epoch)
   376  	if err != nil {
   377  		return err
   378  	}
   379  	higherThanFinalized := slot > fSlot
   380  	// As long as parent node is not in fork choice store, and parent node is in DB.
   381  	for !s.cfg.ForkChoiceStore.HasNode(parentRoot) && s.cfg.BeaconDB.HasBlock(ctx, parentRoot) && higherThanFinalized {
   382  		b, err := s.cfg.BeaconDB.Block(ctx, parentRoot)
   383  		if err != nil {
   384  			return err
   385  		}
   386  
   387  		pendingNodes = append(pendingNodes, b.Block())
   388  		copiedRoot := parentRoot
   389  		pendingRoots = append(pendingRoots, copiedRoot)
   390  		parentRoot = bytesutil.ToBytes32(b.Block().ParentRoot())
   391  		slot = b.Block().Slot()
   392  		higherThanFinalized = slot > fSlot
   393  	}
   394  
   395  	// Insert parent nodes to fork choice store in reverse order.
   396  	// Lower slots should be at the end of the list.
   397  	for i := len(pendingNodes) - 1; i >= 0; i-- {
   398  		b := pendingNodes[i]
   399  		r := pendingRoots[i]
   400  		if err := s.cfg.ForkChoiceStore.ProcessBlock(ctx,
   401  			b.Slot(), r, bytesutil.ToBytes32(b.ParentRoot()), bytesutil.ToBytes32(b.Body().Graffiti()),
   402  			jCheckpoint.Epoch,
   403  			fCheckpoint.Epoch); err != nil {
   404  			return errors.Wrap(err, "could not process block for proto array fork choice")
   405  		}
   406  	}
   407  
   408  	return nil
   409  }
   410  
   411  // inserts finalized deposits into our finalized deposit trie.
   412  func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) error {
   413  	ctx, span := trace.StartSpan(ctx, "blockChain.insertFinalizedDeposits")
   414  	defer span.End()
   415  
   416  	// Update deposit cache.
   417  	finalizedState, err := s.cfg.StateGen.StateByRoot(ctx, fRoot)
   418  	if err != nil {
   419  		return errors.Wrap(err, "could not fetch finalized state")
   420  	}
   421  	// We update the cache up to the last deposit index in the finalized block's state.
   422  	// We can be confident that these deposits will be included in some block
   423  	// because the Eth1 follow distance makes such long-range reorgs extremely unlikely.
   424  	eth1DepositIndex := int64(finalizedState.Eth1Data().DepositCount - 1)
   425  	s.cfg.DepositCache.InsertFinalizedDeposits(ctx, eth1DepositIndex)
   426  	// Deposit proofs are only used during state transition and can be safely removed to save space.
   427  	if err = s.cfg.DepositCache.PruneProofs(ctx, eth1DepositIndex); err != nil {
   428  		return errors.Wrap(err, "could not prune deposit proofs")
   429  	}
   430  	return nil
   431  }
   432  
   433  // The deletes input attestations from the attestation pool, so proposers don't include them in a block for the future.
   434  func (s *Service) deletePoolAtts(atts []*ethpb.Attestation) error {
   435  	for _, att := range atts {
   436  		if helpers.IsAggregated(att) {
   437  			if err := s.cfg.AttPool.DeleteAggregatedAttestation(att); err != nil {
   438  				return err
   439  			}
   440  		} else {
   441  			if err := s.cfg.AttPool.DeleteUnaggregatedAttestation(att); err != nil {
   442  				return err
   443  			}
   444  		}
   445  	}
   446  
   447  	return nil
   448  }
   449  
   450  // This ensures that the input root defaults to using genesis root instead of zero hashes. This is needed for handling
   451  // fork choice justification routine.
   452  func (s *Service) ensureRootNotZeros(root [32]byte) [32]byte {
   453  	if root == params.BeaconConfig().ZeroHash {
   454  		return s.genesisRoot
   455  	}
   456  	return root
   457  }