Skip to content
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

perf: Use SDK math v1.3.0 to speedup BigDec casts to/from Dec #7577

Merged
merged 5 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.17
github.com/ory/dockertest/v3 v3.10.0
github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3
github.com/osmosis-labs/osmosis/osmomath v0.0.8
github.com/osmosis-labs/osmosis/osmomath v0.0.9-0.20240222171503-685566578734
github.com/osmosis-labs/osmosis/osmoutils v0.0.9-0.20240222004208-b602d1901059
github.com/osmosis-labs/osmosis/x/epochs v0.0.4
github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.10
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,10 @@ github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3 h1:Ylmch
github.com/osmosis-labs/go-mutesting v0.0.0-20221208041716-b43bcd97b3b3/go.mod h1:lV6KnqXYD/ayTe7310MHtM3I2q8Z6bBfMAi+bhwPYtI=
github.com/osmosis-labs/osmosis/osmomath v0.0.8 h1:jm6D5UgzQ0GQGtyFezs7tQRgwakf3cTBsE8oJIQdPZE=
github.com/osmosis-labs/osmosis/osmomath v0.0.8/go.mod h1:4iPfmy6R0qbImLe5urBLS0thndfLxfmHOdnYboDS1Qo=
github.com/osmosis-labs/osmosis/osmomath v0.0.9-0.20240222011356-56d2a57ef9e5 h1:WZWqFKJdA9xJoAyClsH4ui4lG1SF49RmJbs0pZisD7I=
github.com/osmosis-labs/osmosis/osmomath v0.0.9-0.20240222011356-56d2a57ef9e5/go.mod h1:SuNYa8LXsQDYy9aRU0yrXQpkiZ8lDJmXDwthLyR5N+w=
github.com/osmosis-labs/osmosis/osmomath v0.0.9-0.20240222171503-685566578734 h1:o30q2J2Q/QZv7g9rwDJHK5e6tvd87GsY1uZ79lTdo5A=
github.com/osmosis-labs/osmosis/osmomath v0.0.9-0.20240222171503-685566578734/go.mod h1:SuNYa8LXsQDYy9aRU0yrXQpkiZ8lDJmXDwthLyR5N+w=
github.com/osmosis-labs/osmosis/osmoutils v0.0.9-0.20240222004208-b602d1901059 h1:2PyAblTdr9l5GacEuQY/CitAAUdA60UH43qD9FChdXQ=
github.com/osmosis-labs/osmosis/osmoutils v0.0.9-0.20240222004208-b602d1901059/go.mod h1:uClYVpeXbVKOHRA0n55kfP1jJz1lv66k+V5N0w/vi5M=
github.com/osmosis-labs/osmosis/v22 v22.0.0-alpha0 h1:pVUT1U8PpL+dBQmsmCaoY3P9BCPZO+wH8hs9kpw8v6A=
Expand Down
50 changes: 33 additions & 17 deletions osmomath/decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"
"testing"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand Down Expand Up @@ -36,14 +37,15 @@ const (
)

var (
precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(BigDecPrecision), nil)
squaredPrecisionReuse = new(big.Int).Mul(precisionReuse, precisionReuse)
precisionReuseSDK = new(big.Int).Exp(big.NewInt(10), big.NewInt(DecPrecision), nil)
fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2))
precisionMultipliers []*big.Int
zeroInt = big.NewInt(0)
oneInt = big.NewInt(1)
tenInt = big.NewInt(10)
precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(BigDecPrecision), nil)
squaredPrecisionReuse = new(big.Int).Mul(precisionReuse, precisionReuse)
precisionReuseSDK = new(big.Int).Exp(big.NewInt(10), big.NewInt(DecPrecision), nil)
bigDecDecPrecisionFactorDiff = new(big.Int).Exp(big.NewInt(10), big.NewInt(BigDecPrecision-DecPrecision), nil)
fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2))
precisionMultipliers []*big.Int
zeroInt = big.NewInt(0)
oneInt = big.NewInt(1)
tenInt = big.NewInt(10)

// log_2(e)
// From: https://www.wolframalpha.com/input?i=log_2%28e%29+with+37+digits
Expand Down Expand Up @@ -131,6 +133,10 @@ func NewBigDecFromBigInt(i *big.Int) BigDec {
return NewBigDecFromBigIntWithPrec(i, 0)
}

func NewBigDecFromBigIntMut(i *big.Int) BigDec {
return NewBigDecFromBigIntMutWithPrec(i, 0)
}

