github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/upgrade/internal/keeper/keeper.go (about) 1 package keeper 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 7 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 8 9 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 10 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/prefix" 11 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 12 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 13 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/upgrade/internal/types" 14 ) 15 16 type Keeper struct { 17 skipUpgradeHeights map[int64]bool 18 storeKey sdk.StoreKey 19 cdc *codec.Codec 20 upgradeHandlers map[string]types.UpgradeHandler 21 } 22 23 // NewKeeper constructs an upgrade Keeper 24 func NewKeeper(skipUpgradeHeights map[int64]bool, storeKey sdk.StoreKey, cdc *codec.Codec) Keeper { 25 return Keeper{ 26 skipUpgradeHeights: skipUpgradeHeights, 27 storeKey: storeKey, 28 cdc: cdc, 29 upgradeHandlers: map[string]types.UpgradeHandler{}, 30 } 31 } 32 33 // SetUpgradeHandler sets an UpgradeHandler for the upgrade specified by name. This handler will be called when the upgrade 34 // with this name is applied. In order for an upgrade with the given name to proceed, a handler for this upgrade 35 // must be set even if it is a no-op function. 36 func (k Keeper) SetUpgradeHandler(name string, upgradeHandler types.UpgradeHandler) { 37 k.upgradeHandlers[name] = upgradeHandler 38 } 39 40 // ScheduleUpgrade schedules an upgrade based on the specified plan. 41 // If there is another Plan already scheduled, it will overwrite it 42 // (implicitly cancelling the current plan) 43 func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { 44 if err := plan.ValidateBasic(); err != nil { 45 return err 46 } 47 48 if !plan.Time.IsZero() { 49 if !plan.Time.After(ctx.BlockHeader().Time) { 50 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") 51 } 52 } else if plan.Height <= ctx.BlockHeight() { 53 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") 54 } 55 56 if k.GetDoneHeight(ctx, plan.Name) != 0 { 57 return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgrade with name %s has already been completed", plan.Name) 58 } 59 60 bz := k.cdc.MustMarshalBinaryBare(plan) 61 store := ctx.KVStore(k.storeKey) 62 store.Set(types.PlanKey(), bz) 63 64 return nil 65 } 66 67 // GetDoneHeight returns the height at which the given upgrade was executed 68 func (k Keeper) GetDoneHeight(ctx sdk.Context, name string) int64 { 69 store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{types.DoneByte}) 70 bz := store.Get([]byte(name)) 71 if len(bz) == 0 { 72 return 0 73 } 74 75 return int64(binary.BigEndian.Uint64(bz)) 76 } 77 78 // ClearUpgradePlan clears any schedule upgrade 79 func (k Keeper) ClearUpgradePlan(ctx sdk.Context) { 80 store := ctx.KVStore(k.storeKey) 81 store.Delete(types.PlanKey()) 82 } 83 84 // Logger returns a module-specific logger. 85 func (k Keeper) Logger(ctx sdk.Context) log.Logger { 86 return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) 87 } 88 89 // GetUpgradePlan returns the currently scheduled Plan if any, setting havePlan to true if there is a scheduled 90 // upgrade or false if there is none 91 func (k Keeper) GetUpgradePlan(ctx sdk.Context) (plan types.Plan, havePlan bool) { 92 store := ctx.KVStore(k.storeKey) 93 bz := store.Get(types.PlanKey()) 94 if bz == nil { 95 return plan, false 96 } 97 98 k.cdc.MustUnmarshalBinaryBare(bz, &plan) 99 return plan, true 100 } 101 102 // setDone marks this upgrade name as being done so the name can't be reused accidentally 103 func (k Keeper) setDone(ctx sdk.Context, name string) { 104 store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{types.DoneByte}) 105 bz := make([]byte, 8) 106 binary.BigEndian.PutUint64(bz, uint64(ctx.BlockHeight())) 107 store.Set([]byte(name), bz) 108 } 109 110 // HasHandler returns true iff there is a handler registered for this name 111 func (k Keeper) HasHandler(name string) bool { 112 _, ok := k.upgradeHandlers[name] 113 return ok 114 } 115 116 // ApplyUpgrade will execute the handler associated with the Plan and mark the plan as done. 117 func (k Keeper) ApplyUpgrade(ctx sdk.Context, plan types.Plan) { 118 handler := k.upgradeHandlers[plan.Name] 119 if handler == nil { 120 panic("ApplyUpgrade should never be called without first checking HasHandler") 121 } 122 123 handler(ctx, plan) 124 125 k.ClearUpgradePlan(ctx) 126 k.setDone(ctx, plan.Name) 127 } 128 129 // IsSkipHeight checks if the given height is part of skipUpgradeHeights 130 func (k Keeper) IsSkipHeight(height int64) bool { 131 return k.skipUpgradeHeights[height] 132 }