2019-03-13 21:17:32 +00:00
|
|
|
package blockchain
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2019-08-02 02:27:38 +00:00
|
|
|
"github.com/pkg/errors"
|
2019-12-07 17:57:26 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
|
|
|
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
2022-05-02 18:32:37 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
2022-04-29 14:32:11 +00:00
|
|
|
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
2021-09-14 20:59:51 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/monitoring/tracing"
|
2022-05-07 15:56:34 +00:00
|
|
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
2021-09-15 00:09:04 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/time"
|
2021-10-01 20:17:57 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/time/slots"
|
2019-03-13 21:17:32 +00:00
|
|
|
"go.opencensus.io/trace"
|
|
|
|
)
|
|
|
|
|
2020-10-23 00:35:30 +00:00
|
|
|
// This defines how many epochs since finality the run time will begin to save hot state on to the DB.
|
2021-02-09 10:05:22 +00:00
|
|
|
var epochsSinceFinalitySaveHotStateDB = types.Epoch(100)
|
2020-10-23 00:35:30 +00:00
|
|
|
|
2022-04-28 11:34:25 +00:00
|
|
|
// BlockReceiver interface defines the methods of chain service for receiving and processing new blocks.
|
2019-08-23 17:48:40 +00:00
|
|
|
type BlockReceiver interface {
|
2022-05-02 18:32:37 +00:00
|
|
|
ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, blockRoot [32]byte) error
|
|
|
|
ReceiveBlockBatch(ctx context.Context, blocks []interfaces.SignedBeaconBlock, blkRoots [][32]byte) error
|
2022-05-04 00:17:40 +00:00
|
|
|
HasBlock(ctx context.Context, root [32]byte) bool
|
2019-08-23 17:48:40 +00:00
|
|
|
}
|
|
|
|
|
2022-05-07 15:56:34 +00:00
|
|
|
// SlashingReceiver interface defines the methods of chain service for receiving validated slashing over the wire.
|
|
|
|
type SlashingReceiver interface {
|
|
|
|
ReceiveAttesterSlashing(ctx context.Context, slashings *ethpb.AttesterSlashing)
|
|
|
|
}
|
|
|
|
|
2022-05-10 19:13:28 +00:00
|
|
|
// ReceiveBlock is a function that defines the operations (minus pubsub)
|
|
|
|
// that are performed on a received block. The operations consist of:
|
|
|
|
// 1. Validate block, apply state transition and update checkpoints
|
2019-08-21 17:40:00 +00:00
|
|
|
// 2. Apply fork choice to the processed block
|
|
|
|
// 3. Save latest head info
|
2022-05-02 18:32:37 +00:00
|
|
|
func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.SignedBeaconBlock, blockRoot [32]byte) error {
|
2020-07-09 23:50:48 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlock")
|
2019-08-21 17:40:00 +00:00
|
|
|
defer span.End()
|
2021-09-15 00:09:04 +00:00
|
|
|
receivedTime := time.Now()
|
2021-05-26 16:19:54 +00:00
|
|
|
blockCopy := block.Copy()
|
2019-08-21 17:40:00 +00:00
|
|
|
|
|
|
|
// Apply state transition on the new block.
|
2020-07-09 23:50:48 +00:00
|
|
|
if err := s.onBlock(ctx, blockCopy, blockRoot); err != nil {
|
2020-02-06 19:03:26 +00:00
|
|
|
err := errors.Wrap(err, "could not process block")
|
2021-09-14 20:59:51 +00:00
|
|
|
tracing.AnnotateError(span, err)
|
2020-02-06 19:03:26 +00:00
|
|
|
return err
|
2019-08-21 17:40:00 +00:00
|
|
|
}
|
2020-01-25 20:22:25 +00:00
|
|
|
|
2020-07-09 23:50:48 +00:00
|
|
|
// Handle post block operations such as attestations and exits.
|
2021-05-26 16:19:54 +00:00
|
|
|
if err := s.handlePostBlockOperations(blockCopy.Block()); err != nil {
|
2020-07-09 23:50:48 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-10-23 00:35:30 +00:00
|
|
|
// Have we been finalizing? Should we start saving hot states to db?
|
|
|
|
if err := s.checkSaveHotStateDB(ctx); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-02-05 17:24:05 +00:00
|
|
|
// Reports on block and fork choice metrics.
|
2022-01-25 18:47:39 +00:00
|
|
|
finalized := s.store.FinalizedCheckpt()
|
|
|
|
if finalized == nil {
|
|
|
|
return errNilFinalizedInStore
|
|
|
|
}
|
|
|
|
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
|
2020-02-05 17:24:05 +00:00
|
|
|
|
2020-04-29 16:57:04 +00:00
|
|
|
// Log block sync status.
|
2022-01-25 18:47:39 +00:00
|
|
|
if err := logBlockSyncStatus(blockCopy.Block(), blockRoot, finalized, receivedTime, uint64(s.genesisTime.Unix())); err != nil {
|
2021-02-10 17:24:40 +00:00
|
|
|
return err
|
|
|
|
}
|
2020-02-05 17:24:05 +00:00
|
|
|
// Log state transition data.
|
2022-03-15 14:02:39 +00:00
|
|
|
if err := logStateTransitionData(blockCopy.Block()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-02-05 17:24:05 +00:00
|
|
|
|
2019-08-21 17:40:00 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-07-07 04:16:12 +00:00
|
|
|
// ReceiveBlockBatch processes the whole block batch at once, assuming the block batch is linear ,transitioning
|
|
|
|
// the state, performing batch verification of all collected signatures and then performing the appropriate
|
|
|
|
// actions for a block post-transition.
|
2022-05-02 18:32:37 +00:00
|
|
|
func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []interfaces.SignedBeaconBlock, blkRoots [][32]byte) error {
|
2020-07-09 23:50:48 +00:00
|
|
|
ctx, span := trace.StartSpan(ctx, "blockChain.ReceiveBlockBatch")
|
2020-07-07 04:16:12 +00:00
|
|
|
defer span.End()
|
|
|
|
|
2022-04-18 12:15:28 +00:00
|
|
|
// Apply state transition on the incoming newly received block batches, one by one.
|
2022-05-10 21:20:28 +00:00
|
|
|
_, _, err := s.onBlockBatch(ctx, blocks, blkRoots)
|
2020-07-07 04:16:12 +00:00
|
|
|
if err != nil {
|
2020-07-20 19:35:30 +00:00
|
|
|
err := errors.Wrap(err, "could not process block in batch")
|
2021-09-14 20:59:51 +00:00
|
|
|
tracing.AnnotateError(span, err)
|
2020-07-07 04:16:12 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, b := range blocks {
|
2021-05-26 16:19:54 +00:00
|
|
|
blockCopy := b.Copy()
|
2020-07-07 04:16:12 +00:00
|
|
|
// Send notification of the processed block to the state feed.
|
2021-03-17 18:36:56 +00:00
|
|
|
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
|
2020-07-07 04:16:12 +00:00
|
|
|
Type: statefeed.BlockProcessed,
|
|
|
|
Data: &statefeed.BlockProcessedData{
|
2021-05-26 16:19:54 +00:00
|
|
|
Slot: blockCopy.Block().Slot(),
|
2021-01-05 20:40:11 +00:00
|
|
|
BlockRoot: blkRoots[i],
|
|
|
|
SignedBlock: blockCopy,
|
|
|
|
Verified: true,
|
2020-07-07 04:16:12 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
// Reports on blockCopy and fork choice metrics.
|
2022-01-25 18:47:39 +00:00
|
|
|
finalized := s.store.FinalizedCheckpt()
|
|
|
|
if finalized == nil {
|
|
|
|
return errNilFinalizedInStore
|
|
|
|
}
|
|
|
|
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
|
2020-09-26 08:04:07 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 15:07:46 +00:00
|
|
|
if err := s.cfg.BeaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-01-25 18:47:39 +00:00
|
|
|
finalized := s.store.FinalizedCheckpt()
|
|
|
|
if finalized == nil {
|
|
|
|
return errNilFinalizedInStore
|
|
|
|
}
|
|
|
|
if err := s.wsVerifier.VerifyWeakSubjectivity(s.ctx, finalized.Epoch); err != nil {
|
2020-10-04 15:03:10 +00:00
|
|
|
// log.Fatalf will prevent defer from being called
|
|
|
|
span.End()
|
2020-09-26 08:04:07 +00:00
|
|
|
// Exit run time if the node failed to verify weak subjectivity checkpoint.
|
|
|
|
log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
|
2020-07-07 04:16:12 +00:00
|
|
|
}
|
|
|
|
|
2020-07-20 19:35:30 +00:00
|
|
|
return nil
|
2020-07-07 04:16:12 +00:00
|
|
|
}
|
|
|
|
|
2022-05-04 00:17:40 +00:00
|
|
|
// HasBlock returns true if the block of the input root exists in initial sync blocks cache or DB.
|
|
|
|
func (s *Service) HasBlock(ctx context.Context, root [32]byte) bool {
|
|
|
|
return s.hasBlockInInitSyncOrDB(ctx, root)
|
2020-03-30 18:04:10 +00:00
|
|
|
}
|
2020-07-09 23:50:48 +00:00
|
|
|
|
2022-05-07 15:56:34 +00:00
|
|
|
// ReceiveAttesterSlashing receives an attester slashing and inserts it to forkchoice
|
|
|
|
func (s *Service) ReceiveAttesterSlashing(ctx context.Context, slashing *ethpb.AttesterSlashing) {
|
|
|
|
s.insertSlashingsToForkChoiceStore(ctx, []*ethpb.AttesterSlashing{slashing})
|
|
|
|
}
|
|
|
|
|
2022-05-02 18:32:37 +00:00
|
|
|
func (s *Service) handlePostBlockOperations(b interfaces.BeaconBlock) error {
|
2020-07-09 23:50:48 +00:00
|
|
|
// Delete the processed block attestations from attestation pool.
|
2021-05-26 16:19:54 +00:00
|
|
|
if err := s.deletePoolAtts(b.Body().Attestations()); err != nil {
|
2020-07-09 23:50:48 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add block attestations to the fork choice pool to compute head.
|
2021-05-26 16:19:54 +00:00
|
|
|
if err := s.cfg.AttPool.SaveBlockAttestations(b.Body().Attestations()); err != nil {
|
2020-07-09 23:50:48 +00:00
|
|
|
log.Errorf("Could not save block attestations for fork choice: %v", err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// Mark block exits as seen so we don't include same ones in future blocks.
|
2021-05-26 16:19:54 +00:00
|
|
|
for _, e := range b.Body().VoluntaryExits() {
|
2021-03-17 18:36:56 +00:00
|
|
|
s.cfg.ExitPool.MarkIncluded(e)
|
2020-07-09 23:50:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Mark attester slashings as seen so we don't include same ones in future blocks.
|
2021-05-26 16:19:54 +00:00
|
|
|
for _, as := range b.Body().AttesterSlashings() {
|
2021-03-17 18:36:56 +00:00
|
|
|
s.cfg.SlashingPool.MarkIncludedAttesterSlashing(as)
|
2020-07-09 23:50:48 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-10-23 00:35:30 +00:00
|
|
|
|
|
|
|
// This checks whether it's time to start saving hot state to DB.
|
|
|
|
// It's time when there's `epochsSinceFinalitySaveHotStateDB` epochs of non-finality.
|
|
|
|
func (s *Service) checkSaveHotStateDB(ctx context.Context) error {
|
2021-10-01 20:17:57 +00:00
|
|
|
currentEpoch := slots.ToEpoch(s.CurrentSlot())
|
2020-10-23 00:35:30 +00:00
|
|
|
// Prevent `sinceFinality` going underflow.
|
2021-02-09 10:05:22 +00:00
|
|
|
var sinceFinality types.Epoch
|
2022-01-25 18:47:39 +00:00
|
|
|
finalized := s.store.FinalizedCheckpt()
|
|
|
|
if finalized == nil {
|
|
|
|
return errNilFinalizedInStore
|
|
|
|
}
|
|
|
|
if currentEpoch > finalized.Epoch {
|
|
|
|
sinceFinality = currentEpoch - finalized.Epoch
|
2020-10-23 00:35:30 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 10:05:22 +00:00
|
|
|
if sinceFinality >= epochsSinceFinalitySaveHotStateDB {
|
2021-03-17 18:36:56 +00:00
|
|
|
s.cfg.StateGen.EnableSaveHotStateToDB(ctx)
|
2020-10-23 00:35:30 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-17 18:36:56 +00:00
|
|
|
return s.cfg.StateGen.DisableSaveHotStateToDB(ctx)
|
2020-10-23 00:35:30 +00:00
|
|
|
}
|