Skip to content

Commit

Permalink
[oracle] add timestamp to oracle exchange rates (#1073)
Browse files Browse the repository at this point in the history
* add timestamp to oracle exchange rates

* fix tests

* fix tests
  • Loading branch information
udpatil authored Sep 28, 2023
1 parent 4fdcf14 commit 4604460
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 100 deletions.
5 changes: 4 additions & 1 deletion proto/oracle/oracle.proto
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ message OracleExchangeRate {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
int64 last_update_timestamp = 3 [
(gogoproto.moretags) = "yaml:\"last_update_timestamp\""
];
}

message PriceSnapshotItem {
Expand All @@ -103,7 +106,7 @@ message PriceSnapshotItem {
}

message PriceSnapshot {
int64 snapshotTimestamp = 1 [
int64 snapshot_timestamp = 1 [
(gogoproto.moretags) = "yaml:\"snapshot_timestamp\""
];
repeated PriceSnapshotItem price_snapshot_items = 2 [
Expand Down
2 changes: 1 addition & 1 deletion wasmbinding/test/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func TestWasmGetOracleExchangeRates(t *testing.T) {
var parsedRes2 oracletypes.QueryExchangeRatesResponse
err = json.Unmarshal(res, &parsedRes2)
require.NoError(t, err)
require.Equal(t, oracletypes.QueryExchangeRatesResponse{DenomOracleExchangeRatePairs: oracletypes.DenomOracleExchangeRatePairs{oracletypes.NewDenomOracleExchangeRatePair(oracleutils.MicroAtomDenom, sdk.NewDec(12), sdk.NewInt(11))}}, parsedRes2)
require.Equal(t, oracletypes.QueryExchangeRatesResponse{DenomOracleExchangeRatePairs: oracletypes.DenomOracleExchangeRatePairs{oracletypes.NewDenomOracleExchangeRatePair(oracleutils.MicroAtomDenom, sdk.NewDec(12), sdk.NewInt(11), testWrapper.Ctx.BlockTime().UnixMilli())}}, parsedRes2)
}

func TestWasmGetOracleTwaps(t *testing.T) {
Expand Down
35 changes: 19 additions & 16 deletions x/oracle/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestOracleThreshold(t *testing.T) {
oracle.MidBlocker(input.Ctx.WithBlockHeight(1), input.OracleKeeper)
oracle.EndBlocker(input.Ctx.WithBlockHeight(1), input.OracleKeeper)

_, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx.WithBlockHeight(1), utils.MicroAtomDenom)
_, _, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx.WithBlockHeight(1), utils.MicroAtomDenom)
require.Error(t, err)

// Case 2.
Expand All @@ -53,7 +53,7 @@ func TestOracleThreshold(t *testing.T) {
oracle.MidBlocker(input.Ctx.WithBlockHeight(1), input.OracleKeeper)
oracle.EndBlocker(input.Ctx.WithBlockHeight(1), input.OracleKeeper)

rate, lastUpdate, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx.WithBlockHeight(1), utils.MicroAtomDenom)
rate, lastUpdate, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx.WithBlockHeight(1), utils.MicroAtomDenom)
require.NoError(t, err)
require.Equal(t, randomExchangeRate, rate)
require.Equal(t, int64(1), lastUpdate.Int64())
Expand All @@ -74,7 +74,7 @@ func TestOracleThreshold(t *testing.T) {
oracle.MidBlocker(input.Ctx.WithBlockHeight(3), input.OracleKeeper)
oracle.EndBlocker(input.Ctx.WithBlockHeight(3), input.OracleKeeper)

rate, lastUpdate, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx.WithBlockHeight(3), utils.MicroAtomDenom)
rate, lastUpdate, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx.WithBlockHeight(3), utils.MicroAtomDenom)
require.NoError(t, err)
require.Equal(t, randomExchangeRate, rate)
// This should still be an older value due to staleness
Expand All @@ -93,7 +93,7 @@ func TestOracleDrop(t *testing.T) {
oracle.MidBlocker(input.Ctx, input.OracleKeeper)
oracle.EndBlocker(input.Ctx, input.OracleKeeper)

rate, lastUpdate, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
rate, lastUpdate, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.NoError(t, err)
require.Equal(t, randomExchangeRate, rate)
// The value should have a stale height
Expand Down Expand Up @@ -194,14 +194,14 @@ func TestOracleTallyTiming(t *testing.T) {

oracle.MidBlocker(input.Ctx, input.OracleKeeper)
oracle.EndBlocker(input.Ctx, input.OracleKeeper)
_, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
_, _, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.Error(t, err)

input.Ctx = input.Ctx.WithBlockHeight(int64(params.VotePeriod - 1))

oracle.MidBlocker(input.Ctx, input.OracleKeeper)
oracle.EndBlocker(input.Ctx, input.OracleKeeper)
_, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
_, _, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.NoError(t, err)
}

Expand Down Expand Up @@ -398,12 +398,12 @@ func TestInvalidVoteOnAssetUnderThresholdMisses(t *testing.T) {

input.Ctx = input.Ctx.WithBlockHeight(input.Ctx.BlockHeight() + 1)

rate, lastUpdate, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
rate, lastUpdate, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.NoError(t, err)
require.Equal(t, randomExchangeRate, rate)
require.Equal(t, endBlockerHeight, lastUpdate.Int64())

rate, lastUpdate, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroEthDenom)
rate, lastUpdate, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroEthDenom)
require.NoError(t, err)
require.Equal(t, randomExchangeRate, rate)
require.Equal(t, endBlockerHeight, lastUpdate.Int64())
Expand Down Expand Up @@ -439,13 +439,13 @@ func TestInvalidVoteOnAssetUnderThresholdMisses(t *testing.T) {

input.Ctx = input.Ctx.WithBlockHeight(input.Ctx.BlockHeight() + 1)

rate, lastUpdate, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
rate, lastUpdate, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.NoError(t, err)
require.Equal(t, anotherRandomExchangeRate, rate)
require.Equal(t, newEndBlockerHeight, lastUpdate.Int64())

// the old value should be persisted because asset didnt meet ballot threshold
rate, lastUpdate, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroEthDenom)
rate, lastUpdate, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroEthDenom)
require.NoError(t, err)
require.Equal(t, randomExchangeRate, rate)
// block height should be old
Expand Down Expand Up @@ -571,7 +571,7 @@ func TestAbstainWithSmallStakingPower(t *testing.T) {

oracle.MidBlocker(input.Ctx, input.OracleKeeper)
oracle.EndBlocker(input.Ctx, input.OracleKeeper)
_, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
_, _, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.Error(t, err)
}

Expand All @@ -591,11 +591,12 @@ func TestOraclePriceSnapshot(t *testing.T) {
oracle.MidBlocker(input.Ctx, input.OracleKeeper)
oracle.EndBlocker(input.Ctx, input.OracleKeeper)

rate, lastUpdate, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
rate, lastUpdate, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.NoError(t, err)
require.Equal(t, randomExchangeRate, rate)
// The value should have a stale height
require.Equal(t, sdk.ZeroInt(), lastUpdate)
ts := input.Ctx.BlockTime().UnixMilli()

snapshot := input.OracleKeeper.GetPriceSnapshot(input.Ctx, 100)
require.NoError(t, err)
Expand All @@ -605,8 +606,9 @@ func TestOraclePriceSnapshot(t *testing.T) {
{
Denom: utils.MicroAtomDenom,
OracleExchangeRate: types.OracleExchangeRate{
ExchangeRate: randomExchangeRate,
LastUpdate: sdk.NewInt(input.Ctx.BlockHeight()),
ExchangeRate: randomExchangeRate,
LastUpdate: sdk.NewInt(input.Ctx.BlockHeight()),
LastUpdateTimestamp: ts,
},
},
},
Expand All @@ -622,8 +624,9 @@ func TestOraclePriceSnapshot(t *testing.T) {
{
Denom: utils.MicroAtomDenom,
OracleExchangeRate: types.OracleExchangeRate{
ExchangeRate: randomExchangeRate,
LastUpdate: sdk.NewInt(input.Ctx.BlockHeight()),
ExchangeRate: randomExchangeRate,
LastUpdate: sdk.NewInt(input.Ctx.BlockHeight()),
LastUpdateTimestamp: ts,
},
},
},
Expand Down
9 changes: 5 additions & 4 deletions x/oracle/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,23 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
//-----------------------------------
// ExchangeRate logic

func (k Keeper) GetBaseExchangeRate(ctx sdk.Context, denom string) (sdk.Dec, sdk.Int, error) {
func (k Keeper) GetBaseExchangeRate(ctx sdk.Context, denom string) (sdk.Dec, sdk.Int, int64, error) {
store := ctx.KVStore(k.storeKey)
b := store.Get(types.GetExchangeRateKey(denom))
if b == nil {
return sdk.ZeroDec(), sdk.ZeroInt(), sdkerrors.Wrap(types.ErrUnknownDenom, denom)
return sdk.ZeroDec(), sdk.ZeroInt(), 0, sdkerrors.Wrap(types.ErrUnknownDenom, denom)
}

exchangeRate := types.OracleExchangeRate{}
k.cdc.MustUnmarshal(b, &exchangeRate)
return exchangeRate.ExchangeRate, exchangeRate.LastUpdate, nil
return exchangeRate.ExchangeRate, exchangeRate.LastUpdate, exchangeRate.LastUpdateTimestamp, nil
}

func (k Keeper) SetBaseExchangeRate(ctx sdk.Context, denom string, exchangeRate sdk.Dec) {
store := ctx.KVStore(k.storeKey)
currHeight := sdk.NewInt(ctx.BlockHeight())
rate := types.OracleExchangeRate{ExchangeRate: exchangeRate, LastUpdate: currHeight}
blockTimestamp := ctx.BlockTime().UnixMilli()
rate := types.OracleExchangeRate{ExchangeRate: exchangeRate, LastUpdate: currHeight, LastUpdateTimestamp: blockTimestamp}
bz := k.cdc.MustMarshal(&rate)
store.Set(types.GetExchangeRateKey(denom), bz)
}
Expand Down
14 changes: 10 additions & 4 deletions x/oracle/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,33 @@ func TestExchangeRate(t *testing.T) {

// Set & get rates
input.OracleKeeper.SetBaseExchangeRate(input.Ctx, utils.MicroSeiDenom, cnyExchangeRate)
rate, lastUpdate, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroSeiDenom)
rate, lastUpdate, _, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroSeiDenom)
require.NoError(t, err)
require.Equal(t, cnyExchangeRate, rate)
require.Equal(t, sdk.ZeroInt(), lastUpdate)

input.Ctx = input.Ctx.WithBlockHeight(3)
ts := time.Now()
input.Ctx = input.Ctx.WithBlockTime(ts)

input.OracleKeeper.SetBaseExchangeRate(input.Ctx, utils.MicroEthDenom, gbpExchangeRate)
rate, lastUpdate, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroEthDenom)
rate, lastUpdate, lastUpdateTimestamp, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroEthDenom)
require.NoError(t, err)
require.Equal(t, gbpExchangeRate, rate)
require.Equal(t, sdk.NewInt(3), lastUpdate)
require.Equal(t, ts.UnixMilli(), lastUpdateTimestamp)

input.Ctx = input.Ctx.WithBlockHeight(15)
laterTS := ts.Add(time.Hour)
input.Ctx = input.Ctx.WithBlockTime(laterTS)

// verify behavior works with event too
input.OracleKeeper.SetBaseExchangeRateWithEvent(input.Ctx, utils.MicroAtomDenom, krwExchangeRate)
rate, lastUpdate, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
rate, lastUpdate, lastUpdateTimestamp, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.NoError(t, err)
require.Equal(t, krwExchangeRate, rate)
require.Equal(t, sdk.NewInt(15), lastUpdate)
require.Equal(t, laterTS.UnixMilli(), lastUpdateTimestamp)
require.True(t, func() bool {
expectedEvent := sdk.NewEvent(types.EventTypeExchangeRateUpdate,
sdk.NewAttribute(types.AttributeKeyDenom, utils.MicroAtomDenom),
Expand All @@ -67,7 +73,7 @@ func TestExchangeRate(t *testing.T) {
}())

input.OracleKeeper.DeleteBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
_, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
_, _, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.Error(t, err)

numExchangeRates := 0
Expand Down
6 changes: 3 additions & 3 deletions x/oracle/keeper/migrations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ func TestMigrate2to3(t *testing.T) {
m.Migrate2to3(input.Ctx)

// Get rate
rate, lastUpdate, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroSeiDenom)
rate, lastUpdate, lastUpdateTimestamp, err := input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroSeiDenom)
require.NoError(t, err)
require.Equal(t, exchangeRate, rate)
require.Equal(t, sdk.ZeroInt(), lastUpdate)
require.Equal(t, int64(0), lastUpdateTimestamp)

input.OracleKeeper.DeleteBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
_, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
_, _, _, err = input.OracleKeeper.GetBaseExchangeRate(input.Ctx, utils.MicroAtomDenom)
require.Error(t, err)

numExchangeRates := 0
Expand Down Expand Up @@ -83,7 +84,6 @@ func TestMigrate3to4(t *testing.T) {
require.Equal(t, types.VotePenaltyCounter{MissCount: missCounter, AbstainCount: 0}, votePenaltyCounter)

input.OracleKeeper.DeleteVotePenaltyCounter(input.Ctx, addr)
votePenaltyCounter = input.OracleKeeper.GetVotePenaltyCounter(input.Ctx, addr) //nolint:staticcheck // no need to use this.

numPenaltyCounters := 0
handler := func(operators sdk.ValAddress, votePenaltyCounter types.VotePenaltyCounter) (stop bool) {
Expand Down
6 changes: 4 additions & 2 deletions x/oracle/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ func (q querier) ExchangeRate(c context.Context, req *types.QueryExchangeRateReq
}

ctx := sdk.UnwrapSDKContext(c)
exchangeRate, lastUpdate, err := q.GetBaseExchangeRate(ctx, req.Denom)
exchangeRate, lastUpdate, lastUpdateTimestamp, err := q.GetBaseExchangeRate(ctx, req.Denom)
if err != nil {
return nil, err
}

return &types.QueryExchangeRateResponse{OracleExchangeRate: types.OracleExchangeRate{ExchangeRate: exchangeRate, LastUpdate: lastUpdate}}, nil
return &types.QueryExchangeRateResponse{OracleExchangeRate: types.OracleExchangeRate{
ExchangeRate: exchangeRate, LastUpdate: lastUpdate, LastUpdateTimestamp: lastUpdateTimestamp,
}}, nil
}

// ExchangeRates queries exchange rates of all denoms
Expand Down
4 changes: 2 additions & 2 deletions x/oracle/keeper/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ func TestQueryExchangeRates(t *testing.T) {
require.NoError(t, err)

require.Equal(t, types.DenomOracleExchangeRatePairs{
types.NewDenomOracleExchangeRatePair(utils.MicroAtomDenom, rate, sdk.ZeroInt()),
types.NewDenomOracleExchangeRatePair(utils.MicroSeiDenom, rate, sdk.ZeroInt()),
types.NewDenomOracleExchangeRatePair(utils.MicroAtomDenom, rate, sdk.ZeroInt(), input.Ctx.BlockTime().UnixMilli()),
types.NewDenomOracleExchangeRatePair(utils.MicroSeiDenom, rate, sdk.ZeroInt(), input.Ctx.BlockTime().UnixMilli()),
}, res.DenomOracleExchangeRatePairs)
}

Expand Down
Loading

0 comments on commit 4604460

Please sign in to comment.