github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/state/stategen/service.go (about)

     1  // Package stategen defines functions to regenerate beacon chain states
     2  // by replaying blocks from a stored state checkpoint, useful for
     3  // optimization and reducing a beacon node's resource consumption.
     4  package stategen
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"sync"
    10  
    11  	types "github.com/prysmaticlabs/eth2-types"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/db"
    13  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    14  	ethereum_beacon_p2p_v1 "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    15  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    16  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    17  	"github.com/prysmaticlabs/prysm/shared/params"
    18  	"go.opencensus.io/trace"
    19  )
    20  
    21  var defaultHotStateDBInterval types.Slot = 128
    22  
    23  // StateManager represents a management object that handles the internal
    24  // logic of maintaining both hot and cold states in DB.
    25  type StateManager interface {
    26  	Resume(ctx context.Context) (iface.BeaconState, error)
    27  	SaveFinalizedState(fSlot types.Slot, fRoot [32]byte, fState iface.BeaconState)
    28  	MigrateToCold(ctx context.Context, fRoot [32]byte) error
    29  	ReplayBlocks(ctx context.Context, state iface.BeaconState, signed []interfaces.SignedBeaconBlock, targetSlot types.Slot) (iface.BeaconState, error)
    30  	LoadBlocks(ctx context.Context, startSlot, endSlot types.Slot, endBlockRoot [32]byte) ([]interfaces.SignedBeaconBlock, error)
    31  	HasState(ctx context.Context, blockRoot [32]byte) (bool, error)
    32  	HasStateInCache(ctx context.Context, blockRoot [32]byte) (bool, error)
    33  	StateByRoot(ctx context.Context, blockRoot [32]byte) (iface.BeaconState, error)
    34  	StateByRootInitialSync(ctx context.Context, blockRoot [32]byte) (iface.BeaconState, error)
    35  	StateBySlot(ctx context.Context, slot types.Slot) (iface.BeaconState, error)
    36  	RecoverStateSummary(ctx context.Context, blockRoot [32]byte) (*ethereum_beacon_p2p_v1.StateSummary, error)
    37  	SaveState(ctx context.Context, root [32]byte, st iface.BeaconState) error
    38  	ForceCheckpoint(ctx context.Context, root []byte) error
    39  	EnableSaveHotStateToDB(_ context.Context)
    40  	DisableSaveHotStateToDB(ctx context.Context) error
    41  }
    42  
    43  // State is a concrete implementation of StateManager.
    44  type State struct {
    45  	beaconDB                db.NoHeadAccessDatabase
    46  	slotsPerArchivedPoint   types.Slot
    47  	hotStateCache           *hotStateCache
    48  	finalizedInfo           *finalizedInfo
    49  	epochBoundaryStateCache *epochBoundaryState
    50  	saveHotStateDB          *saveHotStateDbConfig
    51  }
    52  
    53  // This tracks the config in the event of long non-finality,
    54  // how often does the node save hot states to db? what are
    55  // the saved hot states in db?... etc
    56  type saveHotStateDbConfig struct {
    57  	enabled         bool
    58  	lock            sync.Mutex
    59  	duration        types.Slot
    60  	savedStateRoots [][32]byte
    61  }
    62  
    63  // This tracks the finalized point. It's also the point where slot and the block root of
    64  // cold and hot sections of the DB splits.
    65  type finalizedInfo struct {
    66  	slot  types.Slot
    67  	root  [32]byte
    68  	state iface.BeaconState
    69  	lock  sync.RWMutex
    70  }
    71  
    72  // New returns a new state management object.
    73  func New(beaconDB db.NoHeadAccessDatabase) *State {
    74  	return &State{
    75  		beaconDB:                beaconDB,
    76  		hotStateCache:           newHotStateCache(),
    77  		finalizedInfo:           &finalizedInfo{slot: 0, root: params.BeaconConfig().ZeroHash},
    78  		slotsPerArchivedPoint:   params.BeaconConfig().SlotsPerArchivedPoint,
    79  		epochBoundaryStateCache: newBoundaryStateCache(),
    80  		saveHotStateDB: &saveHotStateDbConfig{
    81  			duration: defaultHotStateDBInterval,
    82  		},
    83  	}
    84  }
    85  
    86  // Resume resumes a new state management object from previously saved finalized check point in DB.
    87  func (s *State) Resume(ctx context.Context) (iface.BeaconState, error) {
    88  	ctx, span := trace.StartSpan(ctx, "stateGen.Resume")
    89  	defer span.End()
    90  
    91  	c, err := s.beaconDB.FinalizedCheckpoint(ctx)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	fRoot := bytesutil.ToBytes32(c.Root)
    96  	// Resume as genesis state if last finalized root is zero hashes.
    97  	if fRoot == params.BeaconConfig().ZeroHash {
    98  		return s.beaconDB.GenesisState(ctx)
    99  	}
   100  	fState, err := s.StateByRoot(ctx, fRoot)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	if fState == nil || fState.IsNil() {
   105  		return nil, errors.New("finalized state not found in disk")
   106  	}
   107  
   108  	go func() {
   109  		if err := s.beaconDB.CleanUpDirtyStates(ctx, s.slotsPerArchivedPoint); err != nil {
   110  			log.WithError(err).Error("Could not clean up dirty states")
   111  		}
   112  	}()
   113  
   114  	s.finalizedInfo = &finalizedInfo{slot: fState.Slot(), root: fRoot, state: fState.Copy()}
   115  
   116  	return fState, nil
   117  }
   118  
   119  // SaveFinalizedState saves the finalized slot, root and state into memory to be used by state gen service.
   120  // This used for migration at the correct start slot and used for hot state play back to ensure
   121  // lower bound to start is always at the last finalized state.
   122  func (s *State) SaveFinalizedState(fSlot types.Slot, fRoot [32]byte, fState iface.BeaconState) {
   123  	s.finalizedInfo.lock.Lock()
   124  	defer s.finalizedInfo.lock.Unlock()
   125  	s.finalizedInfo.root = fRoot
   126  	s.finalizedInfo.state = fState.Copy()
   127  	s.finalizedInfo.slot = fSlot
   128  }
   129  
   130  // Returns true if input root equals to cached finalized root.
   131  func (s *State) isFinalizedRoot(r [32]byte) bool {
   132  	s.finalizedInfo.lock.RLock()
   133  	defer s.finalizedInfo.lock.RUnlock()
   134  	return r == s.finalizedInfo.root
   135  }
   136  
   137  // Returns the cached and copied finalized state.
   138  func (s *State) finalizedState() iface.BeaconState {
   139  	s.finalizedInfo.lock.RLock()
   140  	defer s.finalizedInfo.lock.RUnlock()
   141  	return s.finalizedInfo.state.Copy()
   142  }