Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f071cec
Update oracle endblocker for historic pricing
rbajollari Nov 11, 2022
1869ba0
Stamp prices and set median after updating exchange rate
rbajollari Nov 13, 2022
4b46f4b
Empty-Commit
rbajollari Nov 14, 2022
a79b457
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 15, 2022
75b832c
Update endblocker based on keeper updates
rbajollari Nov 15, 2022
ee9c854
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 16, 2022
e30263d
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 17, 2022
ba20509
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 17, 2022
d15b5b0
Integrate keeper and param changes
rbajollari Nov 17, 2022
c939a47
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 17, 2022
180ee65
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 18, 2022
879271b
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 21, 2022
c3de8b6
Fix comment
rbajollari Nov 21, 2022
c779eb7
Comment out median calc and setting in endblocker
rbajollari Nov 21, 2022
68671c5
Make historacle keeper methods only called in experimental mode in or…
rbajollari Nov 21, 2022
3bef9b1
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 21, 2022
61a730f
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 22, 2022
1b3ba2a
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 22, 2022
02d813c
Add abci_test
rbajollari Nov 22, 2022
26ce029
Merge branch 'main' into ryan/historacle-endblocker
rbajollari Nov 23, 2022
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
27 changes: 26 additions & 1 deletion x/oracle/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func isPeriodLastBlock(ctx sdk.Context, blocksPerPeriod uint64) bool {
}

// EndBlocker is called at the end of every block
func EndBlocker(ctx sdk.Context, k keeper.Keeper) error {
func EndBlocker(ctx sdk.Context, k keeper.Keeper, experimental bool) error {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)

params := k.GetParams(ctx)
Expand All @@ -41,6 +41,11 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) error {

k.ClearExchangeRates(ctx)

if isPeriodLastBlock(ctx, params.MedianPeriod) && experimental {

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
k.ClearMedians(ctx)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
k.ClearMedianDeviations(ctx)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
}

// NOTE: it filters out inactive or jailed validators
ballotDenomSlice := k.OrganizeBallotByDenom(ctx, validatorClaimMap)

Expand All @@ -56,6 +61,18 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) error {
if err = k.SetExchangeRateWithEvent(ctx, ballotDenom.Denom, exchangeRate); err != nil {
return err
}

if experimental {
// Stamp rate every stamp period if asset is set to have historic stats tracked
if isPeriodLastBlock(ctx, params.StampPeriod) && params.HistoricAcceptList.Contains(ballotDenom.Denom) {

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
k.AddHistoricPrice(ctx, ballotDenom.Denom, exchangeRate)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
}

// Set median price every median period if asset is set to have historic stats tracked
if isPeriodLastBlock(ctx, params.MedianPeriod) && params.HistoricAcceptList.Contains(ballotDenom.Denom) {

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
k.CalcAndSetMedian(ctx, ballotDenom.Denom)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
}
}
}

// update miss counting & slashing
Expand Down Expand Up @@ -91,6 +108,14 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) error {
k.SlashAndResetMissCounters(ctx)
}

// Prune historic prices every prune period
if isPeriodLastBlock(ctx, params.PrunePeriod) && experimental {

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
pruneBlock := uint64(ctx.BlockHeight()) - params.PrunePeriod
for _, v := range params.HistoricAcceptList {
k.DeleteHistoricPrice(ctx, v.String(), pruneBlock)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
}
}

return nil
}

Expand Down
109 changes: 109 additions & 0 deletions x/oracle/abci_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package oracle_test

import (
"fmt"
"testing"

"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/staking/teststaking"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/crypto/secp256k1"
tmrand "github.com/tendermint/tendermint/libs/rand"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"

umeeapp "github.com/umee-network/umee/v3/app"
appparams "github.com/umee-network/umee/v3/app/params"
"github.com/umee-network/umee/v3/x/oracle"
"github.com/umee-network/umee/v3/x/oracle/types"
)

const (
displayDenom string = appparams.DisplayDenom
bondDenom string = appparams.BondDenom
)

type IntegrationTestSuite struct {
suite.Suite

ctx sdk.Context
app *umeeapp.UmeeApp
}

const (
initialPower = int64(10000000000)
)

func (s *IntegrationTestSuite) SetupTest() {
require := s.Require()
isCheckTx := false
app := umeeapp.Setup(s.T(), isCheckTx, 1)
ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{
ChainID: fmt.Sprintf("test-chain-%s", tmrand.Str(4)),
Height: int64(types.DefaultMedianPeriod) - 1,
})

oracle.InitGenesis(ctx, app.OracleKeeper, *types.DefaultGenesisState())

sh := teststaking.NewHelper(s.T(), ctx, *app.StakingKeeper)
sh.Denom = bondDenom
amt := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction)

// mint and send coins to validators
require.NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, initCoins))
require.NoError(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, initCoins))
require.NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, initCoins))
require.NoError(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr2, initCoins))

sh.CreateValidator(valAddr, valPubKey, amt, true)
sh.CreateValidator(valAddr2, valPubKey2, amt, true)

staking.EndBlocker(ctx, *app.StakingKeeper)

s.app = app
s.ctx = ctx
}

// Test addresses
var (
valPubKeys = simapp.CreateTestPubKeys(2)

valPubKey = valPubKeys[0]
pubKey = secp256k1.GenPrivKey().PubKey()
addr = sdk.AccAddress(pubKey.Address())
valAddr = sdk.ValAddress(pubKey.Address())

valPubKey2 = valPubKeys[1]
pubKey2 = secp256k1.GenPrivKey().PubKey()
addr2 = sdk.AccAddress(pubKey2.Address())
valAddr2 = sdk.ValAddress(pubKey2.Address())

initTokens = sdk.TokensFromConsensusPower(initialPower, sdk.DefaultPowerReduction)
initCoins = sdk.NewCoins(sdk.NewCoin(bondDenom, initTokens))
)

