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 }