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

     1  package blockchain
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/pkg/errors"
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
     9  	statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    11  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    12  	"github.com/prysmaticlabs/prysm/shared/featureconfig"
    13  	"github.com/prysmaticlabs/prysm/shared/timeutils"
    14  	"github.com/prysmaticlabs/prysm/shared/traceutil"
    15  	"go.opencensus.io/trace"
    16  )
    17  
    18  // This defines how many epochs since finality the run time will begin to save hot state on to the DB.
    19  var epochsSinceFinalitySaveHotStateDB = types.Epoch(100)
    20  
    21  // BlockReceiver interface defines the methods of chain service receive and processing new blocks.
    22  type BlockReceiver interface {
    23  	ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, blockRoot [32]byte) error
    24  	ReceiveBlockBatch(ctx context.Context, blocks []interfaces.SignedBeaconBlock, blkRoots [][32]byte) error
    25  	HasInitSyncBlock(root [32]byte) bool
    26  }
    27  
    28  // ReceiveBlock is a function that defines the the operations (minus pubsub)
    29  // that are performed on blocks that is received from regular sync service. The operations consists of:
    30  //   1. Validate block, apply state transition and update check points
    31  //   2. Apply fork choice to the processed block
    32  //   3. Save latest head info
    33  func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, blockRoot [32]byte) error {
    34  	ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlock")
    35  	defer span.End()
    36  	receivedTime := timeutils.Now()
    37  	blockCopy := block.Copy()
    38  
    39  	// Apply state transition on the new block.
    40  	if err := s.onBlock(ctx, blockCopy, blockRoot); err != nil {
    41  		err := errors.Wrap(err, "could not process block")
    42  		traceutil.AnnotateError(span, err)
    43  		return err
    44  	}
    45  
    46  	// Update and save head block after fork choice.
    47  	if !featureconfig.Get().UpdateHeadTimely {
    48  		if err := s.updateHead(ctx, s.getJustifiedBalances()); err != nil {
    49  			log.WithError(err).Warn("Could not update head")
    50  		}
    51  
    52  		if err := s.pruneCanonicalAttsFromPool(ctx, blockRoot, block); err != nil {
    53  			return err
    54  		}
    55  
    56  		// Send notification of the processed block to the state feed.
    57  		s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
    58  			Type: statefeed.BlockProcessed,
    59  			Data: &statefeed.BlockProcessedData{
    60  				Slot:        blockCopy.Block().Slot(),
    61  				BlockRoot:   blockRoot,
    62  				SignedBlock: blockCopy,
    63  				Verified:    true,
    64  			},
    65  		})
    66  	}
    67  
    68  	// Handle post block operations such as attestations and exits.
    69  	if err := s.handlePostBlockOperations(blockCopy.Block()); err != nil {
    70  		return err
    71  	}
    72  
    73  	// Have we been finalizing? Should we start saving hot states to db?
    74  	if err := s.checkSaveHotStateDB(ctx); err != nil {
    75  		return err
    76  	}
    77  
    78  	// Reports on block and fork choice metrics.
    79  	reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
    80  
    81  	// Log block sync status.
    82  	if err := logBlockSyncStatus(blockCopy.Block(), blockRoot, s.finalizedCheckpt, receivedTime, uint64(s.genesisTime.Unix())); err != nil {
    83  		return err
    84  	}
    85  	// Log state transition data.
    86  	logStateTransitionData(blockCopy.Block())
    87  
    88  	return nil
    89  }
    90  
    91  // ReceiveBlockBatch processes the whole block batch at once, assuming the block batch is linear ,transitioning
    92  // the state, performing batch verification of all collected signatures and then performing the appropriate
    93  // actions for a block post-transition.
    94  func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.SignedBeaconBlock, blkRoots [][32]byte) error {
    95  	ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlockBatch")
    96  	defer span.End()
    97  
    98  	// Apply state transition on the incoming newly received blockCopy without verifying its BLS contents.
    99  	fCheckpoints, jCheckpoints, err := s.onBlockBatch(ctx, blocks, blkRoots)
   100  	if err != nil {
   101  		err := errors.Wrap(err, "could not process block in batch")
   102  		traceutil.AnnotateError(span, err)
   103  		return err
   104  	}
   105  
   106  	for i, b := range blocks {
   107  		blockCopy := b.Copy()
   108  		if err = s.handleBlockAfterBatchVerify(ctx, blockCopy, blkRoots[i], fCheckpoints[i], jCheckpoints[i]); err != nil {
   109  			traceutil.AnnotateError(span, err)
   110  			return err
   111  		}
   112  		// Send notification of the processed block to the state feed.
   113  		s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
   114  			Type: statefeed.BlockProcessed,
   115  			Data: &statefeed.BlockProcessedData{
   116  				Slot:        blockCopy.Block().Slot(),
   117  				BlockRoot:   blkRoots[i],
   118  				SignedBlock: blockCopy,
   119  				Verified:    true,
   120  			},
   121  		})
   122  
   123  		// Reports on blockCopy and fork choice metrics.
   124  		reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), s.finalizedCheckpt)
   125  	}
   126  
   127  	if err := s.VerifyWeakSubjectivityRoot(s.ctx); err != nil {
   128  		// log.Fatalf will prevent defer from being called
   129  		span.End()
   130  		// Exit run time if the node failed to verify weak subjectivity checkpoint.
   131  		log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
   132  	}
   133  
   134  	return nil
   135  }
   136  
   137  // HasInitSyncBlock returns true if the block of the input root exists in initial sync blocks cache.
   138  func (s *Service) HasInitSyncBlock(root [32]byte) bool {
   139  	return s.hasInitSyncBlock(root)
   140  }
   141  
   142  func (s *Service) handlePostBlockOperations(b interfaces.BeaconBlock) error {
   143  	// Delete the processed block attestations from attestation pool.
   144  	if err := s.deletePoolAtts(b.Body().Attestations()); err != nil {
   145  		return err
   146  	}
   147  
   148  	// Add block attestations to the fork choice pool to compute head.
   149  	if err := s.cfg.AttPool.SaveBlockAttestations(b.Body().Attestations()); err != nil {
   150  		log.Errorf("Could not save block attestations for fork choice: %v", err)
   151  		return nil
   152  	}
   153  	// Mark block exits as seen so we don't include same ones in future blocks.
   154  	for _, e := range b.Body().VoluntaryExits() {
   155  		s.cfg.ExitPool.MarkIncluded(e)
   156  	}
   157  
   158  	//  Mark attester slashings as seen so we don't include same ones in future blocks.
   159  	for _, as := range b.Body().AttesterSlashings() {
   160  		s.cfg.SlashingPool.MarkIncludedAttesterSlashing(as)
   161  	}
   162  	return nil
   163  }
   164  
   165  // This checks whether it's time to start saving hot state to DB.
   166  // It's time when there's `epochsSinceFinalitySaveHotStateDB` epochs of non-finality.
   167  func (s *Service) checkSaveHotStateDB(ctx context.Context) error {
   168  	currentEpoch := helpers.SlotToEpoch(s.CurrentSlot())
   169  	// Prevent `sinceFinality` going underflow.
   170  	var sinceFinality types.Epoch
   171  	if currentEpoch > s.finalizedCheckpt.Epoch {
   172  		sinceFinality = currentEpoch - s.finalizedCheckpt.Epoch
   173  	}
   174  
   175  	if sinceFinality >= epochsSinceFinalitySaveHotStateDB {
   176  		s.cfg.StateGen.EnableSaveHotStateToDB(ctx)
   177  		return nil
   178  	}
   179  
   180  	return s.cfg.StateGen.DisableSaveHotStateToDB(ctx)
   181  }