Skip to content

Commit

Permalink
Distribution, expand the ignored distributios set (#7250)
Browse files Browse the repository at this point in the history
* Expand spam filter

* Update comment

* add changelog

* add skipSpamGaugeDistribute test

* lint

---------

Co-authored-by: Adam Tucker <[email protected]>
Co-authored-by: Matt, Park <[email protected]>
Co-authored-by: Adam Tucker <[email protected]>
  • Loading branch information
4 people authored Feb 10, 2024
1 parent 1eb716f commit c281f0a
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* [#7181](https://github.com/osmosis-labs/osmosis/pull/7181) Improve errors for out of gas
* [#7357](https://github.com/osmosis-labs/osmosis/pull/7357) Fix: Ensure rate limits are not applied to packets that aren't ics20s
* [#7250](https://github.com/osmosis-labs/osmosis/pull/7250) Further filter spam gauges from epoch distribution.

### Bug Fixes

Expand Down
43 changes: 25 additions & 18 deletions x/incentives/keeper/distribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,24 +677,9 @@ func (k Keeper) distributeInternal(
}
} else {
// This is a standard lock distribution flow that assumes that we have locks associated with the gauge.
if len(locks) == 0 {
return nil, nil
}

// In this case, remove redundant cases.
// Namely: gauge empty OR gauge coins undistributable.
if remainCoins.Empty() {
ctx.Logger().Debug(fmt.Sprintf("gauge debug, this gauge is empty, why is it being ran %d. Balancer code", gauge.Id))
err := k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins)
return totalDistrCoins, err
}

// Remove some spam gauges, is state compatible.
// If they're to pool 1 they can't distr at this small of a quantity.
if remainCoins.Len() == 1 && remainCoins[0].Amount.LTE(osmomath.NewInt(10)) && gauge.DistributeTo.Denom == "gamm/pool/1" && remainCoins[0].Denom != "uosmo" {
ctx.Logger().Debug(fmt.Sprintf("gauge debug, this gauge is perceived spam, skipping %d", gauge.Id))
err := k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins)
return totalDistrCoins, err
isSpam, totaltotalDistrCoins, err := k.skipSpamGaugeDistribute(ctx, locks, gauge, totalDistrCoins, remainCoins)
if isSpam {
return totaltotalDistrCoins, err
}

// This is a standard lock distribution flow that assumes that we have locks associated with the gauge.
Expand Down Expand Up @@ -757,6 +742,28 @@ func (k Keeper) distributeInternal(
return totalDistrCoins, err
}

func (k Keeper) skipSpamGaugeDistribute(ctx sdk.Context, locks []*lockuptypes.PeriodLock, gauge types.Gauge, totalDistrCoins sdk.Coins, remainCoins sdk.Coins) (bool, sdk.Coins, error) {
if len(locks) == 0 {
return true, nil, nil
}

// In this case, remove redundant cases.
// Namely: gauge empty OR gauge coins undistributable.
if remainCoins.Empty() {
ctx.Logger().Debug(fmt.Sprintf("gauge debug, this gauge is empty, why is it being ran %d. Balancer code", gauge.Id))
err := k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins)
return true, totalDistrCoins, err
}

// Remove some spam gauges that are not worth distributing. (We ignore the denom stake because of tests.)
if remainCoins.Len() == 1 && remainCoins[0].Amount.LTE(osmomath.NewInt(100)) && remainCoins[0].Denom != "stake" {
ctx.Logger().Debug(fmt.Sprintf("gauge debug, this gauge is perceived spam, skipping %d", gauge.Id))
err := k.updateGaugePostDistribute(ctx, gauge, totalDistrCoins)
return true, totalDistrCoins, err
}
return false, totalDistrCoins, nil
}

// faster coins.AmountOf if we know that coins must contain the denom.
// returns a new big int that can be mutated.
func guaranteedNonzeroCoinAmountOf(coins sdk.Coins, denom string) osmomath.Int {
Expand Down
90 changes: 90 additions & 0 deletions x/incentives/keeper/distribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2548,3 +2548,93 @@ func (s *KeeperTestSuite) TestGetNoLockGaugeUptime() {
})
}
}

func (s *KeeperTestSuite) TestSkipSpamGaugeDistribute() {
defaultGauge := perpGaugeDesc{
lockDenom: defaultLPDenom,
lockDuration: defaultLockDuration,
rewardAmount: sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 3000)},
}

tenCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 10)}
oneKCoins := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 1000)}
twoCoinsOneK := sdk.Coins{sdk.NewInt64Coin(defaultRewardDenom, 1000), sdk.NewInt64Coin("uosmo", 1000)}
tests := []struct {
name string
locks []*lockuptypes.PeriodLock
gauge perpGaugeDesc
totalDistrCoins sdk.Coins
remainCoins sdk.Coins
expectedToSkip bool
expectedTotalDistrCoins sdk.Coins
expectedGaugeUpdated bool
}{
{
name: "Lock length of 0, should be skipped",
locks: []*lockuptypes.PeriodLock{},
gauge: defaultGauge,
totalDistrCoins: oneKCoins,
remainCoins: sdk.Coins{},
expectedToSkip: true,
expectedTotalDistrCoins: nil,
expectedGaugeUpdated: false,
},
{
name: "Empty remainCoins, should be skipped",
locks: []*lockuptypes.PeriodLock{
{ID: 1, Owner: string(s.TestAccs[0]), Coins: oneKCoins, Duration: defaultLockDuration},
},
gauge: defaultGauge,
totalDistrCoins: oneKCoins,
remainCoins: sdk.Coins{},
expectedToSkip: true,
expectedTotalDistrCoins: oneKCoins,
expectedGaugeUpdated: true,
},
{
name: "Remain coins len == 1 and value less than 100 threshold, should be skipped",
locks: []*lockuptypes.PeriodLock{
{ID: 1, Owner: string(s.TestAccs[0]), Coins: oneKCoins, Duration: defaultLockDuration},
},
gauge: defaultGauge,
totalDistrCoins: oneKCoins,
remainCoins: tenCoins,
expectedToSkip: true,
expectedTotalDistrCoins: oneKCoins,
expectedGaugeUpdated: true,
},
{
name: "Lock length > 0, gauge value greater than 100 threshold, and remain coins len != 1, should not be skipped",
locks: []*lockuptypes.PeriodLock{
{ID: 1, Owner: string(s.TestAccs[0]), Coins: oneKCoins, Duration: defaultLockDuration},
},
gauge: defaultGauge,
totalDistrCoins: oneKCoins,
remainCoins: twoCoinsOneK,
expectedToSkip: false,
expectedTotalDistrCoins: oneKCoins,
expectedGaugeUpdated: false,
},
}
for _, tc := range tests {
s.SetupTest()
// setup gauge defined in test case
gauges := s.SetupGauges([]perpGaugeDesc{tc.gauge}, defaultLPDenom)

shouldBeSkipped, distrCoins, err := s.App.IncentivesKeeper.SkipSpamGaugeDistribute(s.Ctx, tc.locks, gauges[0], tc.totalDistrCoins, tc.remainCoins)
s.Require().NoError(err)
s.Require().Equal(tc.expectedToSkip, shouldBeSkipped)
s.Require().Equal(tc.expectedTotalDistrCoins, distrCoins)

// Retrieve gauge
gauge, err := s.App.IncentivesKeeper.GetGaugeByID(s.Ctx, gauges[0].Id)
s.Require().NoError(err)

expectedGauge := gauges[0]
if tc.expectedGaugeUpdated {
expectedGauge.FilledEpochs++
expectedGauge.DistributedCoins = expectedGauge.DistributedCoins.Add(distrCoins...)
}
s.Require().Equal(expectedGauge, *gauge)
}
}
5 changes: 5 additions & 0 deletions x/incentives/keeper/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/osmosis-labs/osmosis/osmomath"
"github.com/osmosis-labs/osmosis/v23/x/incentives/types"
lockuptypes "github.com/osmosis-labs/osmosis/v23/x/lockup/types"
)

var ByGroupQueryCondition = byGroupQueryCondition
Expand Down Expand Up @@ -101,3 +102,7 @@ func (k Keeper) CalculateGroupWeights(ctx sdk.Context, group types.Group) (types
func (k Keeper) GetNoLockGaugeUptime(ctx sdk.Context, gauge types.Gauge, poolId uint64) time.Duration {
return k.getNoLockGaugeUptime(ctx, gauge, poolId)
}

func (k Keeper) SkipSpamGaugeDistribute(ctx sdk.Context, locks []*lockuptypes.PeriodLock, gauge types.Gauge, totalDistrCoins sdk.Coins, remainCoins sdk.Coins) (bool, sdk.Coins, error) {
return k.skipSpamGaugeDistribute(ctx, locks, gauge, totalDistrCoins, remainCoins)
}

0 comments on commit c281f0a

Please sign in to comment.