Skip to content

Commit

Permalink
Update numeric store getters to return bool if value is missing (#2169)
Browse files Browse the repository at this point in the history
* update GetTimeMs to return ok

* update GetInteger

* update GetInt

* update GetDec

* update ugov InflationCycleEnd

* comment update

* obsolete comment

* Apply suggestions from code review

Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com>

---------

Co-authored-by: Adam Moser <63419657+toteki@users.noreply.github.com>
  • Loading branch information
robert-zaremba and toteki authored Jul 27, 2023
1 parent 310d6be commit a2b51ee
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 75 deletions.
5 changes: 1 addition & 4 deletions app/inflation/inflation.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@ func (c Calculator) InflationRate(ctx sdk.Context, minter minttypes.Minter, mint
ugovKeeper := c.UgovKeeperB.Keeper(&ctx)
inflationParams := ugovKeeper.InflationParams()
maxSupplyAmount := inflationParams.MaxSupply.Amount

totalSupply := c.MintKeeper.StakingTokenSupply(ctx)
if totalSupply.GTE(maxSupplyAmount) {
// supply is already reached the maximum amount, so inflation should be zero
return sdk.ZeroDec()
}

cycleEnd, err := ugovKeeper.GetInflationCycleEnd()
util.Panic(err)

cycleEnd := ugovKeeper.GetInflationCycleEnd()
if ctx.BlockTime().After(cycleEnd) {
// new inflation cycle is starting , so we need to update the inflation max and min rate
factor := bpmath.One - inflationParams.InflationReductionRate
Expand Down
39 changes: 17 additions & 22 deletions util/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

// GetValue loads value from the store using default Unmarshaler. Panics on failure to decode.
Expand Down Expand Up @@ -98,15 +97,15 @@ func SetValueCdc(store sdk.KVStore, cdc codec.Codec, key []byte, object codec.Pr
return nil
}

// GetInt retrieves an sdkmath.Int from a KVStore, or returns zero if no value is stored.
// GetInt retrieves an sdkmath.Int from a KVStore, or returns (0, false) if no value is stored.
// It panics if a stored value fails to unmarshal or is negative.
// Accepts an additional string which should describe the field being retrieved in custom error messages.
func GetInt(store sdk.KVStore, key []byte, errField string) sdkmath.Int {
func GetInt(store sdk.KVStore, key []byte, errField string) (sdkmath.Int, bool) {
val := GetValue[*sdkmath.Int](store, key, errField)
if val == nil { // Not found
return sdk.ZeroInt()
return sdk.ZeroInt(), false
}
return *val
return *val, true
}

// SetInt stores an sdkmath.Int in a KVStore, or clears if setting to zero or nil.
Expand All @@ -120,14 +119,14 @@ func SetInt(store sdk.KVStore, key []byte, val sdkmath.Int, errField string) err
return SetValue(store, key, &val, errField)
}

// GetDec retrieves an sdk.Dec from a KVStore, or returns zero if no value is stored.
// GetDec retrieves an sdk.Dec from a KVStore, or returns (0, false) if no value is stored.
// Accepts an additional string which should describe the field being retrieved in custom error messages.
func GetDec(store sdk.KVStore, key []byte, errField string) sdk.Dec {
func GetDec(store sdk.KVStore, key []byte, errField string) (sdk.Dec, bool) {
val := GetValue[*sdk.Dec](store, key, errField)
if val == nil { // Not found
return sdk.ZeroDec()
return sdk.ZeroDec(), false
}
return *val
return *val, true
}

// SetDec stores an sdk.Dec in a KVStore, or clears if setting to zero or nil.
Expand Down Expand Up @@ -162,13 +161,10 @@ func SetAddress(store sdk.KVStore, key []byte, val sdk.AccAddress) {
}

// GetTimeMs retrieves time saved as Unix time in Miliseconds.
// Returns sdkerrors.NotFound error if the value is not there, hence time = 0 is not supported.
func GetTimeMs(store sdk.KVStore, key []byte) (time.Time, error) {
t := GetInteger[int64](store, key)
if t == 0 {
return time.Time{}, sdkerrors.ErrNotFound
}
return time.UnixMilli(t), nil
// If the value is not in the store, returns (0 unix time, false).
func GetTimeMs(store sdk.KVStore, key []byte) (time.Time, bool) {
t, ok := GetInteger[int64](store, key)
return time.UnixMilli(t), ok
}

// SetTimeMs saves time as Unix time in Miliseconds.
Expand Down Expand Up @@ -197,20 +193,19 @@ func SetInteger[T Integer](store sdk.KVStore, key []byte, v T) {
store.Set(key, bz)
}

func GetInteger[T Integer](store sdk.KVStore, key []byte) T {
func GetInteger[T Integer](store sdk.KVStore, key []byte) (T, bool) {
bz := store.Get(key)
if bz == nil {
return 0
return 0, false
}
var v T
switch any(v).(type) {
case int64, uint64:
v2 := binary.LittleEndian.Uint64(bz)
return T(v2)
return T(binary.LittleEndian.Uint64(bz)), true
case int32, uint32:
return T(binary.LittleEndian.Uint32(bz))
return T(binary.LittleEndian.Uint32(bz)), true
case byte:
return T(bz[0])
return T(bz[0]), true
}
panic("not possible: all types must be covered above")
}
38 changes: 24 additions & 14 deletions util/store/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/stretchr/testify/require"
"gotest.tools/v3/assert"

Expand All @@ -17,30 +16,41 @@ func TestGetAndSetDec(t *testing.T) {
t.Parallel()
store := tsdk.KVStore(t)
key := []byte("decKey")
val := sdk.MustNewDecFromStr("1234")
err := SetDec(store, key, val, "no error")
v1 := sdk.MustNewDecFromStr("1234.5679")
v2, ok := GetDec(store, key, "no error")
assert.Equal(t, false, ok)
assert.DeepEqual(t, sdk.ZeroDec(), v2)

err := SetDec(store, key, v1, "no error")
assert.NilError(t, err)

v := GetDec(store, key, "no error")
assert.DeepEqual(t, v, val)
v2, ok = GetDec(store, key, "no error")
assert.Equal(t, true, ok)
assert.DeepEqual(t, v2, v1)
}

func TestGetAndSetInt(t *testing.T) {
t.Parallel()
store := tsdk.KVStore(t)
key := []byte("intKey")
val, ok := sdk.NewIntFromString("1234")
v2, ok := GetInt(store, key, "no error")
assert.Equal(t, false, ok)
assert.DeepEqual(t, sdk.ZeroInt(), v2)

v1, ok := sdk.NewIntFromString("1234")
assert.Equal(t, true, ok)
err := SetInt(store, key, val, "no error")
err := SetInt(store, key, v1, "no error")
assert.NilError(t, err)

v := GetInt(store, key, "no error")
assert.DeepEqual(t, v, val)
v2, ok = GetInt(store, key, "no error")
assert.Equal(t, true, ok)
assert.DeepEqual(t, v2, v1)
}

func checkStoreNumber[T Integer](name string, val T, store sdk.KVStore, key []byte, t *testing.T) {
SetInteger(store, key, val)
vOut := GetInteger[T](store, key)
vOut, ok := GetInteger[T](store, key)
require.True(t, ok)
require.Equal(t, val, vOut, name)
}

Expand Down Expand Up @@ -75,14 +85,14 @@ func TestGetAndSetTime(t *testing.T) {
store := tsdk.KVStore(t)
key := []byte("tKey")

_, err := GetTimeMs(store, key)
assert.ErrorIs(t, err, sdkerrors.ErrNotFound)
_, ok := GetTimeMs(store, key)
assert.Equal(t, false, ok)

val := time.Now()
SetTimeMs(store, key, val)

val2, err := GetTimeMs(store, key)
assert.NilError(t, err)
val2, ok := GetTimeMs(store, key)
assert.Equal(t, true, ok)
val = val.Truncate(time.Millisecond)
assert.Equal(t, val, val2)
}
15 changes: 8 additions & 7 deletions x/incentive/keeper/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ func (k Keeper) deleteIncentiveProgram(ctx sdk.Context, id uint32) error {

// getNextProgramID gets the ID that will be assigned to the next incentive program passed by governance.
func (k Keeper) getNextProgramID(ctx sdk.Context) uint32 {
return store.GetInteger[uint32](k.KVStore(ctx), keyNextProgramID)
id, _ := store.GetInteger[uint32](k.KVStore(ctx), keyNextProgramID)
return id
}

// setNextProgramID sets the ID that will be assigned to the next incentive program passed by governance.
Expand All @@ -145,9 +146,9 @@ func (k Keeper) setNextProgramID(ctx sdk.Context, id uint32) error {
}

// getLastRewardsTime gets the last unix time incentive rewards were computed globally by EndBlocker.
// panics if it would return a negative value.
func (k Keeper) GetLastRewardsTime(ctx sdk.Context) int64 {
return store.GetInteger[int64](k.KVStore(ctx), keyLastRewardsTime)
t, _ := store.GetInteger[int64](k.KVStore(ctx), keyLastRewardsTime)
return t
}

// setLastRewardsTime sets the last unix time incentive rewards were computed globally by EndBlocker.
Expand All @@ -164,14 +165,14 @@ func (k Keeper) setLastRewardsTime(ctx sdk.Context, time int64) error {
// getTotalBonded retrieves the total amount of uTokens of a given denom which are bonded to the incentive module
func (k Keeper) getTotalBonded(ctx sdk.Context, denom string) sdk.Coin {
key := keyTotalBonded(denom)
amount := store.GetInt(k.KVStore(ctx), key, "total bonded")
amount, _ := store.GetInt(k.KVStore(ctx), key, "total bonded")
return sdk.NewCoin(denom, amount)
}

// GetBonded retrieves the amount of uTokens of a given denom which are bonded by an account
func (k Keeper) GetBonded(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin {
key := keyBondAmount(addr, denom)
amount := store.GetInt(k.KVStore(ctx), key, "bonded amount")
amount, _ := store.GetInt(k.KVStore(ctx), key, "bonded amount")
return sdk.NewCoin(denom, amount)
}

Expand All @@ -198,15 +199,15 @@ func (k Keeper) setBonded(ctx sdk.Context, addr sdk.AccAddress, uToken sdk.Coin)
// getUnbonding retrieves the amount of uTokens of a given denom which are unbonding by an account
func (k Keeper) getUnbondingAmount(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin {
key := keyUnbondAmount(addr, denom)
amount := store.GetInt(k.KVStore(ctx), key, "unbonding amount")
amount, _ := store.GetInt(k.KVStore(ctx), key, "unbonding amount")
return sdk.NewCoin(denom, amount)
}

// getTotalUnbonding retrieves the total amount of uTokens of a given denom which are unbonding from
// the incentive module
func (k Keeper) getTotalUnbonding(ctx sdk.Context, denom string) sdk.Coin {
key := keyTotalUnbonding(denom)
amount := store.GetInt(k.KVStore(ctx), key, "total unbonding")
amount, _ := store.GetInt(k.KVStore(ctx), key, "total unbonding")
return sdk.NewCoin(denom, amount)
}

Expand Down
10 changes: 2 additions & 8 deletions x/metoken/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,11 @@ func (k Keeper) InitGenesis(genState metoken.GenesisState) {

// ExportGenesis returns the x/metoken module's exported genesis state.
func (k Keeper) ExportGenesis() *metoken.GenesisState {
nextRebalancingTime, err := k.getNextRebalancingTime()
util.Panic(err)

nextInterestClaimTime, err := k.getNextInterestClaimTime()
util.Panic(err)

return &metoken.GenesisState{
Params: k.GetParams(),
Registry: k.GetAllRegisteredIndexes(),
Balances: k.GetAllIndexesBalances(),
NextRebalancingTime: nextRebalancingTime,
NextInterestClaimTime: nextInterestClaimTime,
NextRebalancingTime: k.getNextRebalancingTime(),
NextInterestClaimTime: k.getNextInterestClaimTime(),
}
}
12 changes: 8 additions & 4 deletions x/metoken/keeper/metoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ func (k Keeper) GetAllIndexesBalances() []metoken.IndexBalances {
}

// getNextRebalancingTime returns next x/metoken re-balancing time in Milliseconds.
func (k Keeper) getNextRebalancingTime() (time.Time, error) {
return store.GetTimeMs(k.store, keyPrefixNextRebalancingTime)
// Returns 0 unix time if the time was not set before.
func (k Keeper) getNextRebalancingTime() time.Time {
t, _ := store.GetTimeMs(k.store, keyPrefixNextRebalancingTime)
return t
}

// setNextRebalancingTime next x/metoken re-balancing time in Milliseconds.
Expand All @@ -53,8 +55,10 @@ func (k Keeper) setNextRebalancingTime(nextRebalancingTime time.Time) {
}

// getNextInterestClaimTime returns next x/metoken interest claiming time in Milliseconds.
func (k Keeper) getNextInterestClaimTime() (time.Time, error) {
return store.GetTimeMs(k.store, keyPrefixNextInterestClaimTime)
// Returns 0 unix time if the time was not set before.
func (k Keeper) getNextInterestClaimTime() time.Time {
t, _ := store.GetTimeMs(k.store, keyPrefixNextInterestClaimTime)
return t
}

// setNextInterestClaimTime next x/metoken interest claiming time in Milliseconds.
Expand Down
4 changes: 1 addition & 3 deletions x/ugov/keeper/genesis.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package keeper

import (
"github.com/umee-network/umee/v5/util"
"github.com/umee-network/umee/v5/x/ugov"
)

func (k Keeper) ExportGenesis() *ugov.GenesisState {
cycleEndTime, err := k.GetInflationCycleEnd()
util.Panic(err)
cycleEndTime := k.GetInflationCycleEnd()
return &ugov.GenesisState{
MinGasPrice: k.MinGasPrice(),
InflationParams: k.InflationParams(),
Expand Down
6 changes: 4 additions & 2 deletions x/ugov/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func (k Keeper) SetInflationCycleEnd(startTime time.Time) error {
return nil
}

func (k Keeper) GetInflationCycleEnd() (time.Time, error) {
return store.GetTimeMs(k.store, keyInflationCycleEnd)
// Returns zero unix time if the inflation cycle was not set.
func (k Keeper) GetInflationCycleEnd() time.Time {
t, _ := store.GetTimeMs(k.store, keyInflationCycleEnd)
return t
}
10 changes: 4 additions & 6 deletions x/ugov/keeper/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,12 @@ func TestInflationCycleEnd(t *testing.T) {
st := time.Time{}
err := k.SetInflationCycleEnd(st)
require.NoError(err)
in_c, err := k.GetInflationCycleEnd()
require.NoError(err)
require.Equal(in_c.IsZero(), true, "it should be default zero time")
end := k.GetInflationCycleEnd()
require.Equal(end.IsZero(), true, "it should be default zero time")

cycleEnd := time.Now()
err = k.SetInflationCycleEnd(cycleEnd)
require.NoError(err)
end, err := k.GetInflationCycleEnd()
require.NoError(err)
require.Equal(end.UnixMilli(), cycleEnd.UnixMilli(), "inflation cycle end time should be same")
end = k.GetInflationCycleEnd()
require.Equal(end, cycleEnd.Truncate(time.Millisecond), "inflation cycle end time should be same")
}
5 changes: 1 addition & 4 deletions x/ugov/keeper/query_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ func (q Querier) InflationParams(ctx context.Context, _ *ugov.QueryInflationPara
func (q Querier) InflationCycleEnd(ctx context.Context, _ *ugov.QueryInflationCycleEnd) (
*ugov.QueryInflationCycleEndResponse, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
cycleEndTime, err := q.Keeper(&sdkCtx).GetInflationCycleEnd()
if err != nil {
return nil, err
}
cycleEndTime := q.Keeper(&sdkCtx).GetInflationCycleEnd()
return &ugov.QueryInflationCycleEndResponse{End: &cycleEndTime}, nil
}
2 changes: 1 addition & 1 deletion x/uibc/quota/keeper/quota.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (k Keeper) GetAllOutflows() (sdk.DecCoins, error) {

// GetTokenOutflows returns sum of denom outflows in USD value in the DecCoin structure.
func (k Keeper) GetTokenOutflows(denom string) sdk.DecCoin {
amount := store.GetDec(k.store, KeyTotalOutflows(denom), "total_outflow")
amount, _ := store.GetDec(k.store, KeyTotalOutflows(denom), "total_outflow")
return sdk.NewDecCoinFromDec(denom, amount)
}

Expand Down

0 comments on commit a2b51ee

Please sign in to comment.