diff --git a/proto/umee/oracle/v1/oracle.proto b/proto/umee/oracle/v1/oracle.proto index 714541bdde..baa0d6d349 100644 --- a/proto/umee/oracle/v1/oracle.proto +++ b/proto/umee/oracle/v1/oracle.proto @@ -47,6 +47,10 @@ message Params { // Prune Period represents the maximum amount of blocks which we want // to keep a record of our set of exchange rates. uint64 prune_period = 10; + // Median Period represents the amount blocks we will wait between + // calculating the median and standard deviation of the median of + // historic prices in the last Prune Period. + uint64 median_period = 11; } // Denom - the object to hold configurations of each denom @@ -107,9 +111,9 @@ message ExchangeRateTuple { // HistoricPrice is an instance of a price "stamp" message HistoricPrice { - ExchangeRateTuple exchange_rates = 1 [ - (gogoproto.castrepeated) = "ExchangeRateTuples", - (gogoproto.nullable) = false + ExchangeRateTuple exchange_rate = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false ]; uint64 block_num = 2; } diff --git a/x/oracle/keeper/historic_price.go b/x/oracle/keeper/historic_price.go new file mode 100644 index 0000000000..b7e5bf19b6 --- /dev/null +++ b/x/oracle/keeper/historic_price.go @@ -0,0 +1,205 @@ +package keeper + +import ( + "fmt" + "sort" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/umee-network/umee/v3/x/oracle/types" +) + +// median returns the median of a list of historic prices. +func median(prices []types.HistoricPrice) 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 + }) + + if lenPrices%2 == 0 { + return prices[lenPrices/2-1].ExchangeRate. + Add(prices[lenPrices/2].ExchangeRate). + QuoInt64(2) + } + return prices[lenPrices/2].ExchangeRate +} + +// 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 { + lenPrices := len(prices) + medianDeviation := sdk.ZeroDec() + + for _, price := range prices { + medianDeviation = medianDeviation.Add(price.ExchangeRate. + Sub(median).Abs().Power(2). + QuoInt64(int64(lenPrices))) + } + + return medianDeviation +} + +// GetMedian returns a given denom's median price in the last prune +// period since a given block. +func (k Keeper) GetMedian( + ctx sdk.Context, + denom string, + blockNum uint64, +) (sdk.Dec, error) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.GetMedianKey(denom, blockNum)) + if bz == nil { + return sdk.ZeroDec(), sdkerrors.Wrap(types.ErrNoMedian, fmt.Sprintf("denom: %s block: %d", denom, blockNum)) + } + + decProto := sdk.DecProto{} + k.cdc.MustUnmarshal(bz, &decProto) + + return decProto.Dec, nil +} + +// SetMedian uses all the historic prices of a given denom to calculate +// its median price in the last prune period since the current block and +// set it to the store. It will also call setMedianDeviation with the +// calculated median. +func (k Keeper) SetMedian( + ctx sdk.Context, + denom string, +) { + store := ctx.KVStore(k.storeKey) + historicPrices := k.getHistoricPrices(ctx, denom) + median := median(historicPrices) + bz := k.cdc.MustMarshal(&sdk.DecProto{Dec: median}) + store.Set(types.GetMedianKey(denom, uint64(ctx.BlockHeight())), bz) + k.setMedianDeviation(ctx, denom, median, historicPrices) +} + +// GetMedianDeviation returns a given denom's standard deviation around +// its median price in the last prune period since a given block. +func (k Keeper) GetMedianDeviation( + ctx sdk.Context, + denom string, + blockNum uint64, +) (sdk.Dec, error) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.GetMedianDeviationKey(denom, blockNum)) + if bz == nil { + return sdk.ZeroDec(), sdkerrors.Wrap(types.ErrNoMedianDeviation, fmt.Sprintf("denom: %s block: %d", denom, blockNum)) + } + + decProto := sdk.DecProto{} + k.cdc.MustUnmarshal(bz, &decProto) + + return decProto.Dec, nil +} + +// setMedianDeviation sets a given denom's standard deviation around +// its median price in the last prune period since the current block. +func (k Keeper) setMedianDeviation( + ctx sdk.Context, + denom string, + median sdk.Dec, + prices []types.HistoricPrice, +) { + store := ctx.KVStore(k.storeKey) + medianDeviation := medianDeviation(median, prices) + bz := k.cdc.MustMarshal(&sdk.DecProto{Dec: medianDeviation}) + store.Set(types.GetMedianDeviationKey(denom, uint64(ctx.BlockHeight())), 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, + }) + + return false + }) + + return historicPrices +} + +// IterateHistoricPrices iterates over historic prices of a given +// denom in the store. +// Iterator stops when exhausting the source, or when the handler returns `true`. +func (k Keeper) IterateHistoricPrices( + ctx sdk.Context, + denom string, + handler func(sdk.Dec, uint64) bool, +) { + store := ctx.KVStore(k.storeKey) + + iter := sdk.KVStorePrefixIterator(store, append(types.KeyPrefixHistoricPrice, []byte(denom)...)) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + var historicPrice types.HistoricPrice + k.cdc.MustUnmarshal(iter.Value(), &historicPrice) + if handler(historicPrice.ExchangeRate, historicPrice.BlockNum) { + break + } + } +} + +// AddHistoricPrice adds the historic price of a denom at the current +// block height. +func (k Keeper) AddHistoricPrice( + ctx sdk.Context, + denom string, + exchangeRate sdk.Dec, +) { + store := ctx.KVStore(k.storeKey) + block := uint64(ctx.BlockHeight()) + bz := k.cdc.MustMarshal(&types.HistoricPrice{ + ExchangeRate: exchangeRate, + BlockNum: block, + }) + store.Set(types.GetHistoricPriceKey(denom, block), bz) +} + +// DeleteHistoricPrice deletes the historic price of a denom at a +// given block. +func (k Keeper) DeleteHistoricPrice( + ctx sdk.Context, + denom string, + blockNum uint64, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.GetHistoricPriceKey(denom, blockNum)) +} + +// DeleteMedian deletes a given denom's median price in the last prune +// period since a given block. +func (k Keeper) DeleteMedian( + ctx sdk.Context, + denom string, + blockNum uint64, +) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.GetMedianKey(denom, blockNum)) +} + +// 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.GetMedianDeviationKey(denom, blockNum)) +} diff --git a/x/oracle/keeper/historic_price_test.go b/x/oracle/keeper/historic_price_test.go new file mode 100644 index 0000000000..f342645895 --- /dev/null +++ b/x/oracle/keeper/historic_price_test.go @@ -0,0 +1,50 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/umee-network/umee/v3/x/oracle/types" +) + +func (s *IntegrationTestSuite) TestSetHistoraclePricing() { + app, ctx := s.app, s.ctx + + // set exchange rate in store before adding a historic price + app.OracleKeeper.SetExchangeRate(ctx, displayDenom, sdk.OneDec()) + rate, err := app.OracleKeeper.GetExchangeRate(ctx, displayDenom) + s.Require().NoError(err) + s.Require().Equal(rate, sdk.OneDec()) + + // add multiple historic prices to store + exchangeRates := []string{"1.0", "1.2", "1.1", "1.4"} + for _, exchangeRate := range exchangeRates { + app.OracleKeeper.AddHistoricPrice(ctx, displayDenom, sdk.MustNewDecFromStr(exchangeRate)) + + // update blockheight + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + } + + // set and check median and median standard deviation + app.OracleKeeper.SetMedian(ctx, displayDenom) + median, err := app.OracleKeeper.GetMedian(ctx, displayDenom, uint64(ctx.BlockHeight())) + s.Require().NoError(err) + s.Require().Equal(median, sdk.MustNewDecFromStr("1.15")) + + medianDeviation, err := app.OracleKeeper.GetMedianDeviation(ctx, displayDenom, uint64(ctx.BlockHeight())) + 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())) + + median, err = app.OracleKeeper.GetMedian(ctx, displayDenom, uint64(ctx.BlockHeight())) + 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())) + s.Require().Error(err, sdkerrors.Wrap(types.ErrUnknownDenom, displayDenom)) + s.Require().Equal(median, sdk.ZeroDec()) +} diff --git a/x/oracle/keeper/params.go b/x/oracle/keeper/params.go index cf8dad3ca3..11d228e220 100644 --- a/x/oracle/keeper/params.go +++ b/x/oracle/keeper/params.go @@ -63,6 +63,47 @@ func (k Keeper) MinValidPerWindow(ctx sdk.Context) (res sdk.Dec) { return } +// StampPeriod returns the amount of blocks the oracle module waits +// between recording a set of prices. +func (k Keeper) StampPeriod(ctx sdk.Context) (res uint64) { + k.paramSpace.Get(ctx, types.KeyStampPeriod, &res) + return +} + +// SetStampPeriod updates the amount of blocks the oracle module waits +// between recording a set of prices. +func (k Keeper) SetStampPeriod(ctx sdk.Context, stampPeriod uint64) { + k.paramSpace.Set(ctx, types.KeyStampPeriod, stampPeriod) +} + +// PrunePeriod returns the max amount of blocks that a record of the set +// of exchanges is kept. +func (k Keeper) PrunePeriod(ctx sdk.Context) (res uint64) { + k.paramSpace.Get(ctx, types.KeyPrunePeriod, &res) + return +} + +// SetPrunePeriod updates the max amount of blocks that a record of the set +// of exchanges is kept. +func (k Keeper) SetPrunePeriod(ctx sdk.Context, prunePeriod uint64) { + k.paramSpace.Set(ctx, types.KeyPrunePeriod, prunePeriod) +} + +// MedianPeriod returns the amount blocks we will wait between calculating the +// median and standard deviation of the median of historic prices in the +// last Prune Period. +func (k Keeper) MedianPeriod(ctx sdk.Context) (res uint64) { + k.paramSpace.Get(ctx, types.KeyMedianPeriod, &res) + return +} + +// MedianPeriod updates the amount blocks we will wait between calculating the +// median and standard deviation of the median of historic prices in the +// last Prune Period. +func (k Keeper) SetMedianPeriod(ctx sdk.Context, medianPeriod uint64) { + k.paramSpace.Set(ctx, types.KeyMedianPeriod, medianPeriod) +} + // GetParams returns the total set of oracle parameters. func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { k.paramSpace.GetParamSet(ctx, ¶ms) diff --git a/x/oracle/simulations/genesis.go b/x/oracle/simulations/genesis.go index 3f5b47fd97..d115c038f0 100644 --- a/x/oracle/simulations/genesis.go +++ b/x/oracle/simulations/genesis.go @@ -19,6 +19,9 @@ const ( slashFractionKey = "slash_fraction" slashWindowKey = "slash_window" minValidPerWindowKey = "min_valid_per_window" + stampPeriodKey = "stamp_period" + prunePeriodKey = "prune_period" + medianPeriodKey = "median_period" ) // GenVotePeriod produces a randomized VotePeriod in the range of [5, 100] @@ -56,6 +59,21 @@ func GenMinValidPerWindow(r *rand.Rand) sdk.Dec { return sdk.ZeroDec().Add(sdk.NewDecWithPrec(int64(r.Intn(500)), 3)) } +// GenStampPeriod produces a randomized StampPeriod in the range of [100, 1000] +func GenStampPeriod(r *rand.Rand) uint64 { + return uint64(100 + r.Intn(1000)) +} + +// GenPrunePeriod produces a randomized PrunePeriod in the range of [10001, 100000] +func GenPrunePeriod(r *rand.Rand) uint64 { + return uint64(10001 + r.Intn(100000)) +} + +// GenMedianPeriod produces a randomized MedianPeriod in the range of [1001, 10000] +func GenMedianPeriod(r *rand.Rand) uint64 { + return uint64(1001 + r.Intn(10000)) +} + // RandomizedGenState generates a random GenesisState for oracle func RandomizedGenState(simState *module.SimulationState) { var votePeriod uint64 @@ -100,6 +118,24 @@ func RandomizedGenState(simState *module.SimulationState) { func(r *rand.Rand) { minValidPerWindow = GenMinValidPerWindow(r) }, ) + var stampPeriod uint64 + simState.AppParams.GetOrGenerate( + simState.Cdc, stampPeriodKey, &stampPeriod, simState.Rand, + func(r *rand.Rand) { stampPeriod = GenStampPeriod(r) }, + ) + + var prunePeriod uint64 + simState.AppParams.GetOrGenerate( + simState.Cdc, prunePeriodKey, &prunePeriod, simState.Rand, + func(r *rand.Rand) { prunePeriod = GenPrunePeriod(r) }, + ) + + var medianPeriod uint64 + simState.AppParams.GetOrGenerate( + simState.Cdc, medianPeriodKey, &medianPeriod, simState.Rand, + func(r *rand.Rand) { medianPeriod = GenMedianPeriod(r) }, + ) + oracleGenesis := types.NewGenesisState( types.Params{ VotePeriod: votePeriod, @@ -112,6 +148,9 @@ func RandomizedGenState(simState *module.SimulationState) { SlashFraction: slashFraction, SlashWindow: slashWindow, MinValidPerWindow: minValidPerWindow, + StampPeriod: stampPeriod, + PrunePeriod: prunePeriod, + MedianPeriod: medianPeriod, }, []types.ExchangeRateTuple{}, []types.FeederDelegation{}, diff --git a/x/oracle/types/errors.go b/x/oracle/types/errors.go index 64288d6eaa..a97e9f7657 100644 --- a/x/oracle/types/errors.go +++ b/x/oracle/types/errors.go @@ -26,4 +26,6 @@ var ( ErrExistingPrevote = sdkerrors.Register(ModuleName, 15, "prevote already submitted for this voting period") ErrBallotNotSorted = sdkerrors.Register(ModuleName, 16, "ballot must be sorted before this operation") ErrNotImplemented = sdkerrors.Register(ModuleName, 17, "functon not implemented") + ErrNoMedian = sdkerrors.Register(ModuleName, 18, "no median for this denom at this block") + ErrNoMedianDeviation = sdkerrors.Register(ModuleName, 19, "no median deviation for this denom at this block") ) diff --git a/x/oracle/types/keys.go b/x/oracle/types/keys.go index 19282ff8a0..13bd80d4a6 100644 --- a/x/oracle/types/keys.go +++ b/x/oracle/types/keys.go @@ -1,6 +1,8 @@ package types import ( + "encoding/binary" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" ) @@ -23,6 +25,9 @@ var ( KeyPrefixMissCounter = []byte{0x03} // prefix for each key to a miss counter KeyPrefixAggregateExchangeRatePrevote = []byte{0x04} // prefix for each key to a aggregate prevote KeyPrefixAggregateExchangeRateVote = []byte{0x05} // prefix for each key to a aggregate vote + KeyPrefixMedian = []byte{0x06} // prefix for each key to a price median + KeyPrefixMedianDeviation = []byte{0x07} // prefix for each key to a price median standard deviation + KeyPrefixHistoricPrice = []byte{0x08} // prefix for each key to a historic price ) // GetExchangeRateKey - stored by *denom* @@ -55,3 +60,40 @@ func GetAggregateExchangeRateVoteKey(v sdk.ValAddress) (key []byte) { key = append(key, KeyPrefixAggregateExchangeRateVote...) return append(key, address.MustLengthPrefix(v)...) } + +// GetMedianKey - stored by *denom* and *block* +func GetMedianKey(denom string, blockNum uint64) (key []byte) { + key = append(key, KeyPrefixMedian...) + key = appendDenomAndBlockToKey(key, denom, blockNum) + return append(key, 0) // append 0 for null-termination +} + +// GetMedianDeviationKey - stored by *denom* and *block* +func GetMedianDeviationKey(denom string, blockNum uint64) (key []byte) { + key = append(key, KeyPrefixMedianDeviation...) + key = appendDenomAndBlockToKey(key, denom, blockNum) + return append(key, 0) // append 0 for null-termination +} + +// GetHistoricPriceKey - stored by *denom* and *block* +func GetHistoricPriceKey(denom string, blockNum uint64) (key []byte) { + key = append(key, KeyPrefixHistoricPrice...) + key = appendDenomAndBlockToKey(key, denom, blockNum) + return append(key, 0) // append 0 for null-termination +} + +func appendDenomAndBlockToKey(key []byte, denom string, blockNum uint64) []byte { + key = append(key, []byte(denom)...) + block := make([]byte, 8) + binary.LittleEndian.PutUint64(block, blockNum) + key = append(key, block...) + return key +} + +func ParseDemonFromHistoricPriceKey(key []byte) string { + return string(key[len(KeyPrefixExchangeRate) : len(key)-9]) +} + +func ParseBlockFromHistoricPriceKey(key []byte) uint64 { + return binary.LittleEndian.Uint64(key[len(key)-9 : len(key)-1]) +} diff --git a/x/oracle/types/oracle.pb.go b/x/oracle/types/oracle.pb.go index 98d4b6fab7..0bded5ff66 100644 --- a/x/oracle/types/oracle.pb.go +++ b/x/oracle/types/oracle.pb.go @@ -40,6 +40,10 @@ type Params struct { // Prune Period represents the maximum amount of blocks which we want // to keep a record of our set of exchange rates. PrunePeriod uint64 `protobuf:"varint,10,opt,name=prune_period,json=prunePeriod,proto3" json:"prune_period,omitempty"` + // Medion Period reperesents the amound blocks we will wait between + // calculating the median and standard deviation of the median of + // historic prices in the last Prune Period. + MedianPeriod uint64 `protobuf:"varint,11,opt,name=median_period,json=medianPeriod,proto3" json:"median_period,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -235,8 +239,8 @@ var xxx_messageInfo_ExchangeRateTuple proto.InternalMessageInfo // HistoricPrice is an instance of a price "stamp" type HistoricPrice struct { - ExchangeRates ExchangeRateTuple `protobuf:"bytes,1,opt,name=exchange_rates,json=exchangeRates,proto3,castrepeated=ExchangeRateTuples" json:"exchange_rates"` - BlockNum uint64 `protobuf:"varint,2,opt,name=block_num,json=blockNum,proto3" json:"block_num,omitempty"` + ExchangeRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=exchange_rate,json=exchangeRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"exchange_rate" yaml:"exchange_rate"` + BlockNum uint64 `protobuf:"varint,2,opt,name=block_num,json=blockNum,proto3" json:"block_num,omitempty"` } func (m *HistoricPrice) Reset() { *m = HistoricPrice{} } @@ -284,61 +288,62 @@ func init() { func init() { proto.RegisterFile("umee/oracle/v1/oracle.proto", fileDescriptor_8893c9e0e94ceb54) } var fileDescriptor_8893c9e0e94ceb54 = []byte{ - // 861 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xbf, 0x6f, 0xe4, 0x44, - 0x14, 0x5e, 0x73, 0x49, 0xc8, 0xce, 0xee, 0xe6, 0xc8, 0x5c, 0x02, 0x4b, 0x82, 0xd6, 0xc9, 0x20, - 0x8e, 0x34, 0xb7, 0xd6, 0x71, 0x48, 0x88, 0x74, 0x58, 0xe1, 0xa0, 0x38, 0xd0, 0x6a, 0x74, 0x3a, - 0x24, 0x1a, 0x6b, 0x6c, 0x0f, 0xbb, 0x56, 0x6c, 0x8f, 0x35, 0x33, 0xde, 0x24, 0x0d, 0x35, 0x15, - 0x42, 0x54, 0x94, 0xa9, 0xe9, 0x41, 0xfc, 0x09, 0x29, 0xaf, 0x44, 0x57, 0x18, 0x48, 0x1a, 0x6a, - 0xff, 0x05, 0x68, 0x7e, 0x6c, 0xe2, 0x4d, 0x16, 0x29, 0xd1, 0x55, 0x3b, 0xef, 0x7d, 0xef, 0xc7, - 0xf7, 0xbe, 0x99, 0xb7, 0x06, 0xdb, 0x65, 0x46, 0xa9, 0xc7, 0x38, 0x89, 0x52, 0xea, 0x4d, 0x1f, - 0xdb, 0xd3, 0xb0, 0xe0, 0x4c, 0x32, 0xb8, 0xa6, 0xc0, 0xa1, 0x75, 0x4d, 0x1f, 0x6f, 0x6d, 0x8c, - 0xd9, 0x98, 0x69, 0xc8, 0x53, 0x27, 0x13, 0x85, 0x5e, 0xad, 0x80, 0x95, 0x11, 0xe1, 0x24, 0x13, - 0xf0, 0x13, 0xd0, 0x99, 0x32, 0x49, 0x83, 0x82, 0xf2, 0x84, 0xc5, 0x7d, 0x67, 0xc7, 0xd9, 0x5b, - 0xf2, 0xdf, 0xae, 0x2b, 0x17, 0x9e, 0x90, 0x2c, 0xdd, 0x47, 0x0d, 0x10, 0x61, 0xa0, 0xac, 0x91, - 0x36, 0x60, 0x0e, 0xd6, 0x34, 0x26, 0x27, 0x9c, 0x8a, 0x09, 0x4b, 0xe3, 0xfe, 0x1b, 0x3b, 0xce, - 0x5e, 0xdb, 0xff, 0xe2, 0xac, 0x72, 0x5b, 0xaf, 0x2a, 0xf7, 0xe1, 0x38, 0x91, 0x93, 0x32, 0x1c, - 0x46, 0x2c, 0xf3, 0x22, 0x26, 0x32, 0x26, 0xec, 0xcf, 0x23, 0x11, 0x1f, 0x7a, 0xf2, 0xa4, 0xa0, - 0x62, 0x78, 0x40, 0xa3, 0xba, 0x72, 0x37, 0x1b, 0x9d, 0x2e, 0xab, 0x21, 0xdc, 0x53, 0x8e, 0xe7, - 0x33, 0x1b, 0x52, 0xd0, 0xe1, 0xf4, 0x88, 0xf0, 0x38, 0x08, 0x49, 0x1e, 0xf7, 0xef, 0xe9, 0x66, - 0x07, 0x77, 0x6e, 0x66, 0xc7, 0x6a, 0x94, 0x42, 0x18, 0x18, 0xcb, 0x27, 0x79, 0x0c, 0x23, 0xb0, - 0x65, 0xb1, 0x38, 0x11, 0x92, 0x27, 0x61, 0x29, 0x13, 0x96, 0x07, 0x47, 0x49, 0x1e, 0xb3, 0xa3, - 0xfe, 0x92, 0x96, 0xe7, 0x83, 0xba, 0x72, 0x77, 0xe7, 0xea, 0x2c, 0x88, 0x45, 0xb8, 0x6f, 0xc0, - 0x83, 0x06, 0xf6, 0x8d, 0x86, 0x60, 0x00, 0x3a, 0x24, 0x8a, 0x68, 0x21, 0x83, 0x34, 0x11, 0xb2, - 0xbf, 0xbc, 0x73, 0x6f, 0xaf, 0xf3, 0xd1, 0xe6, 0x70, 0xfe, 0xee, 0x86, 0x07, 0x34, 0x67, 0x99, - 0xff, 0xa1, 0x1a, 0xf1, 0x8a, 0x78, 0x23, 0x0f, 0xfd, 0xfa, 0x97, 0xdb, 0xd6, 0x41, 0xcf, 0x12, - 0x21, 0x31, 0x30, 0x90, 0x3a, 0xab, 0xcb, 0x11, 0x29, 0x11, 0x93, 0xe0, 0x3b, 0x4e, 0x22, 0xd5, - 0xb8, 0xbf, 0xf2, 0x7a, 0x97, 0x33, 0x5f, 0x0d, 0xe1, 0x9e, 0x76, 0x3c, 0xb5, 0x36, 0xdc, 0x07, - 0x5d, 0x13, 0x61, 0x75, 0x7a, 0x53, 0xeb, 0xf4, 0x4e, 0x5d, 0xb9, 0x0f, 0x9a, 0xf9, 0x33, 0x65, - 0x3a, 0xda, 0xb4, 0x62, 0x7c, 0x0f, 0x36, 0xb2, 0x24, 0x0f, 0xa6, 0x24, 0x4d, 0x62, 0xf5, 0xd2, - 0x66, 0x35, 0x56, 0x35, 0xe3, 0xaf, 0xee, 0xcc, 0x78, 0xdb, 0x74, 0x5c, 0x54, 0x13, 0xe1, 0xf5, - 0x2c, 0xc9, 0x5f, 0x28, 0xef, 0x88, 0x72, 0xdb, 0x7f, 0x17, 0x74, 0x85, 0x24, 0x59, 0x31, 0x5b, - 0x81, 0xb6, 0xe2, 0x8e, 0x3b, 0xda, 0x67, 0xdf, 0xfa, 0x2e, 0xe8, 0x16, 0xbc, 0xcc, 0x2f, 0xb7, - 0x04, 0x98, 0x10, 0xed, 0x33, 0x21, 0xfb, 0xab, 0xbf, 0x9c, 0xba, 0xad, 0x7f, 0x4f, 0x5d, 0x07, - 0xfd, 0xe1, 0x80, 0x65, 0x7d, 0x2b, 0xf0, 0x63, 0x00, 0x42, 0x22, 0x68, 0x10, 0x2b, 0x4b, 0xaf, - 0x56, 0xdb, 0xdf, 0xac, 0x2b, 0x77, 0xdd, 0x30, 0xbc, 0xc2, 0x10, 0x6e, 0x2b, 0xc3, 0x64, 0x29, - 0x2d, 0x4f, 0xb2, 0x90, 0xa5, 0x36, 0xcf, 0xac, 0x55, 0x53, 0xcb, 0x06, 0xaa, 0xb4, 0xd4, 0xa6, - 0xc9, 0xf5, 0xc0, 0x2a, 0x3d, 0x2e, 0x58, 0x4e, 0x73, 0xa9, 0x37, 0xa4, 0xe7, 0x3f, 0xa8, 0x2b, - 0xf7, 0xbe, 0xc9, 0x9b, 0x21, 0x08, 0x5f, 0x06, 0xed, 0x77, 0x7f, 0x38, 0x75, 0x5b, 0x96, 0x7a, - 0x0b, 0xfd, 0xe6, 0x80, 0xf7, 0x3e, 0x1b, 0x8f, 0x39, 0x1d, 0x13, 0x49, 0x3f, 0x3f, 0x8e, 0x26, - 0x24, 0x1f, 0x53, 0x4c, 0x24, 0x1d, 0x71, 0xaa, 0xb6, 0x11, 0xbe, 0x0f, 0x96, 0x26, 0x44, 0x4c, - 0xec, 0x2c, 0xf7, 0xeb, 0xca, 0xed, 0x98, 0xda, 0xca, 0x8b, 0xb0, 0x06, 0xe1, 0x43, 0xb0, 0xac, - 0x82, 0xb9, 0x65, 0xfe, 0x56, 0x5d, 0xb9, 0xdd, 0xab, 0x15, 0xe7, 0x08, 0x1b, 0x58, 0x0f, 0x5a, - 0x86, 0x59, 0x22, 0x83, 0x30, 0x65, 0xd1, 0xa1, 0x26, 0x3c, 0xff, 0x68, 0x1a, 0xa8, 0x1a, 0x54, - 0x9b, 0xbe, 0xb2, 0xae, 0xf1, 0x3e, 0x77, 0xc0, 0xbb, 0x0b, 0x79, 0xbf, 0x50, 0xa4, 0x7f, 0x74, - 0xc0, 0x06, 0xb5, 0xce, 0x80, 0x13, 0xf5, 0x2f, 0x53, 0x16, 0x29, 0x15, 0x7d, 0x47, 0xef, 0xdd, - 0xee, 0xf5, 0xbd, 0x6b, 0x16, 0x78, 0xae, 0x22, 0xfd, 0x4f, 0xed, 0x0e, 0x6e, 0xcf, 0x84, 0xbc, - 0x59, 0x4c, 0x2d, 0x23, 0xbc, 0x91, 0x29, 0x30, 0xa4, 0x37, 0x7c, 0xb7, 0x15, 0xe8, 0xda, 0x90, - 0xbf, 0x3b, 0x60, 0xfd, 0x46, 0x03, 0x55, 0xab, 0xf9, 0xbc, 0x1a, 0xb5, 0xec, 0xfb, 0x30, 0x30, - 0x3c, 0x04, 0xbd, 0x39, 0xda, 0xb6, 0xf7, 0xd3, 0x3b, 0xaf, 0xd7, 0xc6, 0x02, 0x0d, 0x10, 0xee, - 0x36, 0xc7, 0xbc, 0x46, 0xfc, 0x67, 0x07, 0xf4, 0xbe, 0x4c, 0x84, 0x64, 0x3c, 0x89, 0x46, 0x3c, - 0x89, 0x28, 0x8c, 0xc1, 0xda, 0x5c, 0xbe, 0xd0, 0xec, 0x6f, 0x75, 0x15, 0x5b, 0x8a, 0xf0, 0xff, - 0x68, 0xdd, 0x6b, 0x92, 0x10, 0x70, 0x1b, 0xb4, 0xf5, 0xd3, 0x09, 0xf2, 0xd2, 0x6c, 0xd1, 0x12, - 0x5e, 0xd5, 0x8e, 0xaf, 0xcb, 0xcc, 0x7f, 0x76, 0xf6, 0xcf, 0xa0, 0x75, 0x76, 0x3e, 0x70, 0x5e, - 0x9e, 0x0f, 0x9c, 0xbf, 0xcf, 0x07, 0xce, 0x4f, 0x17, 0x83, 0xd6, 0xcb, 0x8b, 0x41, 0xeb, 0xcf, - 0x8b, 0x41, 0xeb, 0xdb, 0x61, 0x43, 0x0e, 0x45, 0xe9, 0x51, 0x4e, 0xe5, 0x11, 0xe3, 0x87, 0xda, - 0xf0, 0xa6, 0x4f, 0xbc, 0xe3, 0xd9, 0x07, 0x58, 0x4b, 0x13, 0xae, 0xe8, 0xef, 0xea, 0x93, 0xff, - 0x02, 0x00, 0x00, 0xff, 0xff, 0x88, 0xf0, 0x5a, 0xa8, 0x9c, 0x07, 0x00, 0x00, + // 869 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xbf, 0x6f, 0x23, 0x45, + 0x14, 0xf6, 0x72, 0x49, 0x88, 0xc7, 0xf6, 0x1d, 0xd9, 0x4b, 0xc0, 0x5c, 0x90, 0x37, 0x99, 0x13, + 0x47, 0x9a, 0xb3, 0x75, 0x1c, 0x12, 0x22, 0x1d, 0xab, 0x70, 0x50, 0x1c, 0xc8, 0x1a, 0x9d, 0x0e, + 0x89, 0x66, 0x35, 0xbb, 0x3b, 0xd8, 0xa3, 0xec, 0xee, 0xac, 0x66, 0x66, 0x9d, 0xa4, 0xa1, 0xa6, + 0x42, 0x94, 0x94, 0xa9, 0xe9, 0x41, 0x34, 0xf4, 0x29, 0xaf, 0x44, 0x14, 0x0b, 0x24, 0x0d, 0xf5, + 0xfe, 0x03, 0xa0, 0xf9, 0xb1, 0xc9, 0xda, 0x71, 0x91, 0x08, 0x51, 0x79, 0xde, 0xfb, 0xde, 0x8f, + 0xef, 0xbd, 0x99, 0xcf, 0x0b, 0xb6, 0x8b, 0x94, 0x90, 0x11, 0xe3, 0x38, 0x4a, 0xc8, 0x68, 0xf6, + 0xc4, 0x9e, 0x86, 0x39, 0x67, 0x92, 0xb9, 0x77, 0x15, 0x38, 0xb4, 0xae, 0xd9, 0x93, 0x07, 0x9b, + 0x13, 0x36, 0x61, 0x1a, 0x1a, 0xa9, 0x93, 0x89, 0x82, 0xff, 0xac, 0x81, 0xb5, 0x31, 0xe6, 0x38, + 0x15, 0xee, 0x87, 0xa0, 0x33, 0x63, 0x92, 0x04, 0x39, 0xe1, 0x94, 0xc5, 0x7d, 0x67, 0xc7, 0xd9, + 0x5b, 0xf1, 0xdf, 0xac, 0x4a, 0xcf, 0x3d, 0xc1, 0x69, 0xb2, 0x0f, 0x1b, 0x20, 0x44, 0x40, 0x59, + 0x63, 0x6d, 0xb8, 0x19, 0xb8, 0xab, 0x31, 0x39, 0xe5, 0x44, 0x4c, 0x59, 0x12, 0xf7, 0x5f, 0xdb, + 0x71, 0xf6, 0xda, 0xfe, 0xa7, 0x67, 0xa5, 0xd7, 0xfa, 0xbd, 0xf4, 0x1e, 0x4d, 0xa8, 0x9c, 0x16, + 0xe1, 0x30, 0x62, 0xe9, 0x28, 0x62, 0x22, 0x65, 0xc2, 0xfe, 0x3c, 0x16, 0xf1, 0xe1, 0x48, 0x9e, + 0xe4, 0x44, 0x0c, 0x0f, 0x48, 0x54, 0x95, 0xde, 0x56, 0xa3, 0xd3, 0x65, 0x35, 0x88, 0x7a, 0xca, + 0xf1, 0xa2, 0xb6, 0x5d, 0x02, 0x3a, 0x9c, 0x1c, 0x61, 0x1e, 0x07, 0x21, 0xce, 0xe2, 0xfe, 0x1d, + 0xdd, 0xec, 0xe0, 0xd6, 0xcd, 0xec, 0x58, 0x8d, 0x52, 0x10, 0x01, 0x63, 0xf9, 0x38, 0x8b, 0xdd, + 0x08, 0x3c, 0xb0, 0x58, 0x4c, 0x85, 0xe4, 0x34, 0x2c, 0x24, 0x65, 0x59, 0x70, 0x44, 0xb3, 0x98, + 0x1d, 0xf5, 0x57, 0xf4, 0x7a, 0xde, 0xad, 0x4a, 0x6f, 0x77, 0xae, 0xce, 0x92, 0x58, 0x88, 0xfa, + 0x06, 0x3c, 0x68, 0x60, 0x5f, 0x6a, 0xc8, 0x0d, 0x40, 0x07, 0x47, 0x11, 0xc9, 0x65, 0x90, 0x50, + 0x21, 0xfb, 0xab, 0x3b, 0x77, 0xf6, 0x3a, 0xef, 0x6f, 0x0d, 0xe7, 0xef, 0x6e, 0x78, 0x40, 0x32, + 0x96, 0xfa, 0xef, 0xa9, 0x11, 0xaf, 0x88, 0x37, 0xf2, 0xe0, 0x8f, 0x7f, 0x78, 0x6d, 0x1d, 0xf4, + 0x9c, 0x0a, 0x89, 0x80, 0x81, 0xd4, 0x59, 0x5d, 0x8e, 0x48, 0xb0, 0x98, 0x06, 0x5f, 0x73, 0x1c, + 0xa9, 0xc6, 0xfd, 0xb5, 0xff, 0x76, 0x39, 0xf3, 0xd5, 0x20, 0xea, 0x69, 0xc7, 0x33, 0x6b, 0xbb, + 0xfb, 0xa0, 0x6b, 0x22, 0xec, 0x9e, 0x5e, 0xd7, 0x7b, 0x7a, 0xab, 0x2a, 0xbd, 0xfb, 0xcd, 0xfc, + 0x7a, 0x33, 0x1d, 0x6d, 0xda, 0x65, 0x7c, 0x03, 0x36, 0x53, 0x9a, 0x05, 0x33, 0x9c, 0xd0, 0x58, + 0xbd, 0xb4, 0xba, 0xc6, 0xba, 0x66, 0xfc, 0xf9, 0xad, 0x19, 0x6f, 0x9b, 0x8e, 0xcb, 0x6a, 0x42, + 0xb4, 0x91, 0xd2, 0xec, 0xa5, 0xf2, 0x8e, 0x09, 0xb7, 0xfd, 0x77, 0x41, 0x57, 0x48, 0x9c, 0xe6, + 0xb5, 0x04, 0xda, 0x8a, 0x3b, 0xea, 0x68, 0x9f, 0x7d, 0xeb, 0xbb, 0xa0, 0x9b, 0xf3, 0x22, 0xbb, + 0x54, 0x09, 0x30, 0x21, 0xda, 0x67, 0x43, 0x1e, 0x82, 0x5e, 0x4a, 0x62, 0x8a, 0xb3, 0x3a, 0xa6, + 0xa3, 0x63, 0xba, 0xc6, 0x69, 0x82, 0xf6, 0xd7, 0x7f, 0x38, 0xf5, 0x5a, 0x7f, 0x9f, 0x7a, 0x0e, + 0xfc, 0xc5, 0x01, 0xab, 0xfa, 0xea, 0xdc, 0x0f, 0x00, 0x08, 0xb1, 0x20, 0x41, 0xac, 0x2c, 0xad, + 0xbf, 0xb6, 0xbf, 0x55, 0x95, 0xde, 0x86, 0x19, 0xe3, 0x0a, 0x83, 0xa8, 0xad, 0x0c, 0x93, 0xa5, + 0x16, 0x7e, 0x92, 0x86, 0x2c, 0xb1, 0x79, 0x46, 0x7b, 0xcd, 0x85, 0x37, 0x50, 0xb5, 0x70, 0x6d, + 0x9a, 0xdc, 0x11, 0x58, 0x27, 0xc7, 0x39, 0xcb, 0x48, 0x26, 0xb5, 0x8c, 0x7a, 0xfe, 0xfd, 0xaa, + 0xf4, 0xee, 0x99, 0xbc, 0x1a, 0x81, 0xe8, 0x32, 0x68, 0xbf, 0xfb, 0xed, 0xa9, 0xd7, 0xb2, 0xd4, + 0x5b, 0xf0, 0x27, 0x07, 0xbc, 0xf3, 0xf1, 0x64, 0xc2, 0xc9, 0x04, 0x4b, 0xf2, 0xc9, 0x71, 0x34, + 0xc5, 0xd9, 0x84, 0x20, 0x2c, 0xc9, 0x98, 0x13, 0x25, 0x59, 0xf7, 0x21, 0x58, 0x99, 0x62, 0x31, + 0xb5, 0xb3, 0xdc, 0xab, 0x4a, 0xaf, 0x63, 0x6a, 0x2b, 0x2f, 0x44, 0x1a, 0x74, 0x1f, 0x81, 0x55, + 0x15, 0xcc, 0x2d, 0xf3, 0x37, 0xaa, 0xd2, 0xeb, 0x5e, 0xfd, 0x0f, 0x70, 0x88, 0x0c, 0xac, 0x07, + 0x2d, 0xc2, 0x94, 0xca, 0x20, 0x4c, 0x58, 0x74, 0xa8, 0x09, 0xcf, 0xbf, 0xac, 0x06, 0xaa, 0x06, + 0xd5, 0xa6, 0xaf, 0xac, 0x05, 0xde, 0xe7, 0x0e, 0x78, 0x7b, 0x29, 0xef, 0x97, 0x8a, 0xf4, 0x77, + 0x0e, 0xd8, 0x24, 0xd6, 0x19, 0x70, 0xac, 0xfe, 0x8a, 0x8a, 0x3c, 0x21, 0xa2, 0xef, 0x68, 0x71, + 0xee, 0x2e, 0x8a, 0xb3, 0x59, 0xe0, 0x85, 0x8a, 0xf4, 0x3f, 0xb2, 0x42, 0xdd, 0xae, 0x17, 0x79, + 0xbd, 0x98, 0x52, 0xac, 0x7b, 0x2d, 0x53, 0x20, 0x97, 0x5c, 0xf3, 0xdd, 0x74, 0x41, 0x0b, 0x43, + 0xfe, 0xec, 0x80, 0x8d, 0x6b, 0x0d, 0x54, 0xad, 0xe6, 0xf3, 0x6a, 0xd4, 0xb2, 0xef, 0xc3, 0xc0, + 0xee, 0x21, 0xe8, 0xcd, 0xd1, 0xb6, 0xbd, 0x9f, 0xdd, 0x5a, 0x83, 0x9b, 0x4b, 0x76, 0x00, 0x51, + 0xb7, 0x39, 0xe6, 0x02, 0xf1, 0x5f, 0x1d, 0xd0, 0xfb, 0x8c, 0x0a, 0xc9, 0x38, 0x8d, 0xc6, 0x9c, + 0x46, 0xfa, 0x46, 0x16, 0xd8, 0x28, 0xf6, 0x37, 0xba, 0x8a, 0xff, 0x85, 0xb0, 0xbb, 0x0d, 0xda, + 0xfa, 0x95, 0x05, 0x59, 0x61, 0x04, 0xb7, 0x82, 0xd6, 0xb5, 0xe3, 0x8b, 0x22, 0xf5, 0x9f, 0x9f, + 0xfd, 0x35, 0x68, 0x9d, 0x9d, 0x0f, 0x9c, 0x57, 0xe7, 0x03, 0xe7, 0xcf, 0xf3, 0x81, 0xf3, 0xfd, + 0xc5, 0xa0, 0xf5, 0xea, 0x62, 0xd0, 0xfa, 0xed, 0x62, 0xd0, 0xfa, 0x6a, 0xd8, 0x20, 0xa2, 0xd8, + 0x3f, 0xce, 0x88, 0x3c, 0x62, 0xfc, 0x50, 0x1b, 0xa3, 0xd9, 0xd3, 0xd1, 0x71, 0xfd, 0x41, 0xd7, + 0xa4, 0xc2, 0x35, 0xfd, 0x9d, 0x7e, 0xfa, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xde, 0x31, 0xeb, + 0x42, 0xec, 0x07, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -395,6 +400,9 @@ func (this *Params) Equal(that interface{}) bool { if this.PrunePeriod != that1.PrunePeriod { return false } + if this.MedianPeriod != that1.MedianPeriod { + return false + } return true } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -417,6 +425,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.MedianPeriod != 0 { + i = encodeVarintOracle(dAtA, i, uint64(m.MedianPeriod)) + i-- + dAtA[i] = 0x58 + } if m.PrunePeriod != 0 { i = encodeVarintOracle(dAtA, i, uint64(m.PrunePeriod)) i-- @@ -693,11 +706,11 @@ func (m *HistoricPrice) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x10 } { - size, err := m.ExchangeRates.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { + size := m.ExchangeRate.Size() + i -= size + if _, err := m.ExchangeRate.MarshalTo(dAtA[i:]); err != nil { return 0, err } - i -= size i = encodeVarintOracle(dAtA, i, uint64(size)) } i-- @@ -751,6 +764,9 @@ func (m *Params) Size() (n int) { if m.PrunePeriod != 0 { n += 1 + sovOracle(uint64(m.PrunePeriod)) } + if m.MedianPeriod != 0 { + n += 1 + sovOracle(uint64(m.MedianPeriod)) + } return n } @@ -834,7 +850,7 @@ func (m *HistoricPrice) Size() (n int) { } var l int _ = l - l = m.ExchangeRates.Size() + l = m.ExchangeRate.Size() n += 1 + l + sovOracle(uint64(l)) if m.BlockNum != 0 { n += 1 + sovOracle(uint64(m.BlockNum)) @@ -1142,6 +1158,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MedianPeriod", wireType) + } + m.MedianPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOracle + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MedianPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipOracle(dAtA[iNdEx:]) @@ -1692,7 +1727,7 @@ func (m *HistoricPrice) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ExchangeRates", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExchangeRate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1719,7 +1754,7 @@ func (m *HistoricPrice) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ExchangeRates.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ExchangeRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/oracle/types/params.go b/x/oracle/types/params.go index 9f6fa128e9..a846f2595b 100644 --- a/x/oracle/types/params.go +++ b/x/oracle/types/params.go @@ -18,6 +18,9 @@ var ( KeySlashFraction = []byte("SlashFraction") KeySlashWindow = []byte("SlashWindow") KeyMinValidPerWindow = []byte("MinValidPerWindow") + KeyStampPeriod = []byte("StampPeriod") + KeyPrunePeriod = []byte("PrunePeriod") + KeyMedianPeriod = []byte("MedianPeriod") ) // Default parameter values @@ -25,6 +28,9 @@ const ( DefaultVotePeriod = BlocksPerMinute / 2 // 30 seconds DefaultSlashWindow = BlocksPerWeek // window for a week DefaultRewardDistributionWindow = BlocksPerYear // window for a year + DefaultStampPeriod = BlocksPerHour / 2 // window for 30 minutes + DefaultPrunePeriod = BlocksPerMonth // window for a month + DefaultMedianPeriod = BlocksPerDay // window for a day ) // Default parameter values @@ -60,6 +66,9 @@ func DefaultParams() Params { SlashFraction: DefaultSlashFraction, SlashWindow: DefaultSlashWindow, MinValidPerWindow: DefaultMinValidPerWindow, + StampPeriod: DefaultStampPeriod, + PrunePeriod: DefaultPrunePeriod, + MedianPeriod: DefaultMedianPeriod, } } @@ -112,6 +121,21 @@ func (p *Params) ParamSetPairs() paramstypes.ParamSetPairs { &p.MinValidPerWindow, validateMinValidPerWindow, ), + paramstypes.NewParamSetPair( + KeyStampPeriod, + &p.StampPeriod, + validateStampPeriod, + ), + paramstypes.NewParamSetPair( + KeyPrunePeriod, + &p.PrunePeriod, + validatePrunePeriod, + ), + paramstypes.NewParamSetPair( + KeyMedianPeriod, + &p.MedianPeriod, + validateMedianPeriod, + ), } } @@ -150,6 +174,18 @@ func (p Params) Validate() error { return fmt.Errorf("oracle parameter MinValidPerWindow must be between [0, 1]") } + if p.PrunePeriod < p.StampPeriod { + return fmt.Errorf("oracle parameter PrunePeriod must be greater than or equal with StampPeriod") + } + + if p.PrunePeriod < p.MedianPeriod { + return fmt.Errorf("oracle parameter PrunePeriod must be greater than or equal with MedianPeriod") + } + + if p.MedianPeriod < p.StampPeriod { + return fmt.Errorf("oracle parameter MedianPeriod must be greater than or equal with StampPeriod") + } + for _, denom := range p.AcceptList { if len(denom.BaseDenom) == 0 { return fmt.Errorf("oracle parameter AcceptList Denom must have BaseDenom") @@ -285,3 +321,42 @@ func validateMinValidPerWindow(i interface{}) error { return nil } + +func validateStampPeriod(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v < 1 { + return fmt.Errorf("stamp period must be positive: %d", v) + } + + return nil +} + +func validatePrunePeriod(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v < 1 { + return fmt.Errorf("prune period must be positive: %d", v) + } + + return nil +} + +func validateMedianPeriod(i interface{}) error { + v, ok := i.(uint64) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v < 1 { + return fmt.Errorf("median period must be positive: %d", v) + } + + return nil +} diff --git a/x/oracle/types/params_test.go b/x/oracle/types/params_test.go index 628a6ffcda..e03aa8518b 100644 --- a/x/oracle/types/params_test.go +++ b/x/oracle/types/params_test.go @@ -121,6 +121,39 @@ func TestValidateMinValidPerWindow(t *testing.T) { require.Nil(t, err) } +func TestValidateStampPeriod(t *testing.T) { + err := validateStampPeriod("invalidUint64") + require.ErrorContains(t, err, "invalid parameter type: string") + + err = validateStampPeriod(uint64(0)) + require.ErrorContains(t, err, "stamp period must be positive: 0") + + err = validateStampPeriod(uint64(10)) + require.Nil(t, err) +} + +func TestValidatePrunePeriod(t *testing.T) { + err := validatePrunePeriod("invalidUint64") + require.ErrorContains(t, err, "invalid parameter type: string") + + err = validatePrunePeriod(uint64(0)) + require.ErrorContains(t, err, "prune period must be positive: 0") + + err = validatePrunePeriod(uint64(10)) + require.Nil(t, err) +} + +func TestValidateMedianPeriod(t *testing.T) { + err := validateMedianPeriod("invalidUint64") + require.ErrorContains(t, err, "invalid parameter type: string") + + err = validateMedianPeriod(uint64(0)) + require.ErrorContains(t, err, "median period must be positive: 0") + + err = validateMedianPeriod(uint64(10)) + require.Nil(t, err) +} + func TestParamsEqual(t *testing.T) { p1 := DefaultParams() err := p1.Validate() @@ -167,21 +200,42 @@ func TestParamsEqual(t *testing.T) { err = p7.Validate() require.Error(t, err) - // empty name + // PrunePeriod < StampPeriod + p8 := DefaultParams() + p8.StampPeriod = 10 + p8.PrunePeriod = 1 + err = p8.Validate() + require.Error(t, err) + + // PrunePeriod < MedianPeriod p9 := DefaultParams() - p9.AcceptList[0].BaseDenom = "" - p9.AcceptList[0].SymbolDenom = "ATOM" + p9.MedianPeriod = 10 + p9.PrunePeriod = 1 + err = p8.Validate() + require.Error(t, err) + + // MedianPeriod < StampPeriod + p10 := DefaultParams() + p10.StampPeriod = 10 + p10.MedianPeriod = 1 + err = p8.Validate() + require.Error(t, err) + + // empty name + p11 := DefaultParams() + p11.AcceptList[0].BaseDenom = "" + p11.AcceptList[0].SymbolDenom = "ATOM" err = p9.Validate() require.Error(t, err) // empty - p10 := DefaultParams() - p10.AcceptList[0].BaseDenom = "uatom" - p10.AcceptList[0].SymbolDenom = "" + p12 := DefaultParams() + p12.AcceptList[0].BaseDenom = "uatom" + p12.AcceptList[0].SymbolDenom = "" err = p10.Validate() require.Error(t, err) - p11 := DefaultParams() - require.NotNil(t, p11.ParamSetPairs()) - require.NotNil(t, p11.String()) + p13 := DefaultParams() + require.NotNil(t, p13.ParamSetPairs()) + require.NotNil(t, p13.String()) }