func (s *IntegrationTestSuite) TestEndblockerExperimentalFlag() {
app, ctx := s.app, s.ctx

// add historic price and calcSet median stats
app.OracleKeeper.AddHistoricPrice(s.ctx, displayDenom, sdk.MustNewDecFromStr("1.0"))
app.OracleKeeper.CalcAndSetMedian(s.ctx, displayDenom)

// with experimental flag off median stats don't get cleared
oracle.EndBlocker(ctx, app.OracleKeeper, false)
median, err := app.OracleKeeper.GetMedian(s.ctx, displayDenom)
s.Require().NoError(err)
s.Require().Equal(sdk.MustNewDecFromStr("1.0"), median)

// with experimental flag on median stats get cleared
oracle.EndBlocker(ctx, app.OracleKeeper, true)
median, err = app.OracleKeeper.GetMedian(s.ctx, displayDenom)
s.Require().Error(err)
s.Require().Equal(sdk.ZeroDec(), median)
}

func TestOracleTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
26 changes: 23 additions & 3 deletions x/oracle/keeper/historic_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,7 @@ func (k Keeper) DeleteHistoricPrice(
store.Delete(types.KeyHistoricPrice(denom, blockNum))
}

// DeleteMedian deletes a given denom's median price in the last prune
// period since a given block.
// DeleteMedian deletes a given denom's median price.
func (k Keeper) DeleteMedian(
ctx sdk.Context,
denom string,
Expand All @@ -231,11 +230,32 @@ func (k Keeper) DeleteMedian(
}

// DeleteMedianDeviation deletes a given denom's standard deviation around
// its median price in the last prune period since a given block.
// its median price.
func (k Keeper) DeleteMedianDeviation(
ctx sdk.Context,
denom string,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.KeyMedianDeviation(denom))
}

// ClearMedians iterates through all medians in the store and deletes them.
func (k Keeper) ClearMedians(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)
iter := sdk.KVStorePrefixIterator(store, types.KeyPrefixMedian)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
store.Delete(iter.Key())
}
}

// ClearMedianDeviations iterates through all median deviations in the store
// and deletes them.
func (k Keeper) ClearMedianDeviations(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)
iter := sdk.KVStorePrefixIterator(store, types.KeyPrefixMedianDeviation)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
store.Delete(iter.Key())
}
}
9 changes: 5 additions & 4 deletions x/oracle/keeper/historic_price_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ func (s *IntegrationTestSuite) TestSetHistoraclePricing() {

// 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))

for i, exchangeRate := range exchangeRates {
// update blockheight
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + int64(i))

app.OracleKeeper.AddHistoricPrice(ctx, displayDenom, sdk.MustNewDecFromStr(exchangeRate))
app.OracleKeeper.CalcAndSetMedian(ctx, displayDenom)
}

// set and check median and median standard deviation
Expand Down
2 changes: 1 addition & 1 deletion x/oracle/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
// EndBlock executes all ABCI EndBlock logic respective to the x/oracle module.
// It returns no validator updates.
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
if err := EndBlocker(ctx, am.keeper); err != nil {
if err := EndBlocker(ctx, am.keeper, am.experimental); err != nil {
panic(err)
}

Expand Down
4 changes: 4 additions & 0 deletions x/oracle/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ func (p Params) Validate() error {
return fmt.Errorf("oracle parameter MedianPeriod must be greater than or equal with StampPeriod")
}

if p.StampPeriod%p.VotePeriod != 0 || p.MedianPeriod%p.VotePeriod != 0 || p.PrunePeriod%p.VotePeriod != 0 {
return fmt.Errorf("oracle parameters StampPeriod, MedianPeriod, and PrunePeriod must be exact multiples of VotePeiod")
}

for _, denom := range p.AcceptList {
if len(denom.BaseDenom) == 0 {
return fmt.Errorf("oracle parameter AcceptList Denom must have BaseDenom")
Expand Down
29 changes: 21 additions & 8 deletions x/oracle/types/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,21 +241,34 @@ func TestParamsEqual(t *testing.T) {
err = p10.Validate()
require.Error(t, err)

// empty name
// StampPeriod, MedianPeriod, PrunePeriod are multiples of VotePeriod
p11 := DefaultParams()
p11.AcceptList[0].BaseDenom = ""
p11.AcceptList[0].SymbolDenom = "ATOM"
p11.StampPeriod = 10
p11.VotePeriod = 3
err = p11.Validate()
require.Error(t, err)
p11.MedianPeriod = 10
err = p11.Validate()
require.Error(t, err)
p11.PrunePeriod = 10
err = p11.Validate()
require.Error(t, err)

// empty
// empty name
p12 := DefaultParams()
p12.AcceptList[0].BaseDenom = "uatom"
p12.AcceptList[0].SymbolDenom = ""
p12.AcceptList[0].BaseDenom = ""
p12.AcceptList[0].SymbolDenom = "ATOM"
err = p12.Validate()
require.Error(t, err)

// empty
p13 := DefaultParams()
require.NotNil(t, p13.ParamSetPairs())
require.NotNil(t, p13.String())
p13.AcceptList[0].BaseDenom = "uatom"
p13.AcceptList[0].SymbolDenom = ""
err = p13.Validate()
require.Error(t, err)

p14 := DefaultParams()
require.NotNil(t, p14.ParamSetPairs())
require.NotNil(t, p14.String())
}