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

     1  package stategen
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  
     7  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
     8  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
     9  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    10  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    11  	"github.com/prysmaticlabs/prysm/shared/params"
    12  	"github.com/sirupsen/logrus"
    13  	"go.opencensus.io/trace"
    14  )
    15  
    16  // SaveState saves the state in the cache and/or DB.
    17  func (s *State) SaveState(ctx context.Context, root [32]byte, st iface.BeaconState) error {
    18  	ctx, span := trace.StartSpan(ctx, "stateGen.SaveState")
    19  	defer span.End()
    20  
    21  	return s.saveStateByRoot(ctx, root, st)
    22  }
    23  
    24  // ForceCheckpoint initiates a cold state save of the given state. This method does not update the
    25  // "last archived state" but simply saves the specified state from the root argument into the DB.
    26  func (s *State) ForceCheckpoint(ctx context.Context, root []byte) error {
    27  	ctx, span := trace.StartSpan(ctx, "stateGen.ForceCheckpoint")
    28  	defer span.End()
    29  
    30  	root32 := bytesutil.ToBytes32(root)
    31  	// Before the first finalized check point, the finalized root is zero hash.
    32  	// Return early if there hasn't been a finalized check point.
    33  	if root32 == params.BeaconConfig().ZeroHash {
    34  		return nil
    35  	}
    36  
    37  	fs, err := s.loadStateByRoot(ctx, root32)
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	return s.beaconDB.SaveState(ctx, fs, root32)
    43  }
    44  
    45  // This saves a post beacon state. On the epoch boundary,
    46  // it saves a full state. On an intermediate slot, it saves a back pointer to the
    47  // nearest epoch boundary state.
    48  func (s *State) saveStateByRoot(ctx context.Context, blockRoot [32]byte, st iface.BeaconState) error {
    49  	ctx, span := trace.StartSpan(ctx, "stateGen.saveStateByRoot")
    50  	defer span.End()
    51  
    52  	// Duration can't be 0 to prevent panic for division.
    53  	duration := uint64(math.Max(float64(s.saveHotStateDB.duration), 1))
    54  
    55  	s.saveHotStateDB.lock.Lock()
    56  	if s.saveHotStateDB.enabled && st.Slot().Mod(duration) == 0 {
    57  		if err := s.beaconDB.SaveState(ctx, st, blockRoot); err != nil {
    58  			s.saveHotStateDB.lock.Unlock()
    59  			return err
    60  		}
    61  		s.saveHotStateDB.savedStateRoots = append(s.saveHotStateDB.savedStateRoots, blockRoot)
    62  
    63  		log.WithFields(logrus.Fields{
    64  			"slot":                   st.Slot(),
    65  			"totalHotStateSavedInDB": len(s.saveHotStateDB.savedStateRoots),
    66  		}).Info("Saving hot state to DB")
    67  	}
    68  	s.saveHotStateDB.lock.Unlock()
    69  
    70  	// If the hot state is already in cache, one can be sure the state was processed and in the DB.
    71  	if s.hotStateCache.has(blockRoot) {
    72  		return nil
    73  	}
    74  
    75  	// Only on an epoch boundary slot, saves epoch boundary state in epoch boundary root state cache.
    76  	if helpers.IsEpochStart(st.Slot()) {
    77  		if err := s.epochBoundaryStateCache.put(blockRoot, st); err != nil {
    78  			return err
    79  		}
    80  	}
    81  
    82  	// On an intermediate slots, save state summary.
    83  	if err := s.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{
    84  		Slot: st.Slot(),
    85  		Root: blockRoot[:],
    86  	}); err != nil {
    87  		return err
    88  	}
    89  
    90  	// Store the copied state in the hot state cache.
    91  	s.hotStateCache.put(blockRoot, st)
    92  
    93  	return nil
    94  }
    95  
    96  // EnableSaveHotStateToDB enters the mode that saves hot beacon state to the DB.
    97  // This usually gets triggered when there's long duration since finality.
    98  func (s *State) EnableSaveHotStateToDB(_ context.Context) {
    99  	s.saveHotStateDB.lock.Lock()
   100  	defer s.saveHotStateDB.lock.Unlock()
   101  	if s.saveHotStateDB.enabled {
   102  		return
   103  	}
   104  
   105  	s.saveHotStateDB.enabled = true
   106  
   107  	log.WithFields(logrus.Fields{
   108  		"enabled":       s.saveHotStateDB.enabled,
   109  		"slotsInterval": s.saveHotStateDB.duration,
   110  	}).Warn("Entering mode to save hot states in DB")
   111  }
   112  
   113  // DisableSaveHotStateToDB exits the mode that saves beacon state to DB for the hot states.
   114  // This usually gets triggered once there's finality after long duration since finality.
   115  func (s *State) DisableSaveHotStateToDB(ctx context.Context) error {
   116  	s.saveHotStateDB.lock.Lock()
   117  	defer s.saveHotStateDB.lock.Unlock()
   118  	if !s.saveHotStateDB.enabled {
   119  		return nil
   120  	}
   121  
   122  	log.WithFields(logrus.Fields{
   123  		"enabled":          s.saveHotStateDB.enabled,
   124  		"deletedHotStates": len(s.saveHotStateDB.savedStateRoots),
   125  	}).Warn("Exiting mode to save hot states in DB")
   126  
   127  	// Delete previous saved states in DB as we are turning this mode off.
   128  	s.saveHotStateDB.enabled = false
   129  	if err := s.beaconDB.DeleteStates(ctx, s.saveHotStateDB.savedStateRoots); err != nil {
   130  		return err
   131  	}
   132  	s.saveHotStateDB.savedStateRoots = nil
   133  
   134  	return nil
   135  }