Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[oracle] add timestamp to oracle exchange rates #1073

Merged
merged 3 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading