github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/state/stategen/migrate.go (about) 1 package stategen 2 3 import ( 4 "context" 5 "encoding/hex" 6 "fmt" 7 8 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 9 "github.com/prysmaticlabs/prysm/shared/bytesutil" 10 "github.com/sirupsen/logrus" 11 "go.opencensus.io/trace" 12 ) 13 14 // MigrateToCold advances the finalized info in between the cold and hot state sections. 15 // It moves the recent finalized states from the hot section to the cold section and 16 // only preserve the ones that's on archived point. 17 func (s *State) MigrateToCold(ctx context.Context, fRoot [32]byte) error { 18 ctx, span := trace.StartSpan(ctx, "stateGen.MigrateToCold") 19 defer span.End() 20 21 s.finalizedInfo.lock.RLock() 22 oldFSlot := s.finalizedInfo.slot 23 s.finalizedInfo.lock.RUnlock() 24 25 fBlock, err := s.beaconDB.Block(ctx, fRoot) 26 if err != nil { 27 return err 28 } 29 fSlot := fBlock.Block().Slot() 30 if oldFSlot > fSlot { 31 return nil 32 } 33 34 // Start at previous finalized slot, stop at current finalized slot. 35 // If the slot is on archived point, save the state of that slot to the DB. 36 for slot := oldFSlot; slot < fSlot; slot++ { 37 if ctx.Err() != nil { 38 return ctx.Err() 39 } 40 41 if slot%s.slotsPerArchivedPoint == 0 && slot != 0 { 42 cached, exists, err := s.epochBoundaryStateCache.getBySlot(slot) 43 if err != nil { 44 return fmt.Errorf("could not get epoch boundary state for slot %d", slot) 45 } 46 47 var aRoot [32]byte 48 var aState iface.BeaconState 49 50 // When the epoch boundary state is not in cache due to skip slot scenario, 51 // we have to regenerate the state which will represent epoch boundary. 52 // By finding the highest available block below epoch boundary slot, we 53 // generate the state for that block root. 54 if exists { 55 aRoot = cached.root 56 aState = cached.state 57 } else { 58 blks, err := s.beaconDB.HighestSlotBlocksBelow(ctx, slot) 59 if err != nil { 60 return err 61 } 62 // Given the block has been finalized, the db should not have more than one block in a given slot. 63 // We should error out when this happens. 64 if len(blks) != 1 { 65 return errUnknownBlock 66 } 67 missingRoot, err := blks[0].Block().HashTreeRoot() 68 if err != nil { 69 return err 70 } 71 aRoot = missingRoot 72 // There's no need to generate the state if the state already exists on the DB. 73 // We can skip saving the state. 74 if !s.beaconDB.HasState(ctx, aRoot) { 75 aState, err = s.StateByRoot(ctx, missingRoot) 76 if err != nil { 77 return err 78 } 79 } 80 } 81 82 if s.beaconDB.HasState(ctx, aRoot) { 83 // Remove hot state DB root to prevent it gets deleted later when we turn hot state save DB mode off. 84 s.saveHotStateDB.lock.Lock() 85 roots := s.saveHotStateDB.savedStateRoots 86 for i := 0; i < len(roots); i++ { 87 if aRoot == roots[i] { 88 s.saveHotStateDB.savedStateRoots = append(roots[:i], roots[i+1:]...) 89 // There shouldn't be duplicated roots in `savedStateRoots`. 90 // Break here is ok. 91 break 92 } 93 } 94 s.saveHotStateDB.lock.Unlock() 95 continue 96 } 97 98 if err := s.beaconDB.SaveState(ctx, aState, aRoot); err != nil { 99 return err 100 } 101 log.WithFields( 102 logrus.Fields{ 103 "slot": aState.Slot(), 104 "root": hex.EncodeToString(bytesutil.Trunc(aRoot[:])), 105 }).Info("Saved state in DB") 106 } 107 } 108 109 // Update finalized info in memory. 110 fInfo, ok, err := s.epochBoundaryStateCache.getByRoot(fRoot) 111 if err != nil { 112 return err 113 } 114 if ok { 115 s.SaveFinalizedState(fSlot, fRoot, fInfo.state) 116 } 117 118 return nil 119 }