Skip to content

Commit

Permalink
feat(historacle): Update proto messages and remove BlockNum from medi…
Browse files Browse the repository at this point in the history
…ans (#1588)

remove blocknum from median/medianDeviation
  • Loading branch information
zarazan authored Nov 15, 2022
1 parent ea214e2 commit f331b53
Show file tree
Hide file tree
Showing 7 changed files with 395 additions and 355 deletions.
14 changes: 11 additions & 3 deletions proto/umee/oracle/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ syntax = "proto3";
package umee.oracle.v1;

import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "umee/oracle/v1/oracle.proto";

option go_package = "github.com/umee-network/umee/v3/x/oracle/types";
Expand All @@ -23,8 +22,9 @@ message GenesisState {
[(gogoproto.nullable) = false];
repeated AggregateExchangeRateVote aggregate_exchange_rate_votes = 6
[(gogoproto.nullable) = false];
repeated cosmos.base.v1beta1.DecCoin medians = 7 [(gogoproto.nullable) = false];
repeated HistoricPrice historic_prices = 8 [(gogoproto.nullable) = false];
repeated HistoricPrice historic_prices = 8 [(gogoproto.nullable) = false];
repeated ExchangeRateTuple medians = 7 [(gogoproto.nullable) = false];
repeated ExchangeRateTuple medianDeviations = 9 [(gogoproto.nullable) = false];
}

// FeederDelegation is the address for where oracle feeder authority are
Expand All @@ -41,3 +41,11 @@ message MissCounter {
string validator_address = 1;
uint64 miss_counter = 2;
}

// HistoricPrice is an instance of a price "stamp"
message HistoricPrice {
ExchangeRateTuple exchange_rate_tuple = 1 [
(gogoproto.nullable) = false
];
uint64 block_num = 2;
}
9 changes: 0 additions & 9 deletions proto/umee/oracle/v1/oracle.proto
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,3 @@ message ExchangeRateTuple {
(gogoproto.nullable) = false
];
}

// HistoricPrice is an instance of a price "stamp"
message HistoricPrice {
ExchangeRateTuple exchange_rate = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
uint64 block_num = 2;
}
70 changes: 29 additions & 41 deletions x/oracle/keeper/historic_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,34 @@ import (
)