// create a new BigDec from big integer assuming whole numbers
// CONTRACT: prec <= BigDecPrecision
func NewBigDecFromBigIntWithPrec(i *big.Int, prec int64) BigDec {
Expand Down Expand Up @@ -617,7 +623,10 @@ func (d BigDec) MustFloat64() float64 {
// Dec returns the osmomath.Dec representation of a BigDec.
// Values in any additional decimal places are truncated.
func (d BigDec) Dec() Dec {
return d.DecWithPrecision(DecPrecision)
dec := math.LegacyNewDec(0)
decBi := dec.BigIntMut()
decBi.Quo(d.i, bigDecDecPrecisionFactorDiff)
return dec
}

// DecWithPrecision converts BigDec to Dec with desired precision
Expand All @@ -636,7 +645,7 @@ func (d BigDec) DecWithPrecision(precision uint64) Dec {

// Truncate any additional decimal values that exist due to BigDec's additional precision
// This relies on big.Int's Quo function doing floor division
intRepresentation := new(big.Int).Quo(d.BigInt(), precisionFactor)
intRepresentation := new(big.Int).Quo(d.BigIntMut(), precisionFactor)

// convert int representation back to SDK Dec precision
truncatedDec := NewDecFromBigIntWithPrec(intRepresentation, int64(precision))
Expand Down Expand Up @@ -680,6 +689,12 @@ func BigDecFromDec(d Dec) BigDec {
return NewBigDecFromBigIntMutWithPrec(d.BigInt(), DecPrecision)
}

// BigDecFromDec returns the BigDec representation of an Dec.
// Values in any additional decimal places are truncated.
func BigDecFromDecMut(d Dec) BigDec {
return NewBigDecFromBigIntMutWithPrec(d.BigIntMut(), DecPrecision)
}

// BigDecFromSDKInt returns the BigDec representation of an sdkInt.
// Values in any additional decimal places are truncated.
func BigDecFromSDKInt(i Int) BigDec {
Expand Down Expand Up @@ -846,18 +861,19 @@ func (d BigDec) TruncateDec() BigDec {
// or equal to the given decimal.
func (d BigDec) Ceil() BigDec {
tmp := new(big.Int).Set(d.i)
return BigDec{i: tmp}.CeilMut()
}

quo, rem := tmp, big.NewInt(0)
quo, rem = quo.QuoRem(tmp, precisionReuse, rem)
func (d BigDec) CeilMut() BigDec {
quo, rem := d.i, big.NewInt(0)
quo, rem = quo.QuoRem(quo, precisionReuse, rem)

// no need to round with a zero remainder regardless of sign
if rem.Sign() == 0 {
return NewBigDecFromBigInt(quo)
} else if rem.Sign() == -1 {
return NewBigDecFromBigInt(quo)
if rem.Sign() <= 0 {
return NewBigDecFromBigIntMut(quo)
}

return NewBigDecFromBigInt(quo.Add(quo, oneInt))
return NewBigDecFromBigIntMut(quo.Add(quo, oneInt))
}

// MaxSortableDec is the largest Dec that can be passed into SortableDecBytes()
Expand Down
4 changes: 3 additions & 1 deletion osmomath/decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,8 +586,10 @@ func (s *decimalTestSuite) TestDecCeil() {
}

for i, tc := range testCases {
tc_input_copy := tc.input.Clone()
res := tc.input.Ceil()
s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input)
s.Require().Equal(tc.input, tc_input_copy, "unexpected mutation of input in test case %d, input: %v", i, tc.input)
s.Require().True(tc.expected.Equal(res), "unexpected result for test case %d, input: %v, got %v, expected %v:", i, tc.input, res, tc.expected)
}
}

Expand Down
2 changes: 1 addition & 1 deletion osmomath/rounding_direction.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func DivIntByU64ToBigDec(i Int, u uint64, round RoundingDirection) (BigDec, erro
if u == 0 {
return BigDec{}, errors.New("div by zero")
}
d := BigDecFromDec(i.ToLegacyDec())
d := BigDecFromDecMut(i.ToLegacyDec())
if round == RoundUp {
return d.QuoRoundUp(NewBigDec(int64(u))), nil
} else if round == RoundDown {
Expand Down
2 changes: 1 addition & 1 deletion osmomath/sqrt.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func MonotonicSqrtBigDec(d BigDec) (BigDec, error) {
if check.Cmp(shiftedD) == -1 {
r.Add(r, oneBigInt)
}
root := NewBigDecFromBigIntWithPrec(r, 36)
root := NewBigDecFromBigIntMutWithPrec(r, 36)

return root, nil
}
Expand Down
2 changes: 1 addition & 1 deletion x/concentrated-liquidity/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ func (s *KeeperTestSuite) swap(pool types.ConcentratedPoolExtension, swapInFunde
RoundingDir: osmomath.RoundDown,
}

result := errTolerance.CompareBigDec(osmomath.BigDecFromDec(swapInFunded.Amount.ToLegacyDec()), osmomath.BigDecFromDec(amountInSwapResult.Amount.ToLegacyDec()))
result := errTolerance.CompareBigDec(osmomath.BigDecFromDecMut(swapInFunded.Amount.ToLegacyDec()), osmomath.BigDecFromDecMut(amountInSwapResult.Amount.ToLegacyDec()))

if result != 0 {
// Note: did some investigations into why this happens.
Expand Down
5 changes: 3 additions & 2 deletions x/concentrated-liquidity/lp.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,11 +569,12 @@ func (k Keeper) initializeInitialPositionForPool(ctx sdk.Context, pool types.Con
if err != nil {
return err
}
initialCurSqrtPriceBigDec := osmomath.BigDecFromDecMut(initialCurSqrtPrice)

// Calculate the initial tick from the initial spot price
// We round down here so that the tick is rounded to
// the nearest possible value given the tick spacing.
initialTick, err := math.SqrtPriceToTickRoundDownSpacing(osmomath.BigDecFromDec(initialCurSqrtPrice), pool.GetTickSpacing())
initialTick, err := math.SqrtPriceToTickRoundDownSpacing(initialCurSqrtPriceBigDec, pool.GetTickSpacing())
if err != nil {
return err
}
Expand All @@ -585,7 +586,7 @@ func (k Keeper) initializeInitialPositionForPool(ctx sdk.Context, pool types.Con
// However, there are ticks only at 100_000_000 X/Y and 100_000_100 X/Y.
// In such a case, we do not want to round the sqrt price to 100_000_000 X/Y, but rather
// let it float within the possible tick range.
pool.SetCurrentSqrtPrice(osmomath.BigDecFromDec(initialCurSqrtPrice))
pool.SetCurrentSqrtPrice(initialCurSqrtPriceBigDec)
pool.SetCurrentTick(initialTick)
err = k.setPool(ctx, pool)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion x/concentrated-liquidity/lp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,7 @@ func (s *KeeperTestSuite) TestInitializeInitialPositionForPool() {
sqrt := func(x int64) osmomath.BigDec {
sqrt, err := osmomath.MonotonicSqrt(osmomath.NewDec(x))
s.Require().NoError(err)
return osmomath.BigDecFromDec(sqrt)
return osmomath.BigDecFromDecMut(sqrt)
}

type sendTest struct {
Expand Down
4 changes: 2 additions & 2 deletions x/concentrated-liquidity/math/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func CalcAmount0Delta(liq, sqrtPriceA, sqrtPriceB osmomath.BigDec, roundUp bool)
// Note that the order of divisions is important here. First, we divide by a larger number (sqrtPriceB) and then by a smaller number (sqrtPriceA).
// This leads to a smaller error amplification. This only matters in cases where at least one of the sqrt prices is below 1.
// TODO (perf): QuoRoundUpMut with no reallocation.
return liq.MulRoundUp(diff).QuoRoundUpMut(sqrtPriceB).QuoRoundUpMut(sqrtPriceA).Ceil()
return liq.MulRoundUp(diff).QuoRoundUpMut(sqrtPriceB).QuoRoundUpMut(sqrtPriceA).CeilMut()
}
// These are truncated at precision end to round in favor of the pool when:
// - calculating amount out during swap
Expand Down Expand Up @@ -114,7 +114,7 @@ func CalcAmount1Delta(liq, sqrtPriceA, sqrtPriceB osmomath.BigDec, roundUp bool)
// Examples include:
// - calculating amountIn during swap
// - adding liquidity (request user to provide more tokens in in favor of the pool)
return liq.Mul(diff).Ceil()
return liq.Mul(diff).CeilMut()
}
// This is truncated at precision end to round in favor of the pool when:
// - calculating amount out during swap
Expand Down
5 changes: 3 additions & 2 deletions x/concentrated-liquidity/math/tick.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TickToSqrtPrice(tickIndex int64) (osmomath.BigDec, error) {
if err != nil {
return osmomath.BigDec{}, err
}
return osmomath.BigDecFromDec(sqrtPrice), nil
return osmomath.BigDecFromDecMut(sqrtPrice), nil
}

// For the newly extended range of [tick(MinSpotPriceV2), MinInitializedTick), we use the new math
Expand Down Expand Up @@ -111,10 +111,11 @@ func TickToPrice(tickIndex int64) (osmomath.BigDec, error) {
// original math based on 18 precision decimal on the range of [MinInitializedTick, tick(MaxSpotPrice)]
// For the newly extended range of [MinInitializedTickV2, MinInitializedTick), we use the new math
// based on 36 precision decimal.
// TODO: Delete this code difference, it yields the exact same number every time.
if tickIndex < types.MinInitializedTick {
price = additiveSpacing.AddMut(powTenBigDec(geometricExponentDelta))
} else {
price = osmomath.BigDecFromDec(PowTenInternal(geometricExponentDelta).Add(additiveSpacing.Dec()))
price = osmomath.BigDecFromDecMut((additiveSpacing.Dec()).AddMut(PowTenInternal(geometricExponentDelta)))
}

// defense in depth, this logic would not be reached due to use having checked if given tick is in between
Expand Down
5 changes: 3 additions & 2 deletions x/concentrated-liquidity/model/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,14 @@ func (p Pool) SpotPrice(ctx sdk.Context, quoteAssetDenom string, baseAssetDenom
return osmomath.BigDec{}, fmt.Errorf("quote asset denom (%s) is not in pool with (%s, %s) pair", quoteAssetDenom, p.Token0, p.Token1)
}

priceSquared := p.CurrentSqrtPrice.PowerInteger(2)
// The reason why we convert the result to Dec and then back to BigDec is to temporarily
// maintain backwards compatibility with the original implementation.
// TODO: remove before https://github.com/osmosis-labs/osmosis/issues/5726 is complete
if baseAssetDenom == p.Token0 {
return osmomath.BigDecFromDec(p.CurrentSqrtPrice.PowerInteger(2).Dec()), nil
return osmomath.BigDecFromDecMut(priceSquared.Dec()), nil
}
return osmomath.BigDecFromDec(osmomath.OneBigDec().Quo(p.CurrentSqrtPrice.PowerInteger(2)).Dec()), nil
return osmomath.BigDecFromDecMut(osmomath.OneBigDec().Quo(priceSquared).Dec()), nil
}

// GetToken0 returns the token0 of the pool
Expand Down
4 changes: 2 additions & 2 deletions x/concentrated-liquidity/model/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ var (
DefaultReverseSpotPrice = osmomath.NewDec(1).Quo(DefaultSpotPrice)
DefaultSqrtSpotPrice = func() osmomath.BigDec {
sqrtPrice, _ := osmomath.MonotonicSqrt(DefaultSpotPrice)
return osmomath.BigDecFromDec(sqrtPrice)
return osmomath.BigDecFromDecMut(sqrtPrice)
}()
DefaultLiquidityAmt = osmomath.MustNewDecFromStr("1517882343.751510418088349649")
DefaultCurrTick int64 = 310000
DefaultCurrPrice = osmomath.NewDec(5000)
DefaultCurrSqrtPrice = func() osmomath.BigDec {
sqrtPrice, _ := osmomath.MonotonicSqrt(DefaultCurrPrice)
return osmomath.BigDecFromDec(sqrtPrice)
return osmomath.BigDecFromDecMut(sqrtPrice)
}() // 70.710678118654752440

DefaultSpreadFactor = osmomath.MustNewDecFromStr("0.01")
Expand Down
2 changes: 1 addition & 1 deletion x/concentrated-liquidity/swapstrategy/swap_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func GetSqrtPriceLimit(priceLimit osmomath.BigDec, zeroForOne bool) (osmomath.Bi
if err != nil {
return osmomath.BigDec{}, err
}
return osmomath.BigDecFromDec(sqrtPriceLimit), nil
return osmomath.BigDecFromDecMut(sqrtPriceLimit), nil
}

// On the newly extended lower price range, utilize the 36 decimal
Expand Down
2 changes: 1 addition & 1 deletion x/gamm/pool-models/balancer/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ func (p Pool) SpotPrice(ctx sdk.Context, quoteAsset, baseAsset string) (spotPric
supplyRatio := quote.Token.Amount.ToLegacyDec().Quo(base.Token.Amount.ToLegacyDec())
spotPriceDec := supplyRatio.Mul(invWeightRatio)

return osmomath.BigDecFromDec(spotPriceDec), err
return osmomath.BigDecFromDecMut(spotPriceDec), err
}

// calcPoolOutGivenSingleIn - balance pAo.
Expand Down
2 changes: 1 addition & 1 deletion x/gamm/pool-models/stableswap/amm.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func (p Pool) spotPrice(quoteDenom, baseDenom string) (spotPrice osmomath.Dec, e
}

func oneMinus(spreadFactor osmomath.Dec) osmomath.BigDec {
return osmomath.BigDecFromDec(osmomath.OneDec().Sub(spreadFactor))
return osmomath.BigDecFromDecMut(osmomath.OneDec().SubMut(spreadFactor))
}

// calcOutAmtGivenIn calculate amount of specified denom to output from a pool in osmomath.Dec given the input `tokenIn`
Expand Down
2 changes: 1 addition & 1 deletion x/gamm/pool-models/stableswap/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ func (p Pool) SpotPrice(ctx sdk.Context, quoteAssetDenom string, baseAssetDenom
if err != nil {
return osmomath.BigDec{}, err
}
return osmomath.BigDecFromDec(spotPriceDec), nil
return osmomath.BigDecFromDecMut(spotPriceDec), nil
}

func (p Pool) Copy() Pool {
Expand Down