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 }