Skip to content

Commit

Permalink
chore(tests): Add checks to oracle ABCI test (#1724)
Browse files Browse the repository at this point in the history
* add checks to oracle abci test
  • Loading branch information
zarazan authored Jan 19, 2023
1 parent 13c2a19 commit 38c2d04
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 68 deletions.
30 changes: 5 additions & 25 deletions x/oracle/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,12 @@ import (
"github.com/umee-network/umee/v4/x/oracle/types"
)

// isPeriodLastBlock returns true if we are at the last block of the period
func isPeriodLastBlock(ctx sdk.Context, blocksPerPeriod uint64) bool {
return (uint64(ctx.BlockHeight())+1)%blocksPerPeriod == 0
}

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

params := k.GetParams(ctx)
if isPeriodLastBlock(ctx, params.VotePeriod) {
if k.IsPeriodLastBlock(ctx, params.VotePeriod) {
// Build claim map over all validators in active set
validatorClaimMap := make(map[string]types.Claim)
powerReduction := k.StakingKeeper.PowerReduction(ctx)
Expand Down Expand Up @@ -59,12 +54,12 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) error {
return err
}

if isPeriodLastBlock(ctx, params.HistoricStampPeriod) {
if k.IsPeriodLastBlock(ctx, params.HistoricStampPeriod) {
k.AddHistoricPrice(ctx, denom, exchangeRate)
}

// Calculate and stamp median/median deviation if median stamp period has passed
if isPeriodLastBlock(ctx, params.MedianStampPeriod) {
if k.IsPeriodLastBlock(ctx, params.MedianStampPeriod) {
if err = k.CalcAndSetHistoricMedian(ctx, denom); err != nil {
return err
}
Expand Down Expand Up @@ -100,26 +95,11 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) error {

// Slash oracle providers who missed voting over the threshold and
// reset miss counters of all validators at the last block of slash window
if isPeriodLastBlock(ctx, params.SlashWindow) {
if k.IsPeriodLastBlock(ctx, params.SlashWindow) {
k.SlashAndResetMissCounters(ctx)
}

// Prune historic prices and medians outside pruning period determined by
// the stamp period multiplied by the max stamps.
if isPeriodLastBlock(ctx, params.HistoricStampPeriod) {
pruneHistoricPeriod := params.HistoricStampPeriod * params.MaximumPriceStamps
if pruneHistoricPeriod < uint64(ctx.BlockHeight()) {
k.PruneHistoricPricesBeforeBlock(ctx, uint64(ctx.BlockHeight())-pruneHistoricPeriod)
}

if isPeriodLastBlock(ctx, params.MedianStampPeriod) {
pruneMedianPeriod := params.MedianStampPeriod * params.MaximumMedianStamps
if pruneMedianPeriod < uint64(ctx.BlockHeight()) {
k.PruneMediansBeforeBlock(ctx, uint64(ctx.BlockHeight())-pruneMedianPeriod)
k.PruneMedianDeviationsBeforeBlock(ctx, uint64(ctx.BlockHeight())-pruneMedianPeriod)
}
}
}
k.PruneAllPrices(ctx)

return nil
}
Expand Down
53 changes: 46 additions & 7 deletions x/oracle/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (s *IntegrationTestSuite) TestEndblockerHistoracle() {
var historicStampPeriod int64 = 5
var medianStampPeriod int64 = 20
var maximumPriceStamps int64 = 4
var maximumMedianStamps int64 = 5
var maximumMedianStamps int64 = 3

app.OracleKeeper.SetHistoricStampPeriod(ctx, uint64(historicStampPeriod))
app.OracleKeeper.SetMedianStampPeriod(ctx, uint64(medianStampPeriod))
Expand Down Expand Up @@ -132,15 +132,54 @@ func (s *IntegrationTestSuite) TestEndblockerHistoracle() {
oracle.EndBlocker(ctx, app.OracleKeeper)
}

for denom, _ := range exchangeRates {
// check medians
expectedMedian, err := decmath.Median(exchangeRates[denom])
medians := app.OracleKeeper.HistoricMedians(ctx, denom, uint64(maximumPriceStamps))
for denom, denomRates := range exchangeRates {
// check median
expectedMedian, err := decmath.Median(denomRates)
s.Require().NoError(err)
actualMedian := (*medians.AtBlock(uint64(blockHeight)))[0].ExchangeRateTuple.ExchangeRate
s.Require().Equal(actualMedian, expectedMedian)

medians := app.OracleKeeper.AllMedianPrices(ctx)
medians = *medians.FilterByBlock(uint64(blockHeight)).FilterByDenom(denom)
actualMedian := medians[0].ExchangeRateTuple.ExchangeRate
s.Require().Equal(expectedMedian, actualMedian)

// check median deviation
expectedMedianDeviation, err := decmath.MedianDeviation(actualMedian, denomRates)
s.Require().NoError(err)

medianDeviations := app.OracleKeeper.AllMedianDeviationPrices(ctx)
medianDeviations = *medianDeviations.FilterByBlock(uint64(blockHeight)).FilterByDenom(denom)
actualMedianDeviation := medianDeviations[0].ExchangeRateTuple.ExchangeRate
s.Require().Equal(expectedMedianDeviation, actualMedianDeviation)
}
}
numberOfAssets := int64(len(exchangeRates))

historicPrices := app.OracleKeeper.AllHistoricPrices(ctx)
s.Require().Equal(maximumPriceStamps*numberOfAssets, int64(len(historicPrices)))

for i := int64(0); i < maximumPriceStamps; i++ {
expectedBlockNum := blockHeight - (historicStampPeriod * (maximumPriceStamps - int64(i+1)))
actualBlockNum := historicPrices[i].BlockNum
s.Require().Equal(expectedBlockNum, int64(actualBlockNum))
}

medians := app.OracleKeeper.AllMedianPrices(ctx)
s.Require().Equal(maximumMedianStamps*numberOfAssets, int64(len(medians)))

for i := int64(0); i < maximumMedianStamps; i++ {
expectedBlockNum := blockHeight - (medianStampPeriod * (maximumMedianStamps - int64(i+1)))
actualBlockNum := medians[i].BlockNum
s.Require().Equal(expectedBlockNum, int64(actualBlockNum))
}

medianDeviations := app.OracleKeeper.AllMedianPrices(ctx)
s.Require().Equal(maximumMedianStamps*numberOfAssets, int64(len(medianDeviations)))

for i := int64(0); i < maximumMedianStamps; i++ {
expectedBlockNum := blockHeight - (medianStampPeriod * (maximumMedianStamps - int64(i+1)))
actualBlockNum := medianDeviations[i].BlockNum
s.Require().Equal(expectedBlockNum, int64(actualBlockNum))
}
}

func TestOracleTestSuite(t *testing.T) {
Expand Down
29 changes: 3 additions & 26 deletions x/oracle/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,32 +135,9 @@ func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
},
)

historicPrices := []types.Price{}
keeper.IterateAllHistoricPrices(
ctx,
func(historicPrice types.Price) bool {
historicPrices = append(historicPrices, historicPrice)
return false
},
)

medianPrices := []types.Price{}
keeper.IterateAllMedianPrices(
ctx,
func(medianPrice types.Price) bool {
medianPrices = append(medianPrices, medianPrice)
return false
},
)

medianDeviationPrices := []types.Price{}
keeper.IterateAllMedianDeviationPrices(
ctx,
func(medianDeviationPrice types.Price) bool {
medianDeviationPrices = append(medianDeviationPrices, medianDeviationPrice)
return false
},
)
historicPrices := keeper.AllHistoricPrices(ctx)
medianPrices := keeper.AllMedianPrices(ctx)
medianDeviationPrices := keeper.AllMedianDeviationPrices(ctx)

return types.NewGenesisState(
params,
Expand Down
32 changes: 32 additions & 0 deletions x/oracle/keeper/end_blocker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// PruneAllPrices deletes all historic prices, medians, and median deviations
// outside pruning period determined by the stamp period multiplied by the maximum stamps.
func (k *Keeper) PruneAllPrices(ctx sdk.Context) {
params := k.GetParams(ctx)
blockHeight := uint64(ctx.BlockHeight())

if k.IsPeriodLastBlock(ctx, params.HistoricStampPeriod) {
pruneHistoricPeriod := params.HistoricStampPeriod * params.MaximumPriceStamps
if pruneHistoricPeriod < blockHeight {
k.PruneHistoricPricesBeforeBlock(ctx, blockHeight-pruneHistoricPeriod)
}

if k.IsPeriodLastBlock(ctx, params.MedianStampPeriod) {
pruneMedianPeriod := params.MedianStampPeriod * params.MaximumMedianStamps
if pruneMedianPeriod < blockHeight {
k.PruneMediansBeforeBlock(ctx, blockHeight-pruneMedianPeriod)
k.PruneMedianDeviationsBeforeBlock(ctx, blockHeight-pruneMedianPeriod)
}
}
}
}

// IsPeriodLastBlock returns true if we are at the last block of the period
func (k *Keeper) IsPeriodLastBlock(ctx sdk.Context, blocksPerPeriod uint64) bool {
return (uint64(ctx.BlockHeight())+1)%blocksPerPeriod == 0
}
33 changes: 33 additions & 0 deletions x/oracle/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ func (k Keeper) IterateAllHistoricPrices(
}
}

// AllHistoricPrices is a helper function that collects and returns all
// median prices using the IterateAllHistoricPrices iterator
func (k Keeper) AllHistoricPrices(ctx sdk.Context) types.Prices {
prices := types.Prices{}
k.IterateAllHistoricPrices(ctx, func(median types.Price) (stop bool) {
prices = append(prices, median)
return false
})
return prices
}

// IterateAllMedianPrices iterates over all median prices.
// Iterator stops when exhausting the source, or when the handler returns `true`.
func (k Keeper) IterateAllMedianPrices(
Expand All @@ -54,6 +65,17 @@ func (k Keeper) IterateAllMedianPrices(
}
}

// AllMedianPrices is a helper function that collects and returns all
// median prices using the IterateAllMedianPrices iterator
func (k Keeper) AllMedianPrices(ctx sdk.Context) types.Prices {
prices := types.Prices{}
k.IterateAllMedianPrices(ctx, func(median types.Price) (stop bool) {
prices = append(prices, median)
return false
})
return prices
}

// IterateAllMedianDeviationPrices iterates over all median deviation prices.
// Iterator stops when exhausting the source, or when the handler returns `true`.
func (k Keeper) IterateAllMedianDeviationPrices(
Expand All @@ -78,3 +100,14 @@ func (k Keeper) IterateAllMedianDeviationPrices(
}
}
}

// AllMedianDeviationPrices is a helper function that collects and returns
// all median prices using the IterateAllMedianDeviationPrices iterator
func (k Keeper) AllMedianDeviationPrices(ctx sdk.Context) types.Prices {
prices := types.Prices{}
k.IterateAllMedianDeviationPrices(ctx, func(median types.Price) (stop bool) {
prices = append(prices, median)
return false
})
return prices
}
11 changes: 2 additions & 9 deletions x/oracle/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,7 @@ func (q querier) Medians(

medians = q.HistoricMedians(ctx, req.Denom, uint64(req.NumStamps))
} else {
q.IterateAllMedianPrices(ctx, func(median types.Price) (stop bool) {
medians = append(medians, median)
return false
})
medians = q.AllMedianPrices(ctx)
}

return &types.QueryMediansResponse{Medians: *medians.Sort()}, nil
Expand All @@ -303,13 +300,9 @@ func (q querier) MedianDeviations(
if err != nil {
return nil, err
}

medianDeviations = append(medianDeviations, *price)
} else {
q.IterateAllMedianDeviationPrices(ctx, func(medianDeviation types.Price) (stop bool) {
medianDeviations = append(medianDeviations, medianDeviation)
return false
})
medianDeviations = q.AllMedianDeviationPrices(ctx)
}

return &types.QueryMedianDeviationsResponse{MedianDeviations: *medianDeviations.Sort()}, nil
Expand Down
12 changes: 11 additions & 1 deletion x/oracle/types/price.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (p *Prices) Decs() []sdk.Dec {
return decs
}

func (p *Prices) AtBlock(blockNum uint64) *Prices {
func (p *Prices) FilterByBlock(blockNum uint64) *Prices {
prices := Prices{}
for _, price := range *p {
if price.BlockNum == blockNum {
Expand All @@ -36,6 +36,16 @@ func (p *Prices) AtBlock(blockNum uint64) *Prices {
return &prices
}

func (p *Prices) FilterByDenom(denom string) *Prices {
prices := Prices{}
for _, price := range *p {
if price.ExchangeRateTuple.Denom == denom {
prices = append(prices, price)
}
}
return &prices
}

func (p *Prices) Sort() *Prices {
prices := *p
sort.Slice(
Expand Down

0 comments on commit 38c2d04

Please sign in to comment.