Skip to content

Commit

Permalink
fix: Enforce voting threshold param in oracle endblocker (#1707)
Browse files Browse the repository at this point in the history
* Enforce vote threshold in oracle endblocker

* Add logging

* Fix conflict issues

* pr comments

---------

Co-authored-by: Adam Wozniak <29418299+adamewozniak@users.noreply.github.com>
  • Loading branch information
rbajollari and adamewozniak committed Feb 7, 2023
1 parent 88969af commit 852ff39
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 11 deletions.
6 changes: 6 additions & 0 deletions x/oracle/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ func CalcPrices(ctx sdk.Context, params types.Params, k keeper.Keeper) error {

// Iterate through ballots and update exchange rates; drop if not enough votes have been achieved.
for _, ballotDenom := range ballotDenomSlice {
// Convert ballot power to a percentage to compare with VoteThreshold param
if sdk.NewDecWithPrec(ballotDenom.Ballot.Power(), 2).LTE(k.VoteThreshold(ctx)) {
ctx.Logger().Info("Ballot voting power is under vote threshold, dropping ballot", "denom", ballotDenom)
continue
}

denom := strings.ToUpper(ballotDenom.Denom)
// Get weighted median of exchange rates
exchangeRate, err := Tally(ballotDenom.Ballot, params.RewardBand, validatorClaimMap)
Expand Down
155 changes: 144 additions & 11 deletions x/oracle/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/staking/teststaking"
Expand Down Expand Up @@ -34,7 +35,7 @@ type IntegrationTestSuite struct {
}

const (
initialPower = int64(10000000000)
initialPower = int64(100)
)

func (s *IntegrationTestSuite) SetupTest() {
Expand All @@ -49,13 +50,15 @@ func (s *IntegrationTestSuite) SetupTest() {

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

// mint and send coins to validator
require.NoError(app.BankKeeper.MintCoins(ctx, minttypes.ModuleName, initCoins))
require.NoError(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, initCoins))
require.NoError(app.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr1, 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.CreateValidatorWithValPower(valAddr1, valPubKey1, 70, true)
sh.CreateValidatorWithValPower(valAddr2, valPubKey2, 30, true)

staking.EndBlocker(ctx, *app.StakingKeeper)

Expand All @@ -65,17 +68,147 @@ func (s *IntegrationTestSuite) SetupTest() {

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

valPubKey1 = valPubKeys[0]
pubKey1 = secp256k1.GenPrivKey().PubKey()
addr1 = sdk.AccAddress(pubKey1.Address())
valAddr1 = sdk.ValAddress(pubKey1.Address())

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) TestEndBlockerVoteThreshold() {
app, ctx := s.app, s.ctx
originalBlockHeight := ctx.BlockHeight()
ctx = ctx.WithBlockHeight(1)
preVoteBlockDiff := int64(app.OracleKeeper.VotePeriod(ctx) / 2)
voteBlockDiff := int64(app.OracleKeeper.VotePeriod(ctx)/2 + 1)

var (
val1Tuples types.ExchangeRateTuples
val2Tuples types.ExchangeRateTuples
val1PreVotes types.AggregateExchangeRatePrevote
val2PreVotes types.AggregateExchangeRatePrevote
val1Votes types.AggregateExchangeRateVote
val2Votes types.AggregateExchangeRateVote
)
for _, denom := range app.OracleKeeper.AcceptList(ctx) {
val1Tuples = append(val1Tuples, types.ExchangeRateTuple{
Denom: denom.SymbolDenom,
ExchangeRate: sdk.MustNewDecFromStr("1.0"),
})
val2Tuples = append(val2Tuples, types.ExchangeRateTuple{
Denom: denom.SymbolDenom,
ExchangeRate: sdk.MustNewDecFromStr("0.5"),
})
}

val1PreVotes = types.AggregateExchangeRatePrevote{
Hash: "hash1",
Voter: valAddr1.String(),
SubmitBlock: uint64(ctx.BlockHeight()),
}
val2PreVotes = types.AggregateExchangeRatePrevote{
Hash: "hash2",
Voter: valAddr2.String(),
SubmitBlock: uint64(ctx.BlockHeight()),
}

val1Votes = types.AggregateExchangeRateVote{
ExchangeRateTuples: val1Tuples,
Voter: valAddr1.String(),
}
val2Votes = types.AggregateExchangeRateVote{
ExchangeRateTuples: val2Tuples,
Voter: valAddr2.String(),
}

// total voting power per denom is 100%
app.OracleKeeper.SetAggregateExchangeRatePrevote(ctx, valAddr1, val1PreVotes)
app.OracleKeeper.SetAggregateExchangeRatePrevote(ctx, valAddr2, val2PreVotes)
oracle.EndBlocker(ctx, app.OracleKeeper)

ctx = ctx.WithBlockHeight(ctx.BlockHeight() + voteBlockDiff)
app.OracleKeeper.SetAggregateExchangeRateVote(ctx, valAddr1, val1Votes)
app.OracleKeeper.SetAggregateExchangeRateVote(ctx, valAddr2, val2Votes)
oracle.EndBlocker(ctx, app.OracleKeeper)

for _, denom := range app.OracleKeeper.AcceptList(ctx) {
rate, err := app.OracleKeeper.GetExchangeRate(ctx, denom.SymbolDenom)
s.Require().NoError(err)
s.Require().Equal(sdk.MustNewDecFromStr("1.0"), rate)
}

// update prevotes' block
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + preVoteBlockDiff)
val1PreVotes.SubmitBlock = uint64(ctx.BlockHeight())
val2PreVotes.SubmitBlock = uint64(ctx.BlockHeight())

// total voting power per denom is 30%
app.OracleKeeper.SetAggregateExchangeRatePrevote(ctx, valAddr2, val2PreVotes)
oracle.EndBlocker(ctx, app.OracleKeeper)

ctx = ctx.WithBlockHeight(ctx.BlockHeight() + voteBlockDiff)
app.OracleKeeper.SetAggregateExchangeRateVote(ctx, valAddr2, val2Votes)
oracle.EndBlocker(ctx, app.OracleKeeper)

for _, denom := range app.OracleKeeper.AcceptList(ctx) {
rate, err := app.OracleKeeper.GetExchangeRate(ctx, denom.SymbolDenom)
s.Require().ErrorIs(err, sdkerrors.Wrap(types.ErrUnknownDenom, denom.SymbolDenom))
s.Require().Equal(sdk.ZeroDec(), rate)
}

// update prevotes' block
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + preVoteBlockDiff)
val1PreVotes.SubmitBlock = uint64(ctx.BlockHeight())
val2PreVotes.SubmitBlock = uint64(ctx.BlockHeight())

// umee has 100% power, and atom has 30%
val1Tuples = types.ExchangeRateTuples{
types.ExchangeRateTuple{
Denom: "umee",
ExchangeRate: sdk.MustNewDecFromStr("1.0"),
},
}
val2Tuples = types.ExchangeRateTuples{
types.ExchangeRateTuple{
Denom: "umee",
ExchangeRate: sdk.MustNewDecFromStr("0.5"),
},
types.ExchangeRateTuple{
Denom: "atom",
ExchangeRate: sdk.MustNewDecFromStr("0.5"),
},
}
val1Votes.ExchangeRateTuples = val1Tuples
val2Votes.ExchangeRateTuples = val2Tuples

app.OracleKeeper.SetAggregateExchangeRatePrevote(ctx, valAddr1, val1PreVotes)
app.OracleKeeper.SetAggregateExchangeRatePrevote(ctx, valAddr2, val2PreVotes)
oracle.EndBlocker(ctx, app.OracleKeeper)

ctx = ctx.WithBlockHeight(ctx.BlockHeight() + voteBlockDiff)
app.OracleKeeper.SetAggregateExchangeRateVote(ctx, valAddr1, val1Votes)
app.OracleKeeper.SetAggregateExchangeRateVote(ctx, valAddr2, val2Votes)
oracle.EndBlocker(ctx, app.OracleKeeper)

rate, err := app.OracleKeeper.GetExchangeRate(ctx, "umee")
s.Require().NoError(err)
s.Require().Equal(sdk.MustNewDecFromStr("1.0"), rate)
rate, err = app.OracleKeeper.GetExchangeRate(ctx, "atom")
s.Require().ErrorIs(err, sdkerrors.Wrap(types.ErrUnknownDenom, "atom"))
s.Require().Equal(sdk.ZeroDec(), rate)

ctx = ctx.WithBlockHeight(originalBlockHeight)
}

var exchangeRates = map[string][]sdk.Dec{
"ATOM": {
sdk.MustNewDecFromStr("12.99"),
Expand Down Expand Up @@ -126,9 +259,9 @@ func (s *IntegrationTestSuite) TestEndblockerHistoracle() {

vote := types.AggregateExchangeRateVote{
ExchangeRateTuples: tuples,
Voter: valAddr.String(),
Voter: valAddr1.String(),
}
app.OracleKeeper.SetAggregateExchangeRateVote(ctx, valAddr, vote)
app.OracleKeeper.SetAggregateExchangeRateVote(ctx, valAddr1, vote)
oracle.EndBlocker(ctx, app.OracleKeeper)
}

Expand Down

0 comments on commit 852ff39

Please sign in to comment.