-
Notifications
You must be signed in to change notification settings - Fork 592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: scaling factor for pool uptime accumulator to avoid truncation #7409
Conversation
if incentiveCoin.Amount.IsPositive() { | ||
collectedIncentivesForUptime = append(collectedIncentivesForUptime, incentiveCoin) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this to handle the case is which, even after scaling, we still truncate to zero?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. It doesn't make sense to collect a bunch of zero coins so decided to simply skip them
poolIncentiveRecords: []types.IncentiveRecord{withEmissionRate(incentiveRecordOne, oneE60Dec), incentiveRecordOne}, | ||
|
||
expectedResult: sdk.DecCoins{ | ||
// We only expect the first incentive record to qualify |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We expect both to qualify, just the first is the only that should emit, right? I think the comment might just be wrong here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right except only the second one qualifies since the first one truncates.
Corrected here: 8a43a0b
@@ -2898,7 +2938,7 @@ func (s *KeeperTestSuite) TestQueryAndClaimAllIncentives() { | |||
for _, growthInside := range tc.growthInside { | |||
expectedCoins = expectedCoins.Add(sdk.NormalizeCoins(growthInside)...) | |||
} | |||
s.Require().Equal(expectedCoins, amountClaimed) | |||
s.Require().Equal(expectedCoins.String(), amountClaimed.String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clear indicator there was some debugging going on here 😂
// We multiply the current tick liqudity by this factor | ||
// To bring the current tick liquidity to be at the border line of truncating. | ||
// Then, we choose values on each side of the threshold to show that truncation is still possible | ||
// but, with the scaling factor, it is less likely to occur due to more room for liquidity to grow. | ||
currentTickLiquidityIncreaseFactor := osmomath.BigDecFromDec(cl.PerUnitLiqScalingFactor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we able to write out somewhere what exactly these limits are? As in, are we just buying time and if a pool gets 100M liquidity we are back in the same boat, or is the liquidity unlikely (something like 1T for a single pool?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The analysis is in the appendix of the hack md linked in the PR description.
In a sense, if liquidity growths infinitely, the limit will be hit again.
However, we have alerts in-place. Also, the buffer should be sufficient based on analysis.
Going higher with the scaling factor is also risky because, then, we would be running into overflows
@@ -3615,8 +3672,35 @@ func (s *KeeperTestSuite) TestIncentiveTruncation() { | |||
s.Require().True(incentives.IsZero()) | |||
|
|||
// Incentives should now be claimed due to lack of truncation | |||
s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(time.Minute * 51)) | |||
s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(time.Hour * 6)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the change of this value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current tick liquidity and scaling factor value were changed so this threshold changes as well.
The goal is to show that with the increased scaling factor, we do not get a truncation within the expected range of increase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really great work with this, super clear. IMO we should have at minimum 2 approvals on this prior to merge, 3 would be ideal but if we need to move fast I think 2 will suffice.
// Total amount emitted = time elapsed * emission | ||
totalEmittedAmount := timeElapsed.Mul(incentiveRecordBody.EmissionRate) | ||
totalEmittedAmount := timeElapsed.MulTruncate(incentiveRecordBody.EmissionRate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to future proof this a bit more, thoughts on adding comments in line here for the expected range of each term?
This is basically whats blocking approve for me rn (trying to rederive these)
Actual scale-up change LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attempted to address here:
9e10789
Let me know what you think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Core scaling logic looks good to me, but had a clarifying question about how pools besides the ones being migrated are being handled
app/apptesting/test_suite.go
Outdated
@@ -696,3 +696,11 @@ func (s *KeeperTestHelper) SetupVolumeForPools(poolIDs []uint64, volumesForEachP | |||
func (s *KeeperTestHelper) IncreaseVolumeForPools(poolIDs []uint64, volumesForEachPool []osmomath.Int) { | |||
s.SetupVolumeForPools(poolIDs, volumesForEachPool, map[uint64]osmomath.Int{}) | |||
} | |||
|
|||
// CompareDecCoinsSlice compares two slices of DecCoins | |||
func (s *KeeperTestHelper) CompareDecCoinsSlice(expected, actual []sdk.DecCoins) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: something along the lines of RequireDecCoinsSlice
seems more accurate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, although I did not think deeply about implications of this change on existing state beyond our brief offline discussion, as it seems that is the focus #7416
…7409) * feat: scaling factor for pool uptime accumulator * changelog * updates * updates * handle overflows * Apply suggestions from code review * updates * Apply suggestions from code review * fix test and clean up * spelling * future proof multiplication overflow * clean up * comment * lint * rename
Closes: #XXX ## What is the purpose of the change This PR introduces incentive accumulator migration to address the truncation issue with pool 1423. In the v23 upgrade, we introduce a scaling factor to avoid truncating the per-unit-of-liquidity incentive accumulator. See: #7409 The goal is to have all the newly created pools utilize this accumulator. At the same time, we want to migrate the old pools that are currently affected (e.g. pool 1423). We also want to migrate only the affected pools to limit migration risk. To achieve all of the above, this PR: - Introduces a pool ID threshold snapshotted during the upgrade to state. After this threshold, all newly created pools utilize the scaling factor. - A hard-coded map of pool IDs that are below the threshold but migrated to the scaling factor logic In the core module logic, we dynamically select the scaling factor based on the pool ID to apply to the accumulator. Given successful migration, we will migrate the remaining pools in a future upgrade. ### Testnet Pool ID threshold is selected dynamically based on either mainnet or testnet state. For any environment other than `osmosis-1`, we avoid performing pool migration to avoid dealing with complexity. This is. fine as we don't care about other environments potentially truncating with older pools. ## Testing and Verifying - [ ] Test core helpers - [ ] Test upgrade handler - [ ] Test genesis ## Documentation and Release Note - [ ] Does this pull request introduce a new feature or user-facing behavior changes? - [ ] Changelog entry added to `Unreleased` section of `CHANGELOG.md`? Where is the change documented? - [ ] Specification (`x/{module}/README.md`) - [ ] Osmosis documentation site - [ ] Code comments? - [ ] N/A
Closes: #XXX ## What is the purpose of the change This PR introduces incentive accumulator migration to address the truncation issue with pool 1423. In the v23 upgrade, we introduce a scaling factor to avoid truncating the per-unit-of-liquidity incentive accumulator. See: #7409 The goal is to have all the newly created pools utilize this accumulator. At the same time, we want to migrate the old pools that are currently affected (e.g. pool 1423). We also want to migrate only the affected pools to limit migration risk. To achieve all of the above, this PR: - Introduces a pool ID threshold snapshotted during the upgrade to state. After this threshold, all newly created pools utilize the scaling factor. - A hard-coded map of pool IDs that are below the threshold but migrated to the scaling factor logic In the core module logic, we dynamically select the scaling factor based on the pool ID to apply to the accumulator. Given successful migration, we will migrate the remaining pools in a future upgrade. ### Testnet Pool ID threshold is selected dynamically based on either mainnet or testnet state. For any environment other than `osmosis-1`, we avoid performing pool migration to avoid dealing with complexity. This is. fine as we don't care about other environments potentially truncating with older pools. ## Testing and Verifying - [ ] Test core helpers - [ ] Test upgrade handler - [ ] Test genesis ## Documentation and Release Note - [ ] Does this pull request introduce a new feature or user-facing behavior changes? - [ ] Changelog entry added to `Unreleased` section of `CHANGELOG.md`? Where is the change documented? - [ ] Specification (`x/{module}/README.md`) - [ ] Osmosis documentation site - [ ] Code comments? - [ ] N/A (cherry picked from commit b0d3ff9) # Conflicts: # go.mod # go.sum
What is the purpose of the change
This is a solution to avoid truncation of the pool reward accumulator to zero when liquidity is large.
It focuses on defining the core of the scaling factor solution (task ref) and also implementing and testing logic for silently skipping incentive overflows (task ref).
Initial analysis of the approach was done here: https://hackmd.io/o3oqT8VhSPKAiqNl_mlxXQ
To be implemented next:
We should also analyze whether it makes sense to implement something similar for the spread rewards accumulator by inspecting the new telemetry: #7408
Testing and Verifying
Documentation and Release Note
Unreleased
section ofCHANGELOG.md
?Where is the change documented?
x/{module}/README.md
)