// median returns the median of a list of historic prices.
func median(prices []types.HistoricPrice) sdk.Dec {
func median(prices []sdk.Dec) sdk.Dec {
lenPrices := len(prices)
if lenPrices == 0 {
return sdk.ZeroDec()
}

sort.Slice(prices, func(i, j int) bool {
return prices[i].ExchangeRate.BigInt().
Cmp(prices[j].ExchangeRate.BigInt()) > 0
return prices[i].BigInt().
Cmp(prices[j].BigInt()) > 0
})

if lenPrices%2 == 0 {
return prices[lenPrices/2-1].ExchangeRate.
Add(prices[lenPrices/2].ExchangeRate).
return prices[lenPrices/2-1].
Add(prices[lenPrices/2]).
QuoInt64(2)
}
return prices[lenPrices/2].ExchangeRate
return prices[lenPrices/2]
}

// medianDeviation returns the standard deviation around the
// median of a list of prices.
// medianDeviation = ∑((price - median)^2 / len(prices))
func medianDeviation(median sdk.Dec, prices []types.HistoricPrice) sdk.Dec {
func medianDeviation(median sdk.Dec, prices []sdk.Dec) sdk.Dec {
lenPrices := len(prices)
medianDeviation := sdk.ZeroDec()

for _, price := range prices {
medianDeviation = medianDeviation.Add(price.ExchangeRate.
medianDeviation = medianDeviation.Add(price.
Sub(median).Abs().Power(2).
QuoInt64(int64(lenPrices)))
}
Expand All @@ -52,18 +52,16 @@ func medianDeviation(median sdk.Dec, prices []types.HistoricPrice) sdk.Dec {
func (k Keeper) GetMedian(
ctx sdk.Context,
denom string,
blockNum uint64,
) (sdk.Dec, error) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyMedian(denom, blockNum))
bz := store.Get(types.KeyMedian(denom))
if bz == nil {
return sdk.ZeroDec(), sdkerrors.Wrap(types.ErrNoMedian, fmt.Sprintf("denom: %s block: %d", denom, blockNum))
return sdk.ZeroDec(), sdkerrors.Wrap(types.ErrNoMedian, fmt.Sprintf("denom: %s", denom))
}

decProto := sdk.DecProto{}
k.cdc.MustUnmarshal(bz, &decProto)

return decProto.Dec, nil
median := sdk.DecProto{}
k.cdc.MustUnmarshal(bz, &median)
return median.Dec, nil
}

// SetMedian uses all the historic prices of a given denom to calculate
Expand All @@ -78,7 +76,7 @@ func (k Keeper) SetMedian(
historicPrices := k.getHistoricPrices(ctx, denom)
median := median(historicPrices)
bz := k.cdc.MustMarshal(&sdk.DecProto{Dec: median})
store.Set(types.KeyMedian(denom, uint64(ctx.BlockHeight())), bz)
store.Set(types.KeyMedian(denom), bz)
k.setMedianDeviation(ctx, denom, median, historicPrices)
}

Expand All @@ -87,12 +85,11 @@ func (k Keeper) SetMedian(
func (k Keeper) GetMedianDeviation(
ctx sdk.Context,
denom string,
blockNum uint64,
) (sdk.Dec, error) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyMedianDeviation(denom, blockNum))
bz := store.Get(types.KeyMedianDeviation(denom))
if bz == nil {
return sdk.ZeroDec(), sdkerrors.Wrap(types.ErrNoMedianDeviation, fmt.Sprintf("denom: %s block: %d", denom, blockNum))
return sdk.ZeroDec(), sdkerrors.Wrap(types.ErrNoMedianDeviation, fmt.Sprintf("denom: %s", denom))
}

decProto := sdk.DecProto{}
Expand All @@ -107,27 +104,23 @@ func (k Keeper) setMedianDeviation(
ctx sdk.Context,
denom string,
median sdk.Dec,
prices []types.HistoricPrice,
prices []sdk.Dec,
) {
store := ctx.KVStore(k.storeKey)
medianDeviation := medianDeviation(median, prices)
bz := k.cdc.MustMarshal(&sdk.DecProto{Dec: medianDeviation})
store.Set(types.KeyMedianDeviation(denom, uint64(ctx.BlockHeight())), bz)
store.Set(types.KeyMedianDeviation(denom), bz)
}

// getHistoricPrices returns all the historic prices of a given denom.
func (k Keeper) getHistoricPrices(
ctx sdk.Context,
denom string,
) []types.HistoricPrice {
historicPrices := []types.HistoricPrice{}

k.IterateHistoricPrices(ctx, denom, func(exchangeRate sdk.Dec, blockNum uint64) bool {
historicPrices = append(historicPrices, types.HistoricPrice{
ExchangeRate: exchangeRate,
BlockNum: blockNum,
})
) []sdk.Dec {
historicPrices := []sdk.Dec{}

k.IterateHistoricPrices(ctx, denom, func(exchangeRate sdk.Dec) bool {
historicPrices = append(historicPrices, exchangeRate)
return false
})

Expand All @@ -140,7 +133,7 @@ func (k Keeper) getHistoricPrices(
func (k Keeper) IterateHistoricPrices(
ctx sdk.Context,
denom string,
handler func(sdk.Dec, uint64) bool,
handler func(sdk.Dec) bool,
) {
store := ctx.KVStore(k.storeKey)

Expand All @@ -150,9 +143,9 @@ func (k Keeper) IterateHistoricPrices(
defer iter.Close()

for ; iter.Valid(); iter.Next() {
var historicPrice types.HistoricPrice
k.cdc.MustUnmarshal(iter.Value(), &historicPrice)
if handler(historicPrice.ExchangeRate, historicPrice.BlockNum) {
decProto := sdk.DecProto{}
k.cdc.MustUnmarshal(iter.Value(), &decProto)
if handler(decProto.Dec) {
break
}
}
Expand All @@ -167,10 +160,7 @@ func (k Keeper) AddHistoricPrice(
) {
store := ctx.KVStore(k.storeKey)
block := uint64(ctx.BlockHeight())
bz := k.cdc.MustMarshal(&types.HistoricPrice{
ExchangeRate: exchangeRate,
BlockNum: block,
})
bz := k.cdc.MustMarshal(&sdk.DecProto{Dec: exchangeRate})
store.Set(types.KeyHistoricPrice(denom, block), bz)
}

Expand All @@ -190,19 +180,17 @@ func (k Keeper) DeleteHistoricPrice(
func (k Keeper) DeleteMedian(
ctx sdk.Context,
denom string,
blockNum uint64,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.KeyMedian(denom, blockNum))
store.Delete(types.KeyMedian(denom))
}

// DeleteMedianDeviation deletes a given denom's standard deviation around
// its median price in the last prune period since a given block.
func (k Keeper) DeleteMedianDeviation(
ctx sdk.Context,
denom string,
blockNum uint64,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.KeyMedianDeviation(denom, blockNum))
store.Delete(types.KeyMedianDeviation(denom))
}
12 changes: 6 additions & 6 deletions x/oracle/keeper/historic_price_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,24 @@ func (s *IntegrationTestSuite) TestSetHistoraclePricing() {

// set and check median and median standard deviation
app.OracleKeeper.SetMedian(ctx, displayDenom)
median, err := app.OracleKeeper.GetMedian(ctx, displayDenom, uint64(ctx.BlockHeight()))
median, err := app.OracleKeeper.GetMedian(ctx, displayDenom)
s.Require().NoError(err)
s.Require().Equal(median, sdk.MustNewDecFromStr("1.15"))

medianDeviation, err := app.OracleKeeper.GetMedianDeviation(ctx, displayDenom, uint64(ctx.BlockHeight()))
medianDeviation, err := app.OracleKeeper.GetMedianDeviation(ctx, displayDenom)
s.Require().NoError(err)
s.Require().Equal(medianDeviation, sdk.MustNewDecFromStr("0.0225"))

// delete first historic price, median, and median standard deviation
app.OracleKeeper.DeleteHistoricPrice(ctx, displayDenom, uint64(ctx.BlockHeight()-3))
app.OracleKeeper.DeleteMedian(ctx, displayDenom, uint64(ctx.BlockHeight()))
app.OracleKeeper.DeleteMedianDeviation(ctx, displayDenom, uint64(ctx.BlockHeight()))
app.OracleKeeper.DeleteMedian(ctx, displayDenom)
app.OracleKeeper.DeleteMedianDeviation(ctx, displayDenom)

median, err = app.OracleKeeper.GetMedian(ctx, displayDenom, uint64(ctx.BlockHeight()))
median, err = app.OracleKeeper.GetMedian(ctx, displayDenom)
s.Require().Error(err, sdkerrors.Wrap(types.ErrUnknownDenom, displayDenom))
s.Require().Equal(median, sdk.ZeroDec())

medianDeviation, err = app.OracleKeeper.GetMedianDeviation(ctx, displayDenom, uint64(ctx.BlockHeight()))
medianDeviation, err = app.OracleKeeper.GetMedianDeviation(ctx, displayDenom)
s.Require().Error(err, sdkerrors.Wrap(types.ErrUnknownDenom, displayDenom))
s.Require().Equal(median, sdk.ZeroDec())
}
Loading

0 comments on commit f331b53

Please sign in to comment.