github.com/cosmos/cosmos-sdk@v0.50.10/x/staking/keeper/historical_info.go (about) 1 package keeper 2 3 import ( 4 "context" 5 "errors" 6 7 storetypes "cosmossdk.io/store/types" 8 9 sdk "github.com/cosmos/cosmos-sdk/types" 10 "github.com/cosmos/cosmos-sdk/x/staking/types" 11 ) 12 13 // GetHistoricalInfo gets the historical info at a given height 14 func (k Keeper) GetHistoricalInfo(ctx context.Context, height int64) (types.HistoricalInfo, error) { 15 store := k.storeService.OpenKVStore(ctx) 16 key := types.GetHistoricalInfoKey(height) 17 18 value, err := store.Get(key) 19 if err != nil { 20 return types.HistoricalInfo{}, err 21 } 22 23 if value == nil { 24 return types.HistoricalInfo{}, types.ErrNoHistoricalInfo 25 } 26 27 return types.UnmarshalHistoricalInfo(k.cdc, value) 28 } 29 30 // SetHistoricalInfo sets the historical info at a given height 31 func (k Keeper) SetHistoricalInfo(ctx context.Context, height int64, hi *types.HistoricalInfo) error { 32 store := k.storeService.OpenKVStore(ctx) 33 key := types.GetHistoricalInfoKey(height) 34 value, err := k.cdc.Marshal(hi) 35 if err != nil { 36 return err 37 } 38 return store.Set(key, value) 39 } 40 41 // DeleteHistoricalInfo deletes the historical info at a given height 42 func (k Keeper) DeleteHistoricalInfo(ctx context.Context, height int64) error { 43 store := k.storeService.OpenKVStore(ctx) 44 key := types.GetHistoricalInfoKey(height) 45 46 return store.Delete(key) 47 } 48 49 // IterateHistoricalInfo provides an iterator over all stored HistoricalInfo 50 // objects. For each HistoricalInfo object, cb will be called. If the cb returns 51 // true, the iterator will break and close. 52 func (k Keeper) IterateHistoricalInfo(ctx context.Context, cb func(types.HistoricalInfo) bool) error { 53 store := k.storeService.OpenKVStore(ctx) 54 iterator, err := store.Iterator(types.HistoricalInfoKey, storetypes.PrefixEndBytes(types.HistoricalInfoKey)) 55 if err != nil { 56 return err 57 } 58 defer iterator.Close() 59 60 for ; iterator.Valid(); iterator.Next() { 61 histInfo, err := types.UnmarshalHistoricalInfo(k.cdc, iterator.Value()) 62 if err != nil { 63 return err 64 } 65 if cb(histInfo) { 66 break 67 } 68 } 69 70 return nil 71 } 72 73 // GetAllHistoricalInfo returns all stored HistoricalInfo objects. 74 func (k Keeper) GetAllHistoricalInfo(ctx context.Context) ([]types.HistoricalInfo, error) { 75 var infos []types.HistoricalInfo 76 err := k.IterateHistoricalInfo(ctx, func(histInfo types.HistoricalInfo) bool { 77 infos = append(infos, histInfo) 78 return false 79 }) 80 81 return infos, err 82 } 83 84 // TrackHistoricalInfo saves the latest historical-info and deletes the oldest 85 // heights that are below pruning height 86 func (k Keeper) TrackHistoricalInfo(ctx context.Context) error { 87 entryNum, err := k.HistoricalEntries(ctx) 88 if err != nil { 89 return err 90 } 91 92 sdkCtx := sdk.UnwrapSDKContext(ctx) 93 94 // Prune store to ensure we only have parameter-defined historical entries. 95 // In most cases, this will involve removing a single historical entry. 96 // In the rare scenario when the historical entries gets reduced to a lower value k' 97 // from the original value k. k - k' entries must be deleted from the store. 98 // Since the entries to be deleted are always in a continuous range, we can iterate 99 // over the historical entries starting from the most recent version to be pruned 100 // and then return at the first empty entry. 101 for i := sdkCtx.BlockHeight() - int64(entryNum); i >= 0; i-- { 102 _, err := k.GetHistoricalInfo(ctx, i) 103 if err != nil { 104 if errors.Is(err, types.ErrNoHistoricalInfo) { 105 break 106 } 107 return err 108 } 109 if err = k.DeleteHistoricalInfo(ctx, i); err != nil { 110 return err 111 } 112 } 113 114 // if there is no need to persist historicalInfo, return 115 if entryNum == 0 { 116 return nil 117 } 118 119 // Create HistoricalInfo struct 120 lastVals, err := k.GetLastValidators(ctx) 121 if err != nil { 122 return err 123 } 124 125 historicalEntry := types.NewHistoricalInfo(sdkCtx.BlockHeader(), types.Validators{Validators: lastVals, ValidatorCodec: k.validatorAddressCodec}, k.PowerReduction(ctx)) 126 127 // Set latest HistoricalInfo at current height 128 return k.SetHistoricalInfo(ctx, sdkCtx.BlockHeight(), &historicalEntry) 129 }