From 4ed1087cf5a313c0fd0c97ce9459ed72341ec7ed Mon Sep 17 00:00:00 2001 From: Alexander Peters Date: Fri, 22 Nov 2024 11:29:01 +0100 Subject: [PATCH 1/2] feat(math): Upstream GDA based decimal type (#21982) Co-authored-by: samricotta Co-authored-by: samricotta <37125168+samricotta@users.noreply.github.com> --- .../building-modules/18-decimal-handling.md | 80 + math/dec.go | 1209 +++----- math/dec_bench_test.go | 353 +++ math/dec_examples_test.go | 323 +++ math/dec_rapid_test.go | 527 ++++ math/dec_test.go | 2481 +++++++++-------- math/go.mod | 20 +- math/go.sum | 41 +- math/int_test.go | 2 - math/legacy_dec.go | 971 +++++++ .../{fuzz_test.go => legacy_dec_fuzz_test.go} | 0 ...al_test.go => legacy_dec_internal_test.go} | 0 math/legacy_dec_test.go | 1329 +++++++++ math/uint_test.go | 1 - simapp/go.mod | 2 +- simapp/go.sum | 4 +- simapp/v2/go.mod | 2 +- simapp/v2/go.sum | 4 +- tests/go.mod | 2 +- tests/go.sum | 4 +- x/group/go.mod | 2 +- x/group/go.sum | 4 +- x/group/internal/math/dec.go | 20 +- 23 files changed, 5278 insertions(+), 2103 deletions(-) create mode 100644 docs/build/building-modules/18-decimal-handling.md create mode 100644 math/dec_bench_test.go create mode 100644 math/dec_examples_test.go create mode 100644 math/dec_rapid_test.go create mode 100644 math/legacy_dec.go rename math/{fuzz_test.go => legacy_dec_fuzz_test.go} (100%) rename math/{dec_internal_test.go => legacy_dec_internal_test.go} (100%) create mode 100644 math/legacy_dec_test.go diff --git a/docs/build/building-modules/18-decimal-handling.md b/docs/build/building-modules/18-decimal-handling.md new file mode 100644 index 000000000000..0a14f69459c1 --- /dev/null +++ b/docs/build/building-modules/18-decimal-handling.md @@ -0,0 +1,80 @@ +--- +sidebar_position: 1 +--- +# Decimal Handling in Cosmos SDK + +## Introduction + +In the Cosmos SDK, there are two types of decimals: `LegacyDec` and `Dec`. `LegacyDec` is the older decimal type that is still available for use, while `Dec` is the newer, more performant decimal type. The implementation of `Dec` is adapted from Regen Network's `regen-ledger`, specifically from [this module](https://github.com/regen-network/regen-ledger/tree/main/types/math). Migrating from `LegacyDec` to `Dec` involves state-breaking changes, specifically: + +* **Data Format**: The internal representation of decimals changes, affecting how data is stored and processed. +* **Precision Handling**: `Dec` supports flexible precision up to 34 decimal places, unlike `LegacyDec` which has a fixed precision of 18 decimal places. + +These changes require a state migration to update existing decimal values to the new format. It is recommended to use `Dec` for new modules to leverage its enhanced performance and flexibility. + +## Why the Change? + +* Historically we have wrapped a `big.Int` to represent decimals in the Cosmos SDK and never had a decimal type. Finally, we have a decimal type that is more efficient and accurate. +* `Dec` uses the [apd](https://github.com/cockroachdb/apd) library for arbitrary precision decimals, suitable for accurate financial calculations. +* `Dec` operations are safer for concurrent use as they do not mutate the original values. +* `Dec` operations are faster and more efficient than `LegacyDec`. + +## Using `Dec` in Modules that haven't used `LegacyDec` + +If you are creating a new module or updating an existing module that has not used `LegacyDec`, you can directly use `Dec`. +Ensure proper error handling. + +``` +-- math.NewLegacyDecFromInt64(100) +++ math.NewDecFromInt64(100) + +-- math.LegacyNewDecWithPrec(100, 18) +++ math.NewDecWithPrec(100, 18) + +-- math.LegacyNewDecFromStr("100") +++ math.NewDecFromString("100") + +-- math.LegacyNewDecFromStr("100.000000000000000000").Quo(math.LegacyNewDecFromInt(2)) +++ foo, err := math.NewDecFromString("100.000000000000000000") +++ foo.Quo(math.NewDecFromInt(2)) + +-- math.LegacyNewDecFromStr("100.000000000000000000").Add(math.LegacyNewDecFromInt(2)) +++ foo, err := math.NewDecFromString("100.000000000000000000") +++ foo.Add(math.NewDecFromInt(2)) + +-- math.LegacyNewDecFromStr("100.000000000000000000").Sub(math.LegacyNewDecFromInt(2)) +++ foo, err := math.NewDecFromString("100.000000000000000000") +++ foo.Sub(math.NewDecFromInt(2)) +``` + +## Modules migrating from `LegacyDec` to `Dec` + +When migrating from `LegacyDec` to `Dec`, you need to update your module to use the new decimal type. **These types are state breaking changes and require a migration.** + +## Precision Handling + +The reason for the state breaking change is the difference in precision handling between the two decimal types: + +* **LegacyDec**: Fixed precision of 18 decimal places. +* **Dec**: Flexible precision up to 34 decimal places using the apd library. + +## Impact of Precision Change + +The increase in precision from 18 to 34 decimal places allows for more detailed decimal values but requires data migration. This change in how data is formatted and stored is a key aspect of why the transition is considered state-breaking. + +## Converting `LegacyDec` to `Dec` without storing the data + +If you would like to convert a `LegacyDec` to a `Dec` without a state migration changing how the data is handled internally within the application logic and not how it's stored or represented. You can use the following methods. + +```go +func LegacyDecToDec(ld LegacyDec) (Dec, error) { + return NewDecFromString(ld.String()) +} +``` + +```go +func DecToLegacyDec(ld Dec) (LegacyDec, error) { + return LegacyDecFromString(ld.String()) +} +``` + diff --git a/math/dec.go b/math/dec.go index 16bb0806861b..3f96345e249b 100644 --- a/math/dec.go +++ b/math/dec.go @@ -2,970 +2,453 @@ package math import ( "encoding/json" - "errors" - "fmt" + stderrors "errors" "math/big" - "strconv" - "strings" - "testing" -) -// LegacyDec NOTE: never use new(Dec) or else we will panic unmarshalling into the -// nil embedded big.Int -type LegacyDec struct { - i *big.Int -} + "github.com/cockroachdb/apd/v3" -const ( - // LegacyPrecision number of decimal places - LegacyPrecision = 18 + "cosmossdk.io/errors" +) - // LegacyDecimalPrecisionBits bits required to represent the above precision - // Ceiling[Log2[10^Precision - 1]] - // Deprecated: This is unused and will be removed - LegacyDecimalPrecisionBits = 60 +var _ customProtobufType = &Dec{} - // maxApproxRootIterations max number of iterations in ApproxRoot function - maxApproxRootIterations = 300 +const ( + // MaxExponent is the highest exponent supported. Exponents near this range will + // perform very slowly (many seconds per operation). + MaxExponent = apd.MaxExponent + // MinExponent is the lowest exponent supported with the same limitations as + // MaxExponent. + MinExponent = apd.MinExponent ) -var ( - precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(LegacyPrecision), nil) - fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2)) - - upperLimit LegacyDec - lowerLimit LegacyDec +// Dec is a wrapper struct around apd.Decimal that does no mutation of apd.Decimal's when performing +// arithmetic, instead creating a new apd.Decimal for every operation ensuring usage is safe. +// +// Using apd.Decimal directly can be unsafe because apd operations mutate the underlying Decimal, +// but when copying the big.Int structure can be shared between Decimal instances causing corruption. +// This was originally discovered in regen0-network/mainnet#15. +type Dec struct { + dec apd.Decimal +} - precisionMultipliers []*big.Int - zeroInt = big.NewInt(0) - oneInt = big.NewInt(1) - tenInt = big.NewInt(10) - smallestDec = LegacySmallestDec() -) +const mathCodespace = "math" -// Decimal errors var ( - ErrLegacyEmptyDecimalStr = errors.New("decimal string cannot be empty") - ErrLegacyInvalidDecimalLength = errors.New("invalid decimal length") - ErrLegacyInvalidDecimalStr = errors.New("invalid decimal string") + ErrInvalidDec = errors.Register(mathCodespace, 1, "invalid decimal") + ErrUnexpectedRounding = errors.Register(mathCodespace, 2, "unexpected rounding") + ErrNonIntegral = errors.Register(mathCodespace, 3, "value is non-integral") ) -// Set precision multipliers -func init() { - precisionMultipliers = make([]*big.Int, LegacyPrecision+1) - for i := 0; i <= LegacyPrecision; i++ { - precisionMultipliers[i] = calcPrecisionMultiplier(int64(i)) - } - // 2^256 * 10^18 -1 - tmp := new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil) - tmp = new(big.Int).Sub(new(big.Int).Mul(tmp, precisionReuse), big.NewInt(1)) - upperLimit = LegacyNewDecFromBigIntWithPrec(tmp, LegacyPrecision) - lowerLimit = upperLimit.Neg() +// In cosmos-sdk#7773, decimal128 (with 34 digits of precision) was suggested for performing +// Quo/Mult arithmetic generically across the SDK. Even though the SDK +// has yet to support a GDA with decimal128 (34 digits), we choose to utilize it here. +// https://github.com/cosmos/cosmos-sdk/issues/7773#issuecomment-725006142 +var dec128Context = apd.Context{ + Precision: 34, + MaxExponent: MaxExponent, + MinExponent: MinExponent, + Traps: apd.DefaultTraps, } -func precisionInt() *big.Int { - return new(big.Int).Set(precisionReuse) -} - -func LegacyZeroDec() LegacyDec { return LegacyDec{new(big.Int).Set(zeroInt)} } -func LegacyOneDec() LegacyDec { return LegacyDec{precisionInt()} } -func LegacySmallestDec() LegacyDec { return LegacyDec{new(big.Int).Set(oneInt)} } - -// calculate the precision multiplier -func calcPrecisionMultiplier(prec int64) *big.Int { - if prec < 0 { - panic(fmt.Sprintf("negative precision %v", prec)) - } - - if prec > LegacyPrecision { - panic(fmt.Sprintf("too much precision, maximum %v, provided %v", LegacyPrecision, prec)) - } - zerosToAdd := LegacyPrecision - prec - multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) - return multiplier -} - -// get the precision multiplier, do not mutate result -func precisionMultiplier(prec int64) *big.Int { - if prec < 0 { - panic(fmt.Sprintf("negative precision %v", prec)) - } - - if prec > LegacyPrecision { - panic(fmt.Sprintf("too much precision, maximum %v, provided %v", LegacyPrecision, prec)) +// NewDecFromString converts a string to a Dec type, supporting standard, scientific, and negative notations. +// It handles non-numeric values and overflow conditions, returning errors for invalid inputs like "NaN" or "Infinity". +// +// Examples: +// - "123" -> Dec{123} +// - "-123.456" -> Dec{-123.456} +// - "1.23E4" -> Dec{12300} +// - "NaN" or "Infinity" -> ErrInvalidDec +// +// The internal representation is an arbitrary-precision decimal: Negative × Coeff × 10*Exponent +// The maximum exponent is 100_000 and must not be exceeded. Following values would be invalid: +// 1E100001 -> ErrInvalidDec +// -1E100001 -> ErrInvalidDec +// 1E-100001 -> ErrInvalidDec +// +// This function is essential for converting textual data into Dec types for numerical operations. +func NewDecFromString(s string) (Dec, error) { + d, _, err := apd.NewFromString(s) + if err != nil { + return Dec{}, ErrInvalidDec.Wrap(err.Error()) } - return precisionMultipliers[prec] -} -// LegacyNewDec create a new Dec from integer assuming whole number -func LegacyNewDec(i int64) LegacyDec { - return LegacyNewDecWithPrec(i, 0) -} - -// LegacyNewDecWithPrec create a new Dec from integer with decimal place at prec -// CONTRACT: prec <= Precision -func LegacyNewDecWithPrec(i, prec int64) LegacyDec { - bi := big.NewInt(i) - return LegacyDec{ - bi.Mul(bi, precisionMultiplier(prec)), + switch d.Form { + case apd.NaN, apd.NaNSignaling: + return Dec{}, ErrInvalidDec.Wrap("not a number") + case apd.Infinite: + return Dec{}, ErrInvalidDec.Wrap(s) + case apd.Finite: + result := Dec{*d} + return result, nil + default: + return Dec{}, ErrInvalidDec.Wrapf("unsupported type: %d", d.Form) } } -// LegacyNewDecFromBigInt create a new Dec from big integer assuming whole numbers -// CONTRACT: prec <= Precision -func LegacyNewDecFromBigInt(i *big.Int) LegacyDec { - return LegacyNewDecFromBigIntWithPrec(i, 0) +// NewDecFromInt64 converts an int64 to a Dec type. +// This function is useful for creating Dec values from integer literals or variables, +// ensuring they can be used in high-precision arithmetic operations defined for Dec types. +// +// Example: +// - NewDecFromInt64(123) returns a Dec representing the value 123. +func NewDecFromInt64(x int64) Dec { + var res Dec + res.dec.SetInt64(x) + return res +} + +// NewDecWithExp creates a Dec from a coefficient and exponent, calculated as coeff * 10^exp. +// Useful for precise decimal representations. +// Although this method can be used with a higher than maximum exponent or lower than minimum exponent, further arithmetic +// or other method may fail. +// +// Example: +// - NewDecWithExp(123, -2) -> Dec representing 1.23. +func NewDecWithExp(coeff int64, exp int32) Dec { + var res Dec + res.dec.SetFinite(coeff, exp) + return res } -// LegacyNewDecFromBigIntWithPrec create a new Dec from big integer assuming whole numbers -// CONTRACT: prec <= Precision -func LegacyNewDecFromBigIntWithPrec(i *big.Int, prec int64) LegacyDec { - return LegacyDec{ - new(big.Int).Mul(i, precisionMultiplier(prec)), +// Add returns a new Dec representing the sum of `x` and `y` using returning a new Dec, we use apd.BaseContext. +// This function ensures that no arguments are mutated during the operation and checks for overflow conditions. +// If an overflow occurs, an error is returned. +// +// The precision is much higher as long as the max exponent is not exceeded. If the max exponent is exceeded, an error is returned. +// For example: +// - 1e100000 + -1e-1 +// - 1e100000 + 9e100000 +// - 1e100001 + 0 +// We can see that in apd.BaseContext the max exponent is defined hence we cannot exceed. +// +// This function wraps any internal errors with a context-specific error message for clarity. +func (x Dec) Add(y Dec) (Dec, error) { + var z Dec + _, err := apd.BaseContext.Add(&z.dec, &x.dec, &y.dec) + if err != nil { + return Dec{}, ErrInvalidDec.Wrap(err.Error()) } -} -// LegacyNewDecFromInt create a new Dec from big integer assuming whole numbers -// CONTRACT: prec <= Precision -func LegacyNewDecFromInt(i Int) LegacyDec { - return LegacyNewDecFromIntWithPrec(i, 0) + return z, nil } -// LegacyNewDecFromIntWithPrec create a new Dec from big integer with decimal place at prec -// CONTRACT: prec <= Precision -func LegacyNewDecFromIntWithPrec(i Int, prec int64) LegacyDec { - return LegacyDec{ - new(big.Int).Mul(i.BigIntMut(), precisionMultiplier(prec)), +// Sub returns a new Dec representing the sum of `x` and `y` using returning a new Dec, we use apd.BaseContext. +// This function ensures that no arguments are mutated during the operation and checks for overflow conditions. +// If an overflow occurs, an error is returned. +// +// The precision is much higher as long as the max exponent is not exceeded. If the max exponent is exceeded, an error is returned. +// For example: +// - 1e-100001 - 0 +// - 1e100000 - 1e-1 +// - 1e100000 - -9e100000 +// - 1e100001 - 1e100001 (upper limit exceeded) +// - 1e-100001 - 1e-100001 (lower limit exceeded) +// We can see that in apd.BaseContext the max exponent is defined hence we cannot exceed. +// +// This function wraps any internal errors with a context-specific error message for clarity. +func (x Dec) Sub(y Dec) (Dec, error) { + var z Dec + _, err := apd.BaseContext.Sub(&z.dec, &x.dec, &y.dec) + if err != nil { + if err2 := stderrors.Unwrap(err); err2 != nil { + // use unwrapped error to not return "add:" prefix from raw apd error + err = err2 + } + return Dec{}, ErrInvalidDec.Wrap("sub: " + err.Error()) } + return z, nil } -// LegacyNewDecFromStr create a decimal from an input decimal string. -// valid must come in the form: -// -// (-) whole integers (.) decimal integers +// Quo performs division of x by y using the decimal128 context with 34 digits of precision. +// It returns a new Dec or an error if the division is not feasible due to constraints of decimal128. // -// examples of acceptable input include: +// Within Quo half up rounding may be performed to match the defined precision. If this is unwanted, QuoExact +// should be used instead. // -// -123.456 -// 456.7890 -// 345 -// -456789 +// Key error scenarios: +// - Division by zero (e.g., `123 / 0` or `0 / 0`) results in ErrInvalidDec. +// - Non-representable values due to extreme ratios or precision limits. // -// NOTE - An error will return if more decimal places -// are provided in the string than the constant Precision. +// Examples: +// - `0 / 123` yields `0`. +// - `123 / 123` yields `1.000000000000000000000000000000000`. +// - `-123 / 123` yields `-1.000000000000000000000000000000000`. +// - `4 / 9` yields `0.4444444444444444444444444444444444`. +// - `5 / 9` yields `0.5555555555555555555555555555555556`. +// - `6 / 9` yields `0.6666666666666666666666666666666667`. +// - `1e-100000 / 10` yields error. // -// CONTRACT - This function does not mutate the input str. -func LegacyNewDecFromStr(str string) (LegacyDec, error) { - // first extract any negative symbol - neg := false - if len(str) > 0 && str[0] == '-' { - neg = true - str = str[1:] - } - - if len(str) == 0 { - return LegacyDec{}, ErrLegacyEmptyDecimalStr - } - - strs := strings.Split(str, ".") - lenDecs := 0 - combinedStr := strs[0] - - if len(strs) == 2 { // has a decimal place - lenDecs = len(strs[1]) - if lenDecs == 0 || len(combinedStr) == 0 { - return LegacyDec{}, ErrLegacyInvalidDecimalLength - } - combinedStr += strs[1] - } else if len(strs) > 2 { - return LegacyDec{}, ErrLegacyInvalidDecimalStr - } - - if lenDecs > LegacyPrecision { - return LegacyDec{}, fmt.Errorf("value '%s' exceeds max precision by %d decimal places: max precision %d", str, LegacyPrecision-lenDecs, LegacyPrecision) - } - - // add some extra zero's to correct to the Precision factor - zerosToAdd := LegacyPrecision - lenDecs - zeros := strings.Repeat("0", zerosToAdd) - combinedStr += zeros - - combined, ok := new(big.Int).SetString(combinedStr, 10) // base 10 - if !ok { - return LegacyDec{}, fmt.Errorf("failed to set decimal string with base 10: %s", combinedStr) - } - if neg { - combined = new(big.Int).Neg(combined) - } - - result := LegacyDec{i: combined} - if !result.IsInValidRange() { - return LegacyDec{}, fmt.Errorf("out of range: %w", ErrLegacyInvalidDecimalStr) - } - return result, nil -} - -// LegacyMustNewDecFromStr Decimal from string, panic on error -func LegacyMustNewDecFromStr(s string) LegacyDec { - dec, err := LegacyNewDecFromStr(s) +// This function is non-mutative and enhances error clarity with specific messages. +func (x Dec) Quo(y Dec) (Dec, error) { + var z Dec + _, err := dec128Context.Quo(&z.dec, &x.dec, &y.dec) if err != nil { - panic(err) - } - return dec -} - -func (d LegacyDec) IsNil() bool { return d.i == nil } // is decimal nil -func (d LegacyDec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero -func (d LegacyDec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative -func (d LegacyDec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive -func (d LegacyDec) Equal(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals -func (d LegacyDec) GT(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than -func (d LegacyDec) GTE(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal -func (d LegacyDec) LT(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) < 0 } // less than -func (d LegacyDec) LTE(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal -func (d LegacyDec) Neg() LegacyDec { return LegacyDec{new(big.Int).Neg(d.i)} } // reverse the decimal sign -func (d LegacyDec) NegMut() LegacyDec { d.i.Neg(d.i); return d } // reverse the decimal sign, mutable -func (d LegacyDec) Abs() LegacyDec { return LegacyDec{new(big.Int).Abs(d.i)} } // absolute value -func (d LegacyDec) AbsMut() LegacyDec { d.i.Abs(d.i); return d } // absolute value, mutable -func (d LegacyDec) Set(d2 LegacyDec) LegacyDec { d.i.Set(d2.i); return d } // set to existing dec value -func (d LegacyDec) Clone() LegacyDec { return LegacyDec{new(big.Int).Set(d.i)} } // clone new dec - -// BigInt returns a copy of the underlying big.Int. -func (d LegacyDec) BigInt() *big.Int { - if d.IsNil() { - return nil + return Dec{}, ErrInvalidDec.Wrap(err.Error()) } - cp := new(big.Int) - return cp.Set(d.i) + return z, errors.Wrap(err, "decimal quotient error") } -// BigIntMut converts LegacyDec to big.Int, mutative the input -func (d LegacyDec) BigIntMut() *big.Int { - if d.IsNil() { - return nil - } - - return d.i -} - -func (d LegacyDec) ImmutOp(op func(LegacyDec, LegacyDec) LegacyDec, d2 LegacyDec) LegacyDec { - return op(d.Clone(), d2) -} - -func (d LegacyDec) ImmutOpInt(op func(LegacyDec, Int) LegacyDec, d2 Int) LegacyDec { - return op(d.Clone(), d2) -} - -func (d LegacyDec) ImmutOpInt64(op func(LegacyDec, int64) LegacyDec, d2 int64) LegacyDec { - // TODO: use already allocated operand bigint to avoid - // newint each time, add mutex for race condition - // Issue: https://github.com/cosmos/cosmos-sdk/issues/11166 - return op(d.Clone(), d2) -} - -func (d LegacyDec) SetInt64(i int64) LegacyDec { - d.i.SetInt64(i) - d.i.Mul(d.i, precisionReuse) - return d -} - -// Add addition -func (d LegacyDec) Add(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.AddMut, d2) -} - -// AddMut mutable addition -func (d LegacyDec) AddMut(d2 LegacyDec) LegacyDec { - d.i.Add(d.i, d2.i) - - d.assertInValidRange() - return d -} - -// Sub subtraction -func (d LegacyDec) Sub(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.SubMut, d2) -} - -// SubMut mutable subtraction -func (d LegacyDec) SubMut(d2 LegacyDec) LegacyDec { - d.i.Sub(d.i, d2.i) - - d.assertInValidRange() - return d -} - -func (d LegacyDec) assertInValidRange() { - if !d.IsInValidRange() { - panic("Int overflow") +// QuoExact performs division like Quo and additionally checks for rounding. It returns ErrUnexpectedRounding if +// any rounding occurred during the division. If the division is exact, it returns the result without error. +// +// This function is particularly useful in financial calculations or other scenarios where precision is critical +// and rounding could lead to significant errors. +// +// Key error scenarios: +// - Division by zero (e.g., `123 / 0` or `0 / 0`) results in ErrInvalidDec. +// - Rounding would have occurred, which is not permissible in this context, resulting in ErrUnexpectedRounding. +// +// Examples: +// - `0 / 123` yields `0` without rounding. +// - `123 / 123` yields `1.000000000000000000000000000000000` exactly. +// - `-123 / 123` yields `-1.000000000000000000000000000000000` exactly. +// - `1 / 9` yields error for the precision limit +// - `1e-100000 / 10` yields error for crossing the lower exponent limit. +// - Any division resulting in a non-terminating decimal under decimal128 precision constraints triggers ErrUnexpectedRounding. +// +// This function does not mutate any arguments and wraps any internal errors with a context-specific error message for clarity. +func (x Dec) QuoExact(y Dec) (Dec, error) { + var z Dec + condition, err := dec128Context.Quo(&z.dec, &x.dec, &y.dec) + if err != nil { + return z, ErrInvalidDec.Wrap(err.Error()) } -} - -// IsInValidRange returns true when the value is between the upper limit of (2^256 * 10^18) -// and the lower limit of -1*(2^256 * 10^18). -func (d LegacyDec) IsInValidRange() bool { - return !(d.GT(upperLimit) || d.LT(lowerLimit)) -} - -// Mul multiplication -func (d LegacyDec) Mul(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.MulMut, d2) -} - -// MulMut mutable multiplication -func (d LegacyDec) MulMut(d2 LegacyDec) LegacyDec { - d.i.Mul(d.i, d2.i) - chopped := chopPrecisionAndRound(d.i) - - *d.i = *chopped - d.assertInValidRange() - return d -} - -// MulTruncate multiplication truncate -func (d LegacyDec) MulTruncate(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.MulTruncateMut, d2) -} - -// MulTruncateMut mutable multiplication truncate -func (d LegacyDec) MulTruncateMut(d2 LegacyDec) LegacyDec { - d.i.Mul(d.i, d2.i) - chopPrecisionAndTruncate(d.i) - d.assertInValidRange() - return d -} - -// MulRoundUp multiplication round up at precision end. -func (d LegacyDec) MulRoundUp(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.MulRoundUpMut, d2) -} - -// MulRoundUpMut mutable multiplication with round up at precision end. -func (d LegacyDec) MulRoundUpMut(d2 LegacyDec) LegacyDec { - d.i.Mul(d.i, d2.i) - chopPrecisionAndRoundUp(d.i) - - d.assertInValidRange() - return d -} - -// MulInt multiplication -func (d LegacyDec) MulInt(i Int) LegacyDec { - return d.ImmutOpInt(LegacyDec.MulIntMut, i) -} - -func (d LegacyDec) MulIntMut(i Int) LegacyDec { - d.i.Mul(d.i, i.BigIntMut()) - d.assertInValidRange() - return d -} - -// MulInt64 multiplication with int64 -func (d LegacyDec) MulInt64(i int64) LegacyDec { - return d.ImmutOpInt64(LegacyDec.MulInt64Mut, i) -} - -func (d LegacyDec) MulInt64Mut(i int64) LegacyDec { - d.i.Mul(d.i, big.NewInt(i)) - d.assertInValidRange() - return d -} - -// Quo quotient -func (d LegacyDec) Quo(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.QuoMut, d2) -} - -var squaredPrecisionReuse = new(big.Int).Mul(precisionReuse, precisionReuse) - -// QuoMut mutable quotient -func (d LegacyDec) QuoMut(d2 LegacyDec) LegacyDec { - // multiply by precision twice - d.i.Mul(d.i, squaredPrecisionReuse) - d.i.Quo(d.i, d2.i) - - chopPrecisionAndRound(d.i) - d.assertInValidRange() - return d -} - -// QuoTruncate quotient truncate -func (d LegacyDec) QuoTruncate(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.QuoTruncateMut, d2) -} - -// QuoTruncateMut divides the current LegacyDec value by the provided LegacyDec value, truncating the result. -func (d LegacyDec) QuoTruncateMut(d2 LegacyDec) LegacyDec { - // multiply precision once before performing division - d.i.Mul(d.i, precisionReuse) - d.i.Quo(d.i, d2.i) - - d.assertInValidRange() - return d -} - -// QuoRoundUp quotient, round up -func (d LegacyDec) QuoRoundUp(d2 LegacyDec) LegacyDec { - return d.ImmutOp(LegacyDec.QuoRoundupMut, d2) -} - -// QuoRoundupMut mutable quotient, round up -func (d LegacyDec) QuoRoundupMut(d2 LegacyDec) LegacyDec { - // multiply precision twice - d.i.Mul(d.i, precisionReuse) - _, rem := d.i.QuoRem(d.i, d2.i, big.NewInt(0)) - if rem.Sign() > 0 && d.IsNegative() == d2.IsNegative() || - rem.Sign() < 0 && d.IsNegative() != d2.IsNegative() { - d.i.Add(d.i, oneInt) + if condition.Rounded() { + return z, ErrUnexpectedRounding } - d.assertInValidRange() - return d -} - -// QuoInt quotient -func (d LegacyDec) QuoInt(i Int) LegacyDec { - return d.ImmutOpInt(LegacyDec.QuoIntMut, i) -} - -func (d LegacyDec) QuoIntMut(i Int) LegacyDec { - d.i.Quo(d.i, i.BigIntMut()) - return d -} - -// QuoInt64 quotient with int64 -func (d LegacyDec) QuoInt64(i int64) LegacyDec { - return d.ImmutOpInt64(LegacyDec.QuoInt64Mut, i) + return z, errors.Wrap(err, "decimal quotient error") } -func (d LegacyDec) QuoInt64Mut(i int64) LegacyDec { - d.i.Quo(d.i, big.NewInt(i)) - return d -} - -// ApproxRoot returns an approximate estimation of a Dec's positive real nth root -// using Newton's method (where n is positive). The algorithm starts with some guess and -// computes the sequence of improved guesses until an answer converges to an -// approximate answer. It returns `|d|.ApproxRoot() * -1` if input is negative. -// A maximum number of 100 iterations is used a backup boundary condition for -// cases where the answer never converges enough to satisfy the main condition. -func (d LegacyDec) ApproxRoot(root uint64) (guess LegacyDec, err error) { - defer func() { - if r := recover(); r != nil { - var ok bool - err, ok = r.(error) - if !ok { - err = errors.New("out of bounds") - } - } - }() - - if root == 0 { - // Return 1 as root 0 of any number is considered 1. - return LegacyOneDec(), nil - } - - if d.IsNegative() { - absRoot, err := d.Neg().ApproxRoot(root) - return absRoot.NegMut(), err - } - - // Direct return for base cases: d^1 = d or when d is 0 or 1. - scratchOneDec := LegacyOneDec() - if root == 1 || d.IsZero() || d.Equal(scratchOneDec) { - return d, nil - } - - guess, delta := scratchOneDec, LegacyOneDec() - - for iter := 0; iter < maxApproxRootIterations; iter++ { - prev := guess.Power(root - 1) - if prev.IsZero() { - prev = smallestDec - } - - // Compute delta = (d/prev - guess) / root - delta.Set(d).QuoMut(prev) - delta.SubMut(guess) - delta.QuoInt64Mut(int64(root)) - - guess.AddMut(delta) - - // Stop when delta is small enough - if delta.Abs().LTE(smallestDec) { - break - } +// QuoInteger performs integer division of x by y, returning a new Dec formatted as decimal128 with 34 digit precision. +// This function returns the integer part of the quotient, discarding any fractional part, and is useful in scenarios +// where only the whole number part of the division result is needed without rounding. +// +// Key error scenarios: +// - Division by zero (e.g., `123 / 0`) results in ErrInvalidDec. +// - Overflow conditions if the result exceeds the storage capacity of a decimal128 formatted number. +// +// Examples: +// - `123 / 50` yields `2` (since the fractional part .46 is discarded). +// - `100 / 3` yields `33` (since the fractional part .3333... is discarded). +// - `50 / 100` yields `0` (since 0.5 is less than 1 and thus discarded). +// +// The function does not mutate any arguments and ensures that errors are wrapped with specific messages for clarity. +func (x Dec) QuoInteger(y Dec) (Dec, error) { + var z Dec + _, err := dec128Context.QuoInteger(&z.dec, &x.dec, &y.dec) + if err != nil { + return z, ErrInvalidDec.Wrap(err.Error()) } - - return guess, nil + return z, nil } -// Power returns the result of raising to a positive integer power -func (d LegacyDec) Power(power uint64) LegacyDec { - res := LegacyDec{new(big.Int).Set(d.i)} - return res.PowerMut(power) -} - -func (d LegacyDec) PowerMut(power uint64) LegacyDec { - if power == 0 { - // Set to 1 with the correct precision. - d.i.Set(precisionReuse) - return d - } - tmp := LegacyOneDec() - - for i := power; i > 1; { - if i%2 != 0 { - tmp.MulMut(d) - } - i /= 2 - d.MulMut(d) +// Mul returns a new Dec with value `x*y` (formatted as decimal128, with 34 digit precision) without +// mutating any argument and error if there is an overflow. +func (x Dec) Mul(y Dec) (Dec, error) { + var z Dec + if _, err := dec128Context.Mul(&z.dec, &x.dec, &y.dec); err != nil { + return z, ErrInvalidDec.Wrap(err.Error()) } - - return d.MulMut(tmp) -} - -// ApproxSqrt is a wrapper around ApproxRoot for the common special case -// of finding the square root of a number. It returns -(sqrt(abs(d)) if input is negative. -func (d LegacyDec) ApproxSqrt() (LegacyDec, error) { - return d.ApproxRoot(2) -} - -// IsInteger is integer, e.g. decimals are zero -func (d LegacyDec) IsInteger() bool { - return new(big.Int).Rem(d.i, precisionReuse).Sign() == 0 + return z, nil } -// Format format decimal state -func (d LegacyDec) Format(s fmt.State, verb rune) { - _, err := s.Write([]byte(d.String())) +// MulExact multiplies two Dec values x and y without rounding, using decimal128 precision. +// It returns an error if rounding is necessary to fit the result within the 34-digit limit. +// +// Example: +// - MulExact(Dec{1.234}, Dec{2.345}) -> Dec{2.893}, or ErrUnexpectedRounding if precision exceeded. +// +// Note: +// - This function does not alter the original Dec values. +func (x Dec) MulExact(y Dec) (Dec, error) { + var z Dec + condition, err := dec128Context.Mul(&z.dec, &x.dec, &y.dec) if err != nil { - panic(err) + return z, ErrInvalidDec.Wrap(err.Error()) } -} - -func (d LegacyDec) String() string { - if d.i == nil { - return d.i.String() + if condition.Rounded() { + return z, ErrUnexpectedRounding } - isNeg := d.IsNegative() - - if isNeg { - d = d.Neg() - } + return z, nil +} - bzInt, err := d.i.MarshalText() +// Modulo computes the remainder of division of x by y using decimal128 precision. +// It returns an error if y is zero or if any other error occurs during the computation. +// +// Example: +// - 7 mod 3 = 1 +// - 6 mod 3 = 0 +func (x Dec) Modulo(y Dec) (Dec, error) { + var z Dec + _, err := dec128Context.Rem(&z.dec, &x.dec, &y.dec) if err != nil { - return "" - } - inputSize := len(bzInt) - - var bzStr []byte - - // TODO: Remove trailing zeros - // case 1, purely decimal - if inputSize <= LegacyPrecision { - bzStr = make([]byte, LegacyPrecision+2) - - // 0. prefix - bzStr[0] = byte('0') - bzStr[1] = byte('.') - - // set relevant digits to 0 - for i := 0; i < LegacyPrecision-inputSize; i++ { - bzStr[i+2] = byte('0') - } - - // set final digits - copy(bzStr[2+(LegacyPrecision-inputSize):], bzInt) - } else { - // inputSize + 1 to account for the decimal point that is being added - bzStr = make([]byte, inputSize+1) - decPointPlace := inputSize - LegacyPrecision - - copy(bzStr, bzInt[:decPointPlace]) // pre-decimal digits - bzStr[decPointPlace] = byte('.') // decimal point - copy(bzStr[decPointPlace+1:], bzInt[decPointPlace:]) // post-decimal digits + return z, ErrInvalidDec.Wrap(err.Error()) } - - if isNeg { - return "-" + string(bzStr) - } - - return string(bzStr) -} - -// Float64 returns the float64 representation of a Dec. -// Will return the error if the conversion failed. -func (d LegacyDec) Float64() (float64, error) { - return strconv.ParseFloat(d.String(), 64) + return z, errors.Wrap(err, "decimal remainder error") } -// MustFloat64 returns the float64 representation of a Dec. -// Would panic if the conversion failed. -func (d LegacyDec) MustFloat64() float64 { - if value, err := strconv.ParseFloat(d.String(), 64); err != nil { - panic(err) - } else { - return value - } +// Int64 converts x to an int64 or returns an error if x cannot +// fit precisely into an int64. +func (x Dec) Int64() (int64, error) { + return x.dec.Int64() } -// ____ -// __| |__ "chop 'em -// ` \ round!" -// ___|| ~ _ -bankers -// | | __ -// | | | __|__|__ -// |_____: / | $$$ | -// |________| - -// Remove a Precision amount of rightmost digits and perform bankers rounding -// on the remainder (gaussian rounding) on the digits which have been removed. -// -// Mutates the input. Use the non-mutative version if that is undesired -func chopPrecisionAndRound(d *big.Int) *big.Int { - // remove the negative and add it back when returning - if d.Sign() == -1 { - // make d positive, compute chopped value, and then un-mutate d - d = d.Neg(d) - d = chopPrecisionAndRound(d) - d = d.Neg(d) - return d - } - - // get the truncated quotient and remainder - quo, rem := d, big.NewInt(0) - quo, rem = quo.QuoRem(d, precisionReuse, rem) - - if rem.Sign() == 0 { // remainder is zero - return quo - } - - switch rem.Cmp(fivePrecision) { - case -1: - return quo - case 1: - return quo.Add(quo, oneInt) - default: // bankers rounding must take place - // always round to an even number - if quo.Bit(0) == 0 { - return quo +// BigInt converts x to a *big.Int or returns an error if x cannot +// fit precisely into an *big.Int. +func (x Dec) BigInt() (*big.Int, error) { + y, _ := x.Reduce() + z, ok := new(big.Int).SetString(y.String(), 10) + if !ok { + return nil, ErrNonIntegral + } + return z, nil +} + +// SdkIntTrim rounds the decimal number towards zero to the nearest integer, then converts and returns it as `sdkmath.Int`. +// It handles both positive and negative values correctly by truncating towards zero. +// This function returns an ErrNonIntegral error if the resulting integer is larger than the maximum value that `sdkmath.Int` can represent. +func (x Dec) SdkIntTrim() (Int, error) { + y, _ := x.Reduce() + r := y.dec.Coeff + if y.dec.Exponent != 0 { + decs := apd.NewBigInt(10) + if y.dec.Exponent > 0 { + decs.Exp(decs, apd.NewBigInt(int64(y.dec.Exponent)), nil) + r.Mul(&y.dec.Coeff, decs) + } else { + decs.Exp(decs, apd.NewBigInt(int64(-y.dec.Exponent)), nil) + r.Quo(&y.dec.Coeff, decs) } - return quo.Add(quo, oneInt) } -} - -func chopPrecisionAndRoundUp(d *big.Int) *big.Int { - // remove the negative and add it back when returning - if d.Sign() == -1 { - // make d positive, compute chopped value, and then un-mutate d - d = d.Neg(d) - // truncate since d is negative... - chopPrecisionAndTruncate(d) - d = d.Neg(d) - return d + if x.dec.Negative { + r.Neg(&r) } - - // get the truncated quotient and remainder - quo, rem := d, big.NewInt(0) - quo, rem = quo.QuoRem(d, precisionReuse, rem) - - if rem.Sign() == 0 { // remainder is zero - return quo + bigInt := r.MathBigInt() + if bigInt.BitLen() > MaxBitLen { + return ZeroInt(), ErrNonIntegral } - - return quo.Add(quo, oneInt) + return NewIntFromBigInt(bigInt), nil } -func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int { - tmp := new(big.Int).Set(d) - return chopPrecisionAndRound(tmp) -} - -// RoundInt64 rounds the decimal using bankers rounding -func (d LegacyDec) RoundInt64() int64 { - chopped := chopPrecisionAndRoundNonMutative(d.i) - if !chopped.IsInt64() { - panic("Int64() out of bound") - } - return chopped.Int64() -} - -// RoundInt round the decimal using bankers rounding -func (d LegacyDec) RoundInt() Int { - return NewIntFromBigIntMut(chopPrecisionAndRoundNonMutative(d.i)) -} - -// chopPrecisionAndTruncate is similar to chopPrecisionAndRound, -// but always rounds down. It does not mutate the input. -func chopPrecisionAndTruncate(d *big.Int) { - d.Quo(d, precisionReuse) -} - -func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { - tmp := new(big.Int).Set(d) - chopPrecisionAndTruncate(tmp) - return tmp -} - -// TruncateInt64 truncates the decimals from the number and returns an int64 -func (d LegacyDec) TruncateInt64() int64 { - chopped := chopPrecisionAndTruncateNonMutative(d.i) - if !chopped.IsInt64() { - panic("Int64() out of bound") - } - return chopped.Int64() +// String formatted in decimal notation: '-ddddd.dddd', no exponent +func (x Dec) String() string { + return x.dec.Text('f') } -// TruncateInt truncates the decimals from the number and returns an Int -func (d LegacyDec) TruncateInt() Int { - return NewIntFromBigIntMut(chopPrecisionAndTruncateNonMutative(d.i)) +// Text converts the floating-point number x to a string according +// to the given format. The format is one of: +// +// 'e' -d.dddde±dd, decimal exponent, exponent digits +// 'E' -d.ddddE±dd, decimal exponent, exponent digits +// 'f' -ddddd.dddd, no exponent +// 'g' like 'e' for large exponents, like 'f' otherwise +// 'G' like 'E' for large exponents, like 'f' otherwise +// +// If format is a different character, Text returns a "%" followed by the +// unrecognized.Format character. The 'f' format has the possibility of +// displaying precision that is not present in the Decimal when it appends +// zeros (the 'g' format avoids the use of 'f' in this case). All other +// formats always show the exact precision of the Decimal. +func (x Dec) Text(format byte) string { + return x.dec.Text(format) } -// TruncateDec truncates the decimals from the number and returns a Dec -func (d LegacyDec) TruncateDec() LegacyDec { - return LegacyNewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) +// Cmp compares x and y and returns: +// -1 if x < y +// 0 if x == y +// +1 if x > y +// undefined if d or x are NaN +func (x Dec) Cmp(y Dec) int { + return x.dec.Cmp(&y.dec) } -// Ceil returns the smallest integer value (as a decimal) that is greater than -// or equal to the given decimal. -func (d LegacyDec) Ceil() LegacyDec { - tmp := new(big.Int).Set(d.i) - - quo, rem := tmp, big.NewInt(0) - quo, rem = quo.QuoRem(tmp, precisionReuse, rem) - - // no need to round with a zero remainder regardless of sign - var r LegacyDec - switch rem.Sign() { - case 0: - r = LegacyNewDecFromBigInt(quo) - case -1: - r = LegacyNewDecFromBigInt(quo) - default: - r = LegacyNewDecFromBigInt(quo.Add(quo, oneInt)) - } - r.assertInValidRange() - return r +// Equal checks if the decimal values of x and y are exactly equal. +// It returns true if both decimals represent the same value, otherwise false. +func (x Dec) Equal(y Dec) bool { + return x.dec.Cmp(&y.dec) == 0 } -// LegacyMaxSortableDec is the largest Dec that can be passed into SortableDecBytes() -// Its negative form is the least Dec that can be passed in. -var LegacyMaxSortableDec LegacyDec - -func init() { - LegacyMaxSortableDec = LegacyOneDec().Quo(LegacySmallestDec()) +// IsZero returns true if the decimal is zero. +func (x Dec) IsZero() bool { + return x.dec.IsZero() } -// LegacyValidSortableDec ensures that a Dec is within the sortable bounds, -// a Dec can't have a precision of less than 10^-18. -// Max sortable decimal was set to the reciprocal of SmallestDec. -func LegacyValidSortableDec(dec LegacyDec) bool { - return dec.Abs().LTE(LegacyMaxSortableDec) +// IsNegative returns true if the decimal is negative. +func (x Dec) IsNegative() bool { + return x.dec.Negative && !x.dec.IsZero() } -// LegacySortableDecBytes returns a byte slice representation of a Dec that can be sorted. -// Left and right pads with 0s so there are 18 digits to left and right of the decimal point. -// For this reason, there is a maximum and minimum value for this, enforced by ValidSortableDec. -func LegacySortableDecBytes(dec LegacyDec) []byte { - if !LegacyValidSortableDec(dec) { - panic("dec must be within bounds") - } - // Instead of adding an extra byte to all sortable decs in order to handle max sortable, we just - // makes its bytes be "max" which comes after all numbers in ASCIIbetical order - if dec.Equal(LegacyMaxSortableDec) { - return []byte("max") - } - // For the same reason, we make the bytes of minimum sortable dec be --, which comes before all numbers. - if dec.Equal(LegacyMaxSortableDec.Neg()) { - return []byte("--") - } - // We move the negative sign to the front of all the left padded 0s, to make negative numbers come before positive numbers - if dec.IsNegative() { - return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", LegacyPrecision*2+1), dec.Abs().String()))...) - } - return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", LegacyPrecision*2+1), dec.String())) +// IsPositive returns true if the decimal is positive. +func (x Dec) IsPositive() bool { + return !x.dec.Negative && !x.dec.IsZero() } -// reuse nil values -var nilJSON []byte - -func init() { - empty := new(big.Int) - bz, _ := empty.MarshalText() - nilJSON, _ = json.Marshal(string(bz)) +// IsFinite returns true if the decimal is finite. +func (x Dec) IsFinite() bool { + return x.dec.Form == apd.Finite } -// MarshalJSON marshals the decimal -func (d LegacyDec) MarshalJSON() ([]byte, error) { - if d.i == nil { - return nilJSON, nil +// NumDecimalPlaces returns the number of decimal places in x. +func (x Dec) NumDecimalPlaces() uint32 { + exp := x.dec.Exponent + if exp >= 0 { + return 0 } - return json.Marshal(d.String()) + return uint32(-exp) } -// UnmarshalJSON defines custom decoding scheme -func (d *LegacyDec) UnmarshalJSON(bz []byte) error { - if d.i == nil { - d.i = new(big.Int) - } - - var text string - err := json.Unmarshal(bz, &text) - if err != nil { - return err - } - - // TODO: Reuse dec allocation - newDec, err := LegacyNewDecFromStr(text) - if err != nil { - return err - } - - d.i = newDec.i - return nil +// Reduce returns a copy of x with all trailing zeros removed and the number of zeros that were removed. +// It does not modify the original decimal. +func (x Dec) Reduce() (Dec, int) { + y := Dec{} + _, n := y.dec.Reduce(&x.dec) + return y, n } -// MarshalYAML returns the YAML representation. -func (d LegacyDec) MarshalYAML() (interface{}, error) { - return d.String(), nil +func (x Dec) Marshal() ([]byte, error) { + // implemented in a new PR. See: https://github.com/cosmos/cosmos-sdk/issues/22525 + panic("not implemented") } -// Marshal implements the gogo proto custom type interface. -func (d LegacyDec) Marshal() ([]byte, error) { - i := d.i - if i == nil { - i = new(big.Int) - } - return i.MarshalText() +func (x *Dec) Unmarshal(data []byte) error { + // implemented in a new PR. See: https://github.com/cosmos/cosmos-sdk/issues/22525 + panic("not implemented") } -// MarshalTo implements the gogo proto custom type interface. -func (d *LegacyDec) MarshalTo(data []byte) (n int, err error) { - i := d.i - if i == nil { - i = new(big.Int) - } - - if i.Sign() == 0 { - copy(data, []byte{0x30}) - return 1, nil - } - - bz, err := d.Marshal() +// MarshalTo encodes the receiver into the provided byte slice and returns the number of bytes written and any error encountered. +func (x Dec) MarshalTo(data []byte) (n int, err error) { + bz, err := x.Marshal() if err != nil { return 0, err } - copy(data, bz) - return len(bz), nil + return copy(data, bz), nil } -// Unmarshal implements the gogo proto custom type interface. -func (d *LegacyDec) Unmarshal(data []byte) error { - if len(data) == 0 { - d = nil - return nil - } - - if d.i == nil { - d.i = new(big.Int) - } - - if err := d.i.UnmarshalText(data); err != nil { - return err - } - - if !d.IsInValidRange() { - return errors.New("decimal out of range") - } - return nil -} - -// Size implements the gogo proto custom type interface. -func (d *LegacyDec) Size() int { - bz, _ := d.Marshal() +// Size returns the number of bytes required to encode the Dec value, which is useful for determining storage requirements. +func (x Dec) Size() int { + bz, _ := x.Marshal() return len(bz) } -// MarshalAmino Override Amino binary serialization by proxying to protobuf. -func (d LegacyDec) MarshalAmino() ([]byte, error) { return d.Marshal() } -func (d *LegacyDec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } - -// helpers - -// LegacyDecsEqual return true if two decimal arrays are equal. -func LegacyDecsEqual(d1s, d2s []LegacyDec) bool { - if len(d1s) != len(d2s) { - return false - } - - for i, d1 := range d1s { - if !d1.Equal(d2s[i]) { - return false - } - } - return true -} - -// LegacyMinDec minimum decimal between two -func LegacyMinDec(d1, d2 LegacyDec) LegacyDec { - if d1.LT(d2) { - return d1 - } - return d2 -} - -// LegacyMaxDec maximum decimal between two -func LegacyMaxDec(d1, d2 LegacyDec) LegacyDec { - if d1.LT(d2) { - return d2 - } - return d1 -} - -// LegacyDecEq intended to be used with require/assert: require.True(DecEq(...)) -func LegacyDecEq(t *testing.T, exp, got LegacyDec) (*testing.T, bool, string, string, string) { - t.Helper() - return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String() +// MarshalJSON serializes the Dec struct into a JSON-encoded byte slice using scientific notation. +func (x Dec) MarshalJSON() ([]byte, error) { + return json.Marshal(x.dec.Text('E')) } -func LegacyDecApproxEq(t *testing.T, d1, d2, tol LegacyDec) (*testing.T, bool, string, string, string) { - t.Helper() - diff := d1.Sub(d2).Abs() - return t, diff.LTE(tol), "expected |d1 - d2| <:\t%v\ngot |d1 - d2| = \t\t%v", tol.String(), diff.String() -} - -// FormatDec formats a decimal (as encoded in protobuf) into a value-rendered -// string following ADR-050. This function operates with string manipulation -// (instead of manipulating the sdk.Dec object). -func FormatDec(v string) (string, error) { - parts := strings.Split(v, ".") - if len(parts) > 2 { - return "", fmt.Errorf("invalid decimal: too many points in %s", v) - } - - intPart, err := FormatInt(parts[0]) +// UnmarshalJSON implements the json.Unmarshaler interface for the Dec type, converting JSON strings to Dec objects. +func (x *Dec) UnmarshalJSON(data []byte) error { + var text string + err := json.Unmarshal(data, &text) if err != nil { - return "", err - } - - if len(parts) == 1 { - return intPart, nil - } - - decPart := strings.TrimRight(parts[1], "0") - if len(decPart) == 0 { - return intPart, nil + return err } - - // Ensure that the decimal part has only digits. - // https://github.com/cosmos/cosmos-sdk/issues/12811 - if !hasOnlyDigits(decPart) { - return "", fmt.Errorf("non-digits detected after decimal point in: %q", decPart) + val, err := NewDecFromString(text) + if err != nil { + return err } - - return intPart + "." + decPart, nil + *x = val + return nil } diff --git a/math/dec_bench_test.go b/math/dec_bench_test.go new file mode 100644 index 000000000000..52d79c8b4407 --- /dev/null +++ b/math/dec_bench_test.go @@ -0,0 +1,353 @@ +package math + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func BenchmarkCompareLegacyDecAndNewDecQuotient(b *testing.B) { + specs := map[string]struct { + dividend, divisor string + }{ + "small/ small": { + dividend: "100", divisor: "5", + }, + "big18/ small": { + dividend: "999999999999999999", divisor: "10", + }, + "self18/ self18": { + dividend: "999999999999999999", divisor: "999999999999999999", + }, + "big18/ big18": { + dividend: "888888888888888888", divisor: "444444444444444444", + }, + "decimal18b/ decimal18c": { + dividend: "8.88888888888888888", divisor: "4.1234567890123", + }, + "small/ big18": { + dividend: "100", divisor: "999999999999999999", + }, + "big34/ big34": { + dividend: "9999999999999999999999999999999999", divisor: "1999999999999999999999999999999999", + }, + "negative big34": { + dividend: "-9999999999999999999999999999999999", divisor: "999999999999999999999999999", + }, + "decimal small": { + dividend: "0.0000000001", divisor: "10", + }, + "decimal small/decimal small ": { + dividend: "0.0000000001", divisor: "0.0001", + }, + } + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + b.Run("LegacyDec", func(b *testing.B) { + dv, ds := LegacyMustNewDecFromStr(spec.dividend), LegacyMustNewDecFromStr(spec.divisor) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = dv.Quo(ds) + } + }) + + b.Run("NewDec", func(b *testing.B) { + dv, ds := must(NewDecFromString(spec.dividend)), must(NewDecFromString(spec.divisor)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = dv.Quo(ds) + } + }) + }) + } +} + +func BenchmarkCompareLegacyDecAndNewDecSum(b *testing.B) { + specs := map[string]struct { + summands []string + }{ + "1+2": { + summands: []string{"1", "2"}, + }, + "small numbers": { + summands: []string{"123", "0.2", "3.1415", "15"}, + }, + "medium numbers": { + summands: []string{"1234.567899", "9991345552.2340134"}, + }, + "big18": { + summands: []string{"123456789012345678", "123456789012345678", "123456789012345678", "123456789012345678", "123456789012345678", "123456789012345678"}, + }, + + "growing numbers": { + summands: []string{"1", "100", "1000", "100000", "10000000", "10000000000", "10000000000000", "100000000000000000"}, + }, + "decimals": { + summands: []string{"0.1", "0.01", "0.001", "0.000001", "0.00000001", "0.00000000001", "0.00000000000001", "0.000000000000000001"}, + }, + } + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + b.Run("LegacyDec", func(b *testing.B) { + summands := make([]LegacyDec, len(spec.summands)) + for i, s := range spec.summands { + summands[i] = LegacyMustNewDecFromStr(s) + } + sum := LegacyNewDec(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, s := range summands { + sum = sum.Add(s) + } + } + }) + + b.Run("NewDec", func(b *testing.B) { + summands := make([]Dec, len(spec.summands)) + for i, s := range spec.summands { + summands[i] = must(NewDecFromString(s)) + } + sum := NewDecFromInt64(0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, s := range summands { + sum, _ = sum.Add(s) + } + } + }) + }) + } +} + +func BenchmarkCompareLegacyDecAndNewDecSub(b *testing.B) { + specs := map[string]struct { + minuend string + subtrahends []string + }{ + "100 - 1 - 2": { + minuend: "100", + subtrahends: []string{"1", "2"}, + }, + "small numbers": { + minuend: "152.4013", + subtrahends: []string{"123", "0.2", "3.1415", "15"}, + }, + "10000000 - big18 numbers": { + minuend: "10000000", + subtrahends: []string{"123456789012345678", "123456789012345678", "123456789012345678", "123456789012345678", "123456789012345678", "123456789012345678"}, + }, + "10000000 - growing numbers": { + minuend: "10000000", + subtrahends: []string{"1", "100", "1000", "100000", "10000000", "10000000000", "10000000000000", "100000000000000000"}, + }, + "10000000 shrinking decimals": { + minuend: "10000000", + subtrahends: []string{"0.1", "0.01", "0.001", "0.000001", "0.00000001", "0.00000000001", "0.00000000000001", "0.000000000000000001"}, + }, + } + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + b.Run("LegacyDec", func(b *testing.B) { + summands := make([]LegacyDec, len(spec.subtrahends)) + for i, s := range spec.subtrahends { + summands[i] = LegacyMustNewDecFromStr(s) + } + diff := LegacyMustNewDecFromStr(spec.minuend) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, s := range summands { + diff = diff.Sub(s) + } + } + }) + + b.Run("NewDec", func(b *testing.B) { + summands := make([]Dec, len(spec.subtrahends)) + for i, s := range spec.subtrahends { + summands[i] = must(NewDecFromString(s)) + } + diff := must(NewDecFromString(spec.minuend)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, s := range summands { + diff, _ = diff.Sub(s) + } + } + }) + }) + } +} + +func BenchmarkCompareLegacyDecAndNewDecMul(b *testing.B) { + specs := map[string]struct { + multiplier, multiplicant string + }{ + "small/ small": { + multiplier: "100", multiplicant: "5", + }, + "big18/ small": { + multiplier: "999999999999999999", multiplicant: "10", + }, + "self18/ self18": { + multiplier: "999999999999999999", multiplicant: "999999999999999999", + }, + "big18/ big18": { + multiplier: "888888888888888888", multiplicant: "444444444444444444", + }, + "decimal18b/ decimal18c": { + multiplier: "8.88888888888888888", multiplicant: "4.1234567890123", + }, + "small/ big18": { + multiplier: "100", multiplicant: "999999999999999999", + }, + "big34/ big34": { + multiplier: "9999999999999999999999999999999999", multiplicant: "1999999999999999999999999999999999", + }, + "negative big34": { + multiplier: "-9999999999999999999999999999999999", multiplicant: "999999999999999999999999999", + }, + "decimal small": { + multiplier: "0.0000000001", multiplicant: "10", + }, + "decimal small/decimal small ": { + multiplier: "0.0000000001", multiplicant: "0.0001", + }, + } + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + b.Run("LegacyDec", func(b *testing.B) { + dv, ds := LegacyMustNewDecFromStr(spec.multiplier), LegacyMustNewDecFromStr(spec.multiplicant) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = dv.Mul(ds) + } + }) + + b.Run("NewDec", func(b *testing.B) { + dv, ds := must(NewDecFromString(spec.multiplier)), must(NewDecFromString(spec.multiplicant)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = dv.Mul(ds) + } + }) + }) + } +} + +func BenchmarkCompareLegacyDecAndNewDecMarshalUnmarshal(b *testing.B) { + specs := map[string]struct { + src string + }{ + "small": { + src: "1", + }, + "big18": { + src: "999999999999999999", + }, + "negative big34": { + src: "9999999999999999999999999999999999", + }, + "decimal": { + src: "12345.678901234341", + }, + } + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + b.Run("LegacyDec", func(b *testing.B) { + src := LegacyMustNewDecFromStr(spec.src) + b.ResetTimer() + for i := 0; i < b.N; i++ { + bz, err := src.Marshal() + require.NoError(b, err) + var d LegacyDec + require.NoError(b, d.Unmarshal(bz)) + } + }) + + b.Run("NewDec", func(b *testing.B) { + src := must(NewDecFromString(spec.src)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + bz, err := src.Marshal() + require.NoError(b, err) + var d Dec + require.NoError(b, d.Unmarshal(bz)) + } + }) + }) + } +} + +func BenchmarkCompareLegacyDecAndNewDecQuoInteger(b *testing.B) { + legacyB1 := LegacyNewDec(100) + newB1 := NewDecFromInt64(100) + + b.Run("LegacyDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = legacyB1.Quo(LegacyNewDec(1)) + } + }) + + b.Run("NewDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = newB1.QuoInteger(NewDecFromInt64(1)) + } + }) +} + +func BenchmarkCompareLegacyAddAndDecAdd(b *testing.B) { + legacyB1 := LegacyNewDec(100) + legacyB2 := LegacyNewDec(5) + newB1 := NewDecFromInt64(100) + newB2 := NewDecFromInt64(5) + + b.Run("LegacyDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = legacyB1.Add(legacyB2) + } + }) + + b.Run("NewDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = newB1.Add(newB2) + } + }) +} + +func BenchmarkCompareLegacySubAndDecMul(b *testing.B) { + legacyB1 := LegacyNewDec(100) + legacyB2 := LegacyNewDec(5) + newB1 := NewDecFromInt64(100) + newB2 := NewDecFromInt64(5) + + b.Run("LegacyDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = legacyB1.Mul(legacyB2) + } + }) + + b.Run("NewDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = newB1.Mul(newB2) + } + }) +} + +func BenchmarkCompareLegacySubAndDecSub(b *testing.B) { + legacyB1 := LegacyNewDec(100) + legacyB2 := LegacyNewDec(5) + newB1 := NewDecFromInt64(100) + newB2 := NewDecFromInt64(5) + + b.Run("LegacyDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = legacyB1.Sub(legacyB2) + } + }) + + b.Run("NewDec", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _ = newB1.Sub(newB2) + } + }) +} diff --git a/math/dec_examples_test.go b/math/dec_examples_test.go new file mode 100644 index 000000000000..5c2dc8a021ed --- /dev/null +++ b/math/dec_examples_test.go @@ -0,0 +1,323 @@ +package math + +import "fmt" + +func ExampleDec() { + d := NewDecFromInt64(1) // 1 + fmt.Println(d.String()) + + d = NewDecWithExp(-1234, -3) // -1.234 + fmt.Println(d.String()) + d = NewDecWithExp(1234, 0) // 1234 + fmt.Println(d.String()) + d = NewDecWithExp(1234, 1) // 12340 + fmt.Println(d.String()) + + // scientific notation + d, err := NewDecFromString("1.23E+4") // 12300 + if err != nil { + panic(err) + } + fmt.Println(d.String()) + + // decimal notation + d, err = NewDecFromString("1.234") + if err != nil { + panic(err) + } + fmt.Println(d.String()) + + // Output: 1 + // -1.234 + // 1234 + // 12340 + // 12300 + // 1.234 +} + +func ExampleDec_Add() { + sum, err := NewDecFromInt64(1).Add(NewDecFromInt64(1)) // 1 + 1 = 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + const maxExp = 100_000 + _, err = NewDecWithExp(1, maxExp).Add(NewDecFromInt64(1)) // 1E+1000000 + 1 + if err != nil { + fmt.Println(err.Error()) + } + + sum, err = NewDecWithExp(1, maxExp).Add(NewDecWithExp(1, maxExp)) // 1E+1000000 + 1E+1000000 + if err != nil { + panic(err) + } + fmt.Println(sum.Text('E')) + + // the max exponent must not be exceeded + _, err = NewDecWithExp(1, maxExp+1).Add(NewDecFromInt64(1)) // 1E+1000001 + 1 + if err != nil { + fmt.Println(err.Error()) + } + + const minExp = -100_000 + // same for min exponent + _, err = NewDecWithExp(1, minExp-1).Add(NewDecFromInt64(1)) // 1E-1000001 + 1 + if err != nil { + fmt.Println(err.Error()) + } + // not even by adding 0 + _, err = NewDecWithExp(1, minExp-1).Add(NewDecFromInt64(0)) // 1E-1000001 + 0 + if err != nil { + fmt.Println(err.Error()) + } + + // Output: 2 + // 2E+100000 + // add: exponent out of range: invalid decimal + // add: exponent out of range: invalid decimal + // add: exponent out of range: invalid decimal +} + +func ExampleDec_Sub() { + sum, err := NewDecFromInt64(2).Sub(NewDecFromInt64(1)) // 2 - 1 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + const maxExp = 100_000 + _, err = NewDecWithExp(1, maxExp).Sub(NewDecFromInt64(1)) // 1E+1000000 - 1 + if err != nil { + fmt.Println(err.Error()) + } + + sum, err = NewDecWithExp(1, maxExp).Sub(NewDecWithExp(1, maxExp)) // 1E+1000000 - 1E+1000000 + if err != nil { + panic(err) + } + fmt.Println(sum.Text('E')) + + // the max exponent must not be exceeded + _, err = NewDecWithExp(1, maxExp+1).Sub(NewDecFromInt64(1)) // 1E+1000001 - 1 + if err != nil { + fmt.Println(err.Error()) + } + + const minExp = -100_000 + // same for min exponent + _, err = NewDecWithExp(1, minExp-1).Sub(NewDecFromInt64(1)) // 1E-1000001 - 1 + if err != nil { + fmt.Println(err.Error()) + } + // not even by adding 0 + _, err = NewDecWithExp(1, minExp-1).Sub(NewDecFromInt64(0)) // 1E-1000001 - 0 + if err != nil { + fmt.Println(err.Error()) + } + + // Output: 1 + // 0E+100000 + // sub: exponent out of range: invalid decimal + // sub: exponent out of range: invalid decimal + // sub: exponent out of range: invalid decimal +} + +func ExampleDec_Quo() { + sum, err := NewDecFromInt64(6).Quo(NewDecFromInt64(2)) // 6 / 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(7).Quo(NewDecFromInt64(2)) // 7 / 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(4).Quo(NewDecFromInt64(9)) // 4 / 9 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + const minExp = -100_000 + sum, err = NewDecWithExp(1, minExp).Quo(NewDecFromInt64(10)) // 1e-100000 / 10 + if err != nil { + fmt.Println(err.Error()) + } + + sum, err = NewDecFromInt64(1).Quo(NewDecFromInt64(0)) // 1 / 0 -> error + if err != nil { + fmt.Println(err.Error()) + } + + // Output: 3.000000000000000000000000000000000 + // 3.500000000000000000000000000000000 + // 0.4444444444444444444444444444444444 + // exponent out of range: invalid decimal + // division by zero: invalid decimal +} + +func ExampleDec_QuoExact() { + sum, err := NewDecFromInt64(6).QuoExact(NewDecFromInt64(2)) // 6 / 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(7).QuoExact(NewDecFromInt64(2)) // 7 / 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(4).QuoExact(NewDecFromInt64(9)) // 4 / 9 -> error + if err != nil { + fmt.Println(err.Error()) + } + + const minExp = -100_000 + sum, err = NewDecWithExp(1, minExp).QuoExact(NewDecFromInt64(10)) // 1e-100000 / 10 -> error + if err != nil { + fmt.Println(err.Error()) + } + + sum, err = NewDecFromInt64(1).QuoExact(NewDecFromInt64(0)) // 1 / 0 -> error + if err != nil { + fmt.Println(err.Error()) + } + + // Output: 3.000000000000000000000000000000000 + // 3.500000000000000000000000000000000 + // unexpected rounding + // exponent out of range: invalid decimal + // division by zero: invalid decimal +} + +func ExampleDec_QuoInteger() { + sum, err := NewDecFromInt64(6).QuoInteger(NewDecFromInt64(2)) // 6 / 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(7).QuoInteger(NewDecFromInt64(2)) // 7 / 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(4).QuoInteger(NewDecFromInt64(9)) // 4 / 9 -> error + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + const minExp = -100_000 + sum, err = NewDecWithExp(1, minExp).QuoInteger(NewDecFromInt64(10)) // 1e-100000 / 10 -> 0 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(1).QuoInteger(NewDecFromInt64(0)) // 1 / 0 -> error + if err != nil { + fmt.Println(err.Error()) + } + + // Output: 3 + // 3 + // 0 + // 0 + // division by zero: invalid decimal +} + +func ExampleDec_Mul() { + sum, err := NewDecFromInt64(2).Mul(NewDecFromInt64(3)) // 2 * 3 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecWithExp(125, -2).Mul(NewDecFromInt64(2)) // 1.25 * 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + const maxExp = 100_000 + sum, err = NewDecWithExp(1, maxExp).Mul(NewDecFromInt64(10)) // 1e100000 * 10 -> err + if err != nil { + fmt.Println(err.Error()) + } + + sum, err = NewDecFromInt64(1).Mul(NewDecFromInt64(0)) // 1 * 0 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + // Output: 6 + // 2.50 + // exponent out of range: invalid decimal + // 0 +} + +func ExampleDec_MulExact() { + sum, err := NewDecFromInt64(2).MulExact(NewDecFromInt64(3)) // 2 * 3 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecWithExp(125, -2).MulExact(NewDecFromInt64(2)) // 1.25 * 2 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + const maxExp = 100_000 + sum, err = NewDecWithExp(1, maxExp).MulExact(NewDecFromInt64(10)) // 1e100000 * 10 -> err + if err != nil { + fmt.Println(err.Error()) + } + a, err := NewDecFromString("0.12345678901234567890123456789012345") // 35 digits after the comma + if err != nil { + panic(err) + } + sum, err = a.MulExact(NewDecFromInt64(1)) + if err != nil { + fmt.Println(err.Error()) + } + + sum, err = a.MulExact(NewDecFromInt64(0)) + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + sum, err = NewDecFromInt64(1).MulExact(NewDecFromInt64(0)) // 1 * 0 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + // Output: 6 + // 2.50 + // exponent out of range: invalid decimal + // unexpected rounding + // 0.00000000000000000000000000000000000 + // 0 +} + +func ExampleDec_Modulo() { + sum, err := NewDecFromInt64(7).Modulo(NewDecFromInt64(3)) // 7 mod 3 = 1 + if err != nil { + panic(err) + } + fmt.Println(sum.String()) + + // Output: 1 +} diff --git a/math/dec_rapid_test.go b/math/dec_rapid_test.go new file mode 100644 index 000000000000..8a1830b86694 --- /dev/null +++ b/math/dec_rapid_test.go @@ -0,0 +1,527 @@ +package math + +import ( + "fmt" + "regexp" + "strconv" + "testing" + + "github.com/stretchr/testify/require" + "pgregory.net/rapid" +) + +// Rapid is a Go library for property-based testing. +func TestDecWithRapid(t *testing.T) { + // Property tests + t.Run("TestNewDecFromInt64", rapid.MakeCheck(testDecInt64)) + + // Properties about *FromString functions + t.Run("TestInvalidNewDecFromString", rapid.MakeCheck(testInvalidNewDecFromString)) + + // Properties about addition + t.Run("TestAddLeftIdentity", rapid.MakeCheck(testAddLeftIdentity)) + t.Run("TestAddRightIdentity", rapid.MakeCheck(testAddRightIdentity)) + t.Run("TestAddCommutative", rapid.MakeCheck(testAddCommutative)) + t.Run("TestAddAssociative", rapid.MakeCheck(testAddAssociative)) + + // Properties about subtraction + t.Run("TestSubRightIdentity", rapid.MakeCheck(testSubRightIdentity)) + t.Run("TestSubZero", rapid.MakeCheck(testSubZero)) + + // Properties about multiplication + t.Run("TestMulLeftIdentity", rapid.MakeCheck(testMulLeftIdentity)) + t.Run("TestMulRightIdentity", rapid.MakeCheck(testMulRightIdentity)) + t.Run("TestMulCommutative", rapid.MakeCheck(testMulCommutative)) + t.Run("TestMulAssociative", rapid.MakeCheck(testMulAssociative)) + t.Run("TestZeroIdentity", rapid.MakeCheck(testMulZero)) + + // Properties about division + t.Run("TestDivisionBySelf", rapid.MakeCheck(testSelfQuo)) + t.Run("TestDivisionByOne", rapid.MakeCheck(testQuoByOne)) + + // Properties combining operations + t.Run("TestSubAdd", rapid.MakeCheck(testSubAdd)) + t.Run("TestAddSub", rapid.MakeCheck(testAddSub)) + t.Run("TestMulQuoA", rapid.MakeCheck(testMulQuoA)) + t.Run("TestMulQuoB", rapid.MakeCheck(testMulQuoB)) + t.Run("TestMulQuoExact", rapid.MakeCheck(testMulQuoExact)) + t.Run("TestQuoMulExact", rapid.MakeCheck(testQuoMulExact)) + + // Properties about comparison and equality + t.Run("TestCmpInverse", rapid.MakeCheck(testCmpInverse)) + t.Run("TestEqualCommutative", rapid.MakeCheck(testEqualCommutative)) + + // Properties about tests on a single Dec + t.Run("TestIsZero", rapid.MakeCheck(testIsZero)) + t.Run("TestIsNegative", rapid.MakeCheck(testIsNegative)) + t.Run("TestIsPositive", rapid.MakeCheck(testIsPositive)) + t.Run("TestNumDecimalPlaces", rapid.MakeCheck(testNumDecimalPlaces)) + + // Unit tests + zero := Dec{} + one := NewDecFromInt64(1) + two := NewDecFromInt64(2) + three := NewDecFromInt64(3) + four := NewDecFromInt64(4) + five := NewDecFromInt64(5) + minusOne := NewDecFromInt64(-1) + + onePointOneFive, err := NewDecFromString("1.15") + require.NoError(t, err) + twoPointThreeFour, err := NewDecFromString("2.34") + require.NoError(t, err) + threePointFourNine, err := NewDecFromString("3.49") + require.NoError(t, err) + onePointFourNine, err := NewDecFromString("1.49") + require.NoError(t, err) + minusFivePointZero, err := NewDecFromString("-5.0") + require.NoError(t, err) + + twoThousand := NewDecWithExp(2, 3) + require.True(t, twoThousand.Equal(NewDecFromInt64(2000))) + + res, err := two.Add(zero) + require.NoError(t, err) + require.True(t, res.Equal(two)) + + res, err = five.Sub(two) + require.NoError(t, err) + require.True(t, res.Equal(three)) + + res, err = four.Quo(two) + require.NoError(t, err) + require.True(t, res.Equal(two)) + + res, err = five.QuoInteger(two) + require.NoError(t, err) + require.True(t, res.Equal(two)) + + res, err = five.Modulo(two) + require.NoError(t, err) + require.True(t, res.Equal(one)) + + x, err := four.Int64() + require.NoError(t, err) + require.Equal(t, int64(4), x) + + require.Equal(t, "5", five.String()) + + res, err = onePointOneFive.Add(twoPointThreeFour) + require.NoError(t, err) + require.True(t, res.Equal(threePointFourNine)) + + res, err = threePointFourNine.Sub(two) + require.NoError(t, err) + require.True(t, res.Equal(onePointFourNine)) + + res, err = minusOne.Sub(four) + require.NoError(t, err) + require.True(t, res.Equal(minusFivePointZero)) + + require.True(t, zero.IsZero()) + require.False(t, zero.IsPositive()) + require.False(t, zero.IsNegative()) + + require.False(t, one.IsZero()) + require.True(t, one.IsPositive()) + require.False(t, one.IsNegative()) + + require.False(t, minusOne.IsZero()) + require.False(t, minusOne.IsPositive()) + require.True(t, minusOne.IsNegative()) + + res, err = one.MulExact(two) + require.NoError(t, err) + require.True(t, res.Equal(two)) +} + +var genDec *rapid.Generator[Dec] = rapid.Custom(func(t *rapid.T) Dec { + f := rapid.Float64().Draw(t, "f") + dec, err := NewDecFromString(fmt.Sprintf("%g", f)) + require.NoError(t, err) + return dec +}) + +// A Dec value and the float used to create it +type floatAndDec struct { + float float64 + dec Dec +} + +// Generate a Dec value along with the float used to create it +var genFloatAndDec *rapid.Generator[floatAndDec] = rapid.Custom(func(t *rapid.T) floatAndDec { + f := rapid.Float64().Draw(t, "f") + dec, err := NewDecFromString(fmt.Sprintf("%g", f)) + require.NoError(t, err) + return floatAndDec{f, dec} +}) + +// Property: n == NewDecFromInt64(n).Int64() +func testDecInt64(t *rapid.T) { + nIn := rapid.Int64().Draw(t, "n") + nOut, err := NewDecFromInt64(nIn).Int64() + + require.NoError(t, err) + require.Equal(t, nIn, nOut) +} + +// Property: invalid_number_string(s) => NewDecFromString(s) == err +func testInvalidNewDecFromString(t *rapid.T) { + s := rapid.StringMatching("[[:alpha:]]+").Draw(t, "s") + _, err := NewDecFromString(s) + require.Error(t, err) +} + +// Property: 0 + a == a +func testAddLeftIdentity(t *rapid.T) { + a := genDec.Draw(t, "a") + zero := NewDecFromInt64(0) + + b, err := zero.Add(a) + require.NoError(t, err) + + require.True(t, a.Equal(b)) +} + +// Property: a + 0 == a +func testAddRightIdentity(t *rapid.T) { + a := genDec.Draw(t, "a") + zero := NewDecFromInt64(0) + + b, err := a.Add(zero) + require.NoError(t, err) + + require.True(t, a.Equal(b)) +} + +// Property: a + b == b + a +func testAddCommutative(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + + c, err := a.Add(b) + require.NoError(t, err) + + d, err := b.Add(a) + require.NoError(t, err) + + require.True(t, c.Equal(d)) +} + +// Property: (a + b) + c == a + (b + c) +func testAddAssociative(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + c := genDec.Draw(t, "c") + + // (a + b) + c + d, err := a.Add(b) + require.NoError(t, err) + + e, err := d.Add(c) + require.NoError(t, err) + + // a + (b + c) + f, err := b.Add(c) + require.NoError(t, err) + + g, err := a.Add(f) + require.NoError(t, err) + + require.True(t, e.Equal(g)) +} + +// Property: a - 0 == a +func testSubRightIdentity(t *rapid.T) { + a := genDec.Draw(t, "a") + zero := NewDecFromInt64(0) + + b, err := a.Sub(zero) + require.NoError(t, err) + + require.True(t, a.Equal(b)) +} + +// Property: a - a == 0 +func testSubZero(t *rapid.T) { + a := genDec.Draw(t, "a") + zero := NewDecFromInt64(0) + + b, err := a.Sub(a) + require.NoError(t, err) + + require.True(t, b.Equal(zero)) +} + +// Property: 1 * a == a +func testMulLeftIdentity(t *rapid.T) { + a := genDec.Draw(t, "a") + one := NewDecFromInt64(1) + + b, err := one.Mul(a) + require.NoError(t, err) + + require.True(t, a.Equal(b)) +} + +// Property: a * 1 == a +func testMulRightIdentity(t *rapid.T) { + a := genDec.Draw(t, "a") + one := NewDecFromInt64(1) + + b, err := a.Mul(one) + require.NoError(t, err) + + require.True(t, a.Equal(b)) +} + +// Property: a * b == b * a +func testMulCommutative(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + + c, err := a.Mul(b) + require.NoError(t, err) + + d, err := b.Mul(a) + require.NoError(t, err) + + require.True(t, c.Equal(d)) +} + +// Property: (a * b) * c == a * (b * c) +func testMulAssociative(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + c := genDec.Draw(t, "c") + + // (a * b) * c + d, err := a.Mul(b) + require.NoError(t, err) + + e, err := d.Mul(c) + require.NoError(t, err) + + // a * (b * c) + f, err := b.Mul(c) + require.NoError(t, err) + + g, err := a.Mul(f) + require.NoError(t, err) + + require.True(t, e.Equal(g)) +} + +// Property: (a - b) + b == a +func testSubAdd(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + + c, err := a.Sub(b) + require.NoError(t, err) + + d, err := c.Add(b) + require.NoError(t, err) + + require.True(t, a.Equal(d)) +} + +// Property: (a + b) - b == a +func testAddSub(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + + c, err := a.Add(b) + require.NoError(t, err) + + d, err := c.Sub(b) + require.NoError(t, err) + + require.True(t, a.Equal(d)) +} + +// Property: a * 0 = 0 +func testMulZero(t *rapid.T) { + a := genDec.Draw(t, "a") + zero := Dec{} + + c, err := a.Mul(zero) + require.NoError(t, err) + require.True(t, c.IsZero()) +} + +// Property: a/a = 1 +func testSelfQuo(t *rapid.T) { + decNotZero := func(d Dec) bool { return !d.IsZero() } + a := genDec.Filter(decNotZero).Draw(t, "a") + one := NewDecFromInt64(1) + + b, err := a.Quo(a) + require.NoError(t, err) + require.True(t, one.Equal(b)) +} + +// Property: a/1 = a +func testQuoByOne(t *rapid.T) { + a := genDec.Draw(t, "a") + one := NewDecFromInt64(1) + + b, err := a.Quo(one) + require.NoError(t, err) + require.True(t, a.Equal(b)) +} + +// Property: (a * b) / a == b +func testMulQuoA(t *rapid.T) { + decNotZero := func(d Dec) bool { return !d.IsZero() } + a := genDec.Filter(decNotZero).Draw(t, "a") + b := genDec.Draw(t, "b") + + c, err := a.Mul(b) + require.NoError(t, err) + + d, err := c.Quo(a) + require.NoError(t, err) + + require.True(t, b.Equal(d)) +} + +// Property: (a * b) / b == a +func testMulQuoB(t *rapid.T) { + decNotZero := func(d Dec) bool { return !d.IsZero() } + a := genDec.Draw(t, "a") + b := genDec.Filter(decNotZero).Draw(t, "b") + + c, err := a.Mul(b) + require.NoError(t, err) + + d, err := c.Quo(b) + require.NoError(t, err) + + require.True(t, a.Equal(d)) +} + +// Property: (a * 10^b) / 10^b == a using MulExact and QuoExact +// and a with no more than b decimal places (b <= 32). +func testMulQuoExact(t *rapid.T) { + b := rapid.Uint32Range(0, 32).Draw(t, "b") + decPrec := func(d Dec) bool { return d.NumDecimalPlaces() <= b } + a := genDec.Filter(decPrec).Draw(t, "a") + + c := NewDecWithExp(1, int32(b)) + + d, err := a.MulExact(c) + require.NoError(t, err) + + e, err := d.QuoExact(c) + require.NoError(t, err) + + require.True(t, a.Equal(e)) +} + +// Property: (a / b) * b == a using QuoExact and MulExact and +// a as an integer. +func testQuoMulExact(t *rapid.T) { + a := rapid.Uint64().Draw(t, "a") + aDec, err := NewDecFromString(fmt.Sprintf("%d", a)) + require.NoError(t, err) + b := rapid.Uint32Range(0, 32).Draw(t, "b") + c := NewDecWithExp(1, int32(b)) + + require.NoError(t, err) + + d, err := aDec.QuoExact(c) + require.NoError(t, err) + + e, err := d.MulExact(c) + require.NoError(t, err) + + require.True(t, aDec.Equal(e)) +} + +// Property: Cmp(a, b) == -Cmp(b, a) +func testCmpInverse(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + + require.Equal(t, a.Cmp(b), -b.Cmp(a)) +} + +// Property: Equal(a, b) == Equal(b, a) +func testEqualCommutative(t *rapid.T) { + a := genDec.Draw(t, "a") + b := genDec.Draw(t, "b") + + require.Equal(t, a.Equal(b), b.Equal(a)) +} + +// Property: isZero(f) == isZero(NewDecFromString(f.String())) +func testIsZero(t *rapid.T) { + floatAndDec := genFloatAndDec.Draw(t, "floatAndDec") + f, dec := floatAndDec.float, floatAndDec.dec + + require.Equal(t, f == 0, dec.IsZero()) +} + +// Property: isNegative(f) == isNegative(NewDecFromString(f.String())) +func testIsNegative(t *rapid.T) { + floatAndDec := genFloatAndDec.Draw(t, "floatAndDec") + f, dec := floatAndDec.float, floatAndDec.dec + + require.Equal(t, f < 0, dec.IsNegative()) +} + +// Property: isPositive(f) == isPositive(NewDecFromString(f.String())) +func testIsPositive(t *rapid.T) { + floatAndDec := genFloatAndDec.Draw(t, "floatAndDec") + f, dec := floatAndDec.float, floatAndDec.dec + + require.Equal(t, f > 0, dec.IsPositive()) +} + +// Property: floatDecimalPlaces(f) == NumDecimalPlaces(NewDecFromString(f.String())) +func testNumDecimalPlaces(t *rapid.T) { + floatAndDec := genFloatAndDec.Draw(t, "floatAndDec") + f, dec := floatAndDec.float, floatAndDec.dec + + require.Equal(t, floatDecimalPlaces(t, f), dec.NumDecimalPlaces()) +} + +func floatDecimalPlaces(t *rapid.T, f float64) uint32 { + reScientific := regexp.MustCompile(`^\-?(?:[[:digit:]]+(?:\.([[:digit:]]+))?|\.([[:digit:]]+))(?:e?(?:\+?([[:digit:]]+)|(-[[:digit:]]+)))?$`) + fStr := fmt.Sprintf("%g", f) + matches := reScientific.FindAllStringSubmatch(fStr, 1) + if len(matches) != 1 { + t.Fatalf("Didn't match float: %g", f) + } + + // basePlaces is the number of decimal places in the decimal part of the + // string + basePlaces := 0 + if matches[0][1] != "" { + basePlaces = len(matches[0][1]) + } else if matches[0][2] != "" { + basePlaces = len(matches[0][2]) + } + t.Logf("Base places: %d", basePlaces) + + // exp is the exponent + exp := 0 + if matches[0][3] != "" { + var err error + exp, err = strconv.Atoi(matches[0][3]) + require.NoError(t, err) + } else if matches[0][4] != "" { + var err error + exp, err = strconv.Atoi(matches[0][4]) + require.NoError(t, err) + } + + // Subtract exponent from base and check if negative + res := basePlaces - exp + if res <= 0 { + return 0 + } + + return uint32(res) +} diff --git a/math/dec_test.go b/math/dec_test.go index 4f3897a0867e..ef4c9fbd5de3 100644 --- a/math/dec_test.go +++ b/math/dec_test.go @@ -1,1329 +1,1412 @@ -package math_test +package math import ( - "bytes" - "encoding/json" "fmt" - "math/big" - "os" + "math" + "strconv" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "sigs.k8s.io/yaml" - - "cosmossdk.io/math" ) -type decimalTestSuite struct { - suite.Suite -} - -func TestDecimalTestSuite(t *testing.T) { - suite.Run(t, new(decimalTestSuite)) -} - -func TestDecApproxEq(t *testing.T) { - // d1 = 0.55, d2 = 0.6, tol = 0.1 - d1 := math.LegacyNewDecWithPrec(55, 2) - d2 := math.LegacyNewDecWithPrec(6, 1) - tol := math.LegacyNewDecWithPrec(1, 1) - - require.True(math.LegacyDecApproxEq(t, d1, d2, tol)) - - // d1 = 0.55, d2 = 0.6, tol = 1E-5 - d1 = math.LegacyNewDecWithPrec(55, 2) - d2 = math.LegacyNewDecWithPrec(6, 1) - tol = math.LegacyNewDecWithPrec(1, 5) - - require.False(math.LegacyDecApproxEq(t, d1, d2, tol)) - - // d1 = 0.6, d2 = 0.61, tol = 0.01 - d1 = math.LegacyNewDecWithPrec(6, 1) - d2 = math.LegacyNewDecWithPrec(61, 2) - tol = math.LegacyNewDecWithPrec(1, 2) - - require.True(math.LegacyDecApproxEq(t, d1, d2, tol)) -} - -// create a decimal from a decimal string (ex. "1234.5678") -func (s *decimalTestSuite) mustNewDecFromStr(str string) (d math.LegacyDec) { - d, err := math.LegacyNewDecFromStr(str) - s.Require().NoError(err) - - return d -} - -func (s *decimalTestSuite) TestNewDecFromStr() { - largeBigInt, ok := new(big.Int).SetString("3144605511029693144278234343371835", 10) - s.Require().True(ok) - - largerBigInt, ok := new(big.Int).SetString("8888888888888888888888888888888888888888888888888888888888888888888844444440", 10) - s.Require().True(ok) - - largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) - s.Require().True(ok) - - tests := []struct { - decimalStr string - expErr bool - exp math.LegacyDec - }{ - {"", true, math.LegacyDec{}}, - {"0.-75", true, math.LegacyDec{}}, - {"0", false, math.LegacyNewDec(0)}, - {"1", false, math.LegacyNewDec(1)}, - {"1.1", false, math.LegacyNewDecWithPrec(11, 1)}, - {"0.75", false, math.LegacyNewDecWithPrec(75, 2)}, - {"0.8", false, math.LegacyNewDecWithPrec(8, 1)}, - {"0.11111", false, math.LegacyNewDecWithPrec(11111, 5)}, - {"314460551102969.3144278234343371835", true, math.LegacyNewDec(3141203149163817869)}, - { - "314460551102969314427823434337.1835718092488231350", - true, math.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4), - }, - { - "314460551102969314427823434337.1835", - false, math.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4), - }, - {".", true, math.LegacyDec{}}, - {".0", true, math.LegacyNewDec(0)}, - {"1.", true, math.LegacyNewDec(1)}, - {"foobar", true, math.LegacyDec{}}, - {"0.foobar", true, math.LegacyDec{}}, - {"0.foobar.", true, math.LegacyDec{}}, - {"8888888888888888888888888888888888888888888888888888888888888888888844444440", false, math.LegacyNewDecFromBigInt(largerBigInt)}, - {"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535", false, math.LegacyNewDecFromBigIntWithPrec(largestBigInt, 18)}, - {"133499189745056880149688856635597007162669032647290798121690100488888732861291", true, math.LegacyDec{}}, - {"115792089237316195423570985008687907853269984665640564039457584007913129639936", true, math.LegacyDec{}}, // 2^256 - } - - for tcIndex, tc := range tests { - res, err := math.LegacyNewDecFromStr(tc.decimalStr) - if tc.expErr { - s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - } else { - s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - s.Require().True(res.Equal(tc.exp), "equality was incorrect, res %v, expTruncated %v, tc %v", res, tc.exp, tcIndex) - } - - // negative tc - res, err = math.LegacyNewDecFromStr("-" + tc.decimalStr) - if tc.expErr { - s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - } else { - s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - exp := tc.exp.Mul(math.LegacyNewDec(-1)) - s.Require().True(res.Equal(exp), "equality was incorrect, res %v, expTruncated %v, tc %v", res, exp, tcIndex) - } - } -} - -func (s *decimalTestSuite) TestDecString() { - tests := []struct { - d math.LegacyDec - want string - }{ - {math.LegacyNewDec(0), "0.000000000000000000"}, - {math.LegacyNewDec(1), "1.000000000000000000"}, - {math.LegacyNewDec(10), "10.000000000000000000"}, - {math.LegacyNewDec(12340), "12340.000000000000000000"}, - {math.LegacyNewDecWithPrec(12340, 4), "1.234000000000000000"}, - {math.LegacyNewDecWithPrec(12340, 5), "0.123400000000000000"}, - {math.LegacyNewDecWithPrec(12340, 8), "0.000123400000000000"}, - {math.LegacyNewDecWithPrec(1009009009009009009, 17), "10.090090090090090090"}, - } - for tcIndex, tc := range tests { - s.Require().Equal(tc.want, tc.d.String(), "bad String(), index: %v", tcIndex) - } -} - -func (s *decimalTestSuite) TestDecFloat64() { - tests := []struct { - d math.LegacyDec - want float64 - }{ - {math.LegacyNewDec(0), 0.000000000000000000}, - {math.LegacyNewDec(1), 1.000000000000000000}, - {math.LegacyNewDec(10), 10.000000000000000000}, - {math.LegacyNewDec(12340), 12340.000000000000000000}, - {math.LegacyNewDecWithPrec(12340, 4), 1.234000000000000000}, - {math.LegacyNewDecWithPrec(12340, 5), 0.123400000000000000}, - {math.LegacyNewDecWithPrec(12340, 8), 0.000123400000000000}, - {math.LegacyNewDecWithPrec(1009009009009009009, 17), 10.090090090090090090}, - } - for tcIndex, tc := range tests { - value, err := tc.d.Float64() - s.Require().Nil(err, "error getting Float64(), index: %v", tcIndex) - s.Require().Equal(tc.want, value, "bad Float64(), index: %v", tcIndex) - s.Require().Equal(tc.want, tc.d.MustFloat64(), "bad MustFloat64(), index: %v", tcIndex) - } -} - -func (s *decimalTestSuite) TestEqualities() { - tests := []struct { - d1, d2 math.LegacyDec - gt, lt, eq bool - }{ - {math.LegacyNewDec(0), math.LegacyNewDec(0), false, false, true}, - {math.LegacyNewDecWithPrec(0, 2), math.LegacyNewDecWithPrec(0, 4), false, false, true}, - {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(100, 0), false, false, true}, - {math.LegacyNewDecWithPrec(-100, 0), math.LegacyNewDecWithPrec(-100, 0), false, false, true}, - {math.LegacyNewDecWithPrec(-1, 1), math.LegacyNewDecWithPrec(-1, 1), false, false, true}, - {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(3333, 3), false, false, true}, - - {math.LegacyNewDecWithPrec(0, 0), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, - {math.LegacyNewDecWithPrec(0, 0), math.LegacyNewDecWithPrec(100, 0), false, true, false}, - {math.LegacyNewDecWithPrec(-1, 0), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, - {math.LegacyNewDecWithPrec(-1, 0), math.LegacyNewDecWithPrec(100, 0), false, true, false}, - {math.LegacyNewDecWithPrec(1111, 3), math.LegacyNewDecWithPrec(100, 0), false, true, false}, - {math.LegacyNewDecWithPrec(1111, 3), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, - {math.LegacyNewDecWithPrec(-3333, 3), math.LegacyNewDecWithPrec(-1111, 3), false, true, false}, - - {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(0, 0), true, false, false}, - {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(0, 0), true, false, false}, - {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(-1, 0), true, false, false}, - {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(-1, 0), true, false, false}, - {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(1111, 3), true, false, false}, - {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(1111, 3), true, false, false}, - {math.LegacyNewDecWithPrec(-1111, 3), math.LegacyNewDecWithPrec(-3333, 3), true, false, false}, - } - - for tcIndex, tc := range tests { - s.Require().Equal(tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc %d", tcIndex) - s.Require().Equal(tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc %d", tcIndex) - s.Require().Equal(tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestDecsEqual() { - tests := []struct { - d1s, d2s []math.LegacyDec - eq bool - }{ - {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(0)}, true}, - {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1)}, false}, - {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{}, false}, - {[]math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, []math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, true}, - {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, true}, - {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, false}, - {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1)}, false}, - {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(2)}, []math.LegacyDec{math.LegacyNewDec(2), math.LegacyNewDec(4)}, false}, - {[]math.LegacyDec{math.LegacyNewDec(3), math.LegacyNewDec(18)}, []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(6)}, false}, - } - - for tcIndex, tc := range tests { - s.Require().Equal(tc.eq, math.LegacyDecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) - s.Require().Equal(tc.eq, math.LegacyDecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestArithmetic() { - tests := []struct { - d1, d2 math.LegacyDec - expMul, expMulTruncate, expMulRoundUp math.LegacyDec - expQuo, expQuoRoundUp, expQuoTruncate math.LegacyDec - expAdd, expSub math.LegacyDec +func TestNewDecFromString(t *testing.T) { + specs := map[string]struct { + src string + exp Dec + expErr error }{ - // d1 d2 MUL MulTruncate MulRoundUp QUO QUORoundUp QUOTrunctate ADD SUB - {math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0)}, - {math.LegacyNewDec(1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(1)}, - {math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(-1)}, - {math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(1)}, - {math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(-1)}, - - {math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(2), math.LegacyNewDec(0)}, - {math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(-2), math.LegacyNewDec(0)}, - {math.LegacyNewDec(1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(2)}, - {math.LegacyNewDec(-1), math.LegacyNewDec(1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(-2)}, - - { - math.LegacyNewDec(3), math.LegacyNewDec(7), math.LegacyNewDec(21), math.LegacyNewDec(21), math.LegacyNewDec(21), - math.LegacyNewDecWithPrec(428571428571428571, 18), math.LegacyNewDecWithPrec(428571428571428572, 18), math.LegacyNewDecWithPrec(428571428571428571, 18), - math.LegacyNewDec(10), math.LegacyNewDec(-4), + "simple decimal": { + src: "1", + exp: NewDecFromInt64(1), }, - { - math.LegacyNewDec(2), math.LegacyNewDec(4), math.LegacyNewDec(8), math.LegacyNewDec(8), math.LegacyNewDec(8), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), - math.LegacyNewDec(6), math.LegacyNewDec(-2), + "simple negative decimal": { + src: "-1", + exp: NewDecFromInt64(-1), }, - - {math.LegacyNewDec(100), math.LegacyNewDec(100), math.LegacyNewDec(10000), math.LegacyNewDec(10000), math.LegacyNewDec(10000), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(200), math.LegacyNewDec(0)}, - - { - math.LegacyNewDecWithPrec(15, 1), math.LegacyNewDecWithPrec(15, 1), math.LegacyNewDecWithPrec(225, 2), math.LegacyNewDecWithPrec(225, 2), math.LegacyNewDecWithPrec(225, 2), - math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(3), math.LegacyNewDec(0), + "valid decimal with decimal places": { + src: "1.234", + exp: NewDecWithExp(1234, -3), }, - { - math.LegacyNewDecWithPrec(3333, 4), math.LegacyNewDecWithPrec(333, 4), math.LegacyNewDecWithPrec(1109889, 8), math.LegacyNewDecWithPrec(1109889, 8), math.LegacyNewDecWithPrec(1109889, 8), - math.LegacyMustNewDecFromStr("10.009009009009009009"), math.LegacyMustNewDecFromStr("10.009009009009009010"), math.LegacyMustNewDecFromStr("10.009009009009009009"), - math.LegacyNewDecWithPrec(3666, 4), math.LegacyNewDecWithPrec(3, 1), + "valid negative decimal": { + src: "-1.234", + exp: NewDecWithExp(-1234, -3), + }, + "min decimal": { + src: "-" + strings.Repeat("9", 34), + exp: must(NewDecWithExp(-1, 34).Add(NewDecFromInt64(1))), + }, + "max decimal": { + src: strings.Repeat("9", 34), + exp: must(NewDecWithExp(1, 34).Sub(NewDecFromInt64(1))), + }, + "too big": { + src: strings.Repeat("9", 100_0000), + expErr: ErrInvalidDec, + }, + "too small": { + src: "-" + strings.Repeat("9", 100_0000), + expErr: ErrInvalidDec, + }, + "valid decimal with leading zero": { + src: "01234", + exp: NewDecWithExp(1234, 0), + }, + "valid decimal without leading zero": { + src: ".1234", + exp: NewDecWithExp(1234, -4), }, - } - - for tcIndex, tc := range tests { - - resAdd := tc.d1.Add(tc.d2) - resSub := tc.d1.Sub(tc.d2) - resMul := tc.d1.Mul(tc.d2) - resMulTruncate := tc.d1.MulTruncate(tc.d2) - resMulRoundUp := tc.d1.MulRoundUp(tc.d2) - s.Require().True(tc.expAdd.Equal(resAdd), "expTruncated %v, res %v, tc %d", tc.expAdd, resAdd, tcIndex) - s.Require().True(tc.expSub.Equal(resSub), "expTruncated %v, res %v, tc %d", tc.expSub, resSub, tcIndex) - s.Require().True(tc.expMul.Equal(resMul), "expTruncated %v, res %v, tc %d", tc.expMul, resMul, tcIndex) - s.Require().True(tc.expMulTruncate.Equal(resMulTruncate), "expTruncated %v, res %v, tc %d", tc.expMulTruncate, resMulTruncate, tcIndex) - s.Require().True(tc.expMulRoundUp.Equal(resMulRoundUp), "expTruncated %v, res %v, tc %d", tc.expMulRoundUp, resMulRoundUp, tcIndex) - - if tc.d2.IsZero() { // panic for divide by zero - s.Require().Panics(func() { tc.d1.Quo(tc.d2) }) - } else { - resQuo := tc.d1.Quo(tc.d2) - s.Require().True(tc.expQuo.Equal(resQuo), "expTruncated %v, res %v, tc %d", tc.expQuo.String(), resQuo.String(), tcIndex) - - resQuoRoundUp := tc.d1.QuoRoundUp(tc.d2) - s.Require().True(tc.expQuoRoundUp.Equal(resQuoRoundUp), "expTruncated %v, res %v, tc %d", - tc.expQuoRoundUp.String(), resQuoRoundUp.String(), tcIndex) - - resQuoTruncate := tc.d1.QuoTruncate(tc.d2) - s.Require().True(tc.expQuoTruncate.Equal(resQuoTruncate), "expTruncated %v, res %v, tc %d", - tc.expQuoTruncate.String(), resQuoTruncate.String(), tcIndex) - } - } -} - -func (s *decimalTestSuite) TestMulRoundUp_RoundingAtPrecisionEnd() { - var ( - a = math.LegacyMustNewDecFromStr("0.000000000000000009") - b = math.LegacyMustNewDecFromStr("0.000000000000000009") - expectedRoundUp = math.LegacyMustNewDecFromStr("0.000000000000000001") - expectedTruncate = math.LegacyMustNewDecFromStr("0.000000000000000000") - ) - - actualRoundUp := a.MulRoundUp(b) - s.Require().Equal(expectedRoundUp.String(), actualRoundUp.String(), "expTruncated %v, res %v", expectedRoundUp, actualRoundUp) - - actualTruncate := a.MulTruncate(b) - s.Require().Equal(expectedTruncate.String(), actualTruncate.String(), "expTruncated %v, res %v", expectedRoundUp, actualTruncate) -} - -func (s *decimalTestSuite) TestBankerRoundChop() { - tests := []struct { - d1 math.LegacyDec - exp int64 - }{ - {s.mustNewDecFromStr("0.25"), 0}, - {s.mustNewDecFromStr("0"), 0}, - {s.mustNewDecFromStr("1"), 1}, - {s.mustNewDecFromStr("0.75"), 1}, - {s.mustNewDecFromStr("0.5"), 0}, - {s.mustNewDecFromStr("7.5"), 8}, - {s.mustNewDecFromStr("1.5"), 2}, - {s.mustNewDecFromStr("2.5"), 2}, - {s.mustNewDecFromStr("0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even - {s.mustNewDecFromStr("1.545"), 2}, - } - - for tcIndex, tc := range tests { - resNeg := tc.d1.Neg().RoundInt64() - s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) - - resPos := tc.d1.RoundInt64() - s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestTruncate() { - tests := []struct { - d1 math.LegacyDec - exp int64 - }{ - {s.mustNewDecFromStr("0"), 0}, - {s.mustNewDecFromStr("0.25"), 0}, - {s.mustNewDecFromStr("0.75"), 0}, - {s.mustNewDecFromStr("1"), 1}, - {s.mustNewDecFromStr("1.5"), 1}, - {s.mustNewDecFromStr("7.5"), 7}, - {s.mustNewDecFromStr("7.6"), 7}, - {s.mustNewDecFromStr("7.4"), 7}, - {s.mustNewDecFromStr("100.1"), 100}, - {s.mustNewDecFromStr("1000.1"), 1000}, - } - - for tcIndex, tc := range tests { - resNeg := tc.d1.Neg().TruncateInt64() - s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) - - resPos := tc.d1.TruncateInt64() - s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestStringOverflow() { - // two random 64 bit primes - dec1, err := math.LegacyNewDecFromStr("51643150036226787134389711697696177267") - s.Require().NoError(err) - dec2, err := math.LegacyNewDecFromStr("-31798496660535729618459429845579852627") - s.Require().NoError(err) - dec3 := dec1.Add(dec2) - s.Require().Equal( - "19844653375691057515930281852116324640.000000000000000000", - dec3.String(), - ) -} -func (s *decimalTestSuite) TestDecMulInt() { - tests := []struct { - sdkDec math.LegacyDec - sdkInt math.Int - want math.LegacyDec - }{ - {math.LegacyNewDec(10), math.NewInt(2), math.LegacyNewDec(20)}, - {math.LegacyNewDec(1000000), math.NewInt(100), math.LegacyNewDec(100000000)}, - {math.LegacyNewDecWithPrec(1, 1), math.NewInt(10), math.LegacyNewDec(1)}, - {math.LegacyNewDecWithPrec(1, 5), math.NewInt(20), math.LegacyNewDecWithPrec(2, 4)}, - } - for i, tc := range tests { - got := tc.sdkDec.MulInt(tc.sdkInt) - s.Require().Equal(tc.want, got, "Incorrect result on test case %d", i) - } -} + "valid decimal without trailing digits": { + src: "123.", + exp: NewDecWithExp(123, 0), + }, -func (s *decimalTestSuite) TestDecCeil() { - testCases := []struct { - input math.LegacyDec - expected math.LegacyDec - }{ - {math.LegacyNewDecWithPrec(1000000000000000, math.LegacyPrecision), math.LegacyNewDec(1)}, // 0.001 => 1.0 - {math.LegacyNewDecWithPrec(-1000000000000000, math.LegacyPrecision), math.LegacyZeroDec()}, // -0.001 => 0.0 - {math.LegacyZeroDec(), math.LegacyZeroDec()}, // 0.0 => 0.0 - {math.LegacyNewDecWithPrec(900000000000000000, math.LegacyPrecision), math.LegacyNewDec(1)}, // 0.9 => 1.0 - {math.LegacyNewDecWithPrec(4001000000000000000, math.LegacyPrecision), math.LegacyNewDec(5)}, // 4.001 => 5.0 - {math.LegacyNewDecWithPrec(-4001000000000000000, math.LegacyPrecision), math.LegacyNewDec(-4)}, // -4.001 => -4.0 - {math.LegacyNewDecWithPrec(4700000000000000000, math.LegacyPrecision), math.LegacyNewDec(5)}, // 4.7 => 5.0 - {math.LegacyNewDecWithPrec(-4700000000000000000, math.LegacyPrecision), math.LegacyNewDec(-4)}, // -4.7 => -4.0 + "valid negative decimal without leading zero": { + src: "-.1234", + exp: NewDecWithExp(-1234, -4), + }, + "valid negative decimal without trailing digits": { + src: "-123.", + exp: NewDecWithExp(-123, 0), + }, + "decimal with scientific notation": { + src: "1.23e4", + exp: NewDecWithExp(123, 2), + }, + "decimal with upper case scientific notation": { + src: "1.23E+4", + exp: NewDecWithExp(123, 2), + }, + "negative decimal with scientific notation": { + src: "-1.23e4", + exp: NewDecWithExp(-123, 2), + }, + "exceed max exp 11E+1000000": { + src: "11E+1000000", + expErr: ErrInvalidDec, + }, + "exceed min exp 11E-1000000": { + src: "11E-1000000", + expErr: ErrInvalidDec, + }, + "exceed max exp 1E100001": { + src: "1E100001", + expErr: ErrInvalidDec, + }, + "exceed min exp 1E-100001": { + src: "1E-100001", + expErr: ErrInvalidDec, + }, + "empty string": { + src: "", + expErr: ErrInvalidDec, + }, + "NaN": { + src: "NaN", + expErr: ErrInvalidDec, + }, + "random string": { + src: "1foo", + expErr: ErrInvalidDec, + }, + "Infinity": { + src: "Infinity", + expErr: ErrInvalidDec, + }, + "Inf": { + src: "Inf", + expErr: ErrInvalidDec, + }, } - - for i, tc := range testCases { - res := tc.input.Ceil() - s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := NewDecFromString(spec.src) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr, got.String()) + return + } + require.NoError(t, gotErr) + assert.True(t, spec.exp.Equal(got)) + }) } } -func (s *decimalTestSuite) TestCeilOverflow() { - // (2^256 * 10^18 -1) / 10^18 - d, err := math.LegacyNewDecFromStr("115792089237316195423570985008687907853269984665640564039457584007913129639935.999999999999999999") - s.Require().NoError(err) - s.Require().True(d.IsInValidRange()) - // this call panics because the value is too large - s.Require().Panics(func() { d.Ceil() }, "Ceil should panic on overflow") -} - -func (s *decimalTestSuite) TestPower() { - testCases := []struct { - input math.LegacyDec - power uint64 - expected math.LegacyDec +func TestNewDecFromInt64(t *testing.T) { + specs := map[string]struct { + src int64 + exp string }{ - {math.LegacyNewDec(100), 0, math.LegacyOneDec()}, // 10 ^ (0) => 1.0 - {math.LegacyOneDec(), 10, math.LegacyOneDec()}, // 1.0 ^ (10) => 1.0 - {math.LegacyNewDecWithPrec(5, 1), 2, math.LegacyNewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 - {math.LegacyNewDecWithPrec(2, 1), 2, math.LegacyNewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 - {math.LegacyNewDecFromInt(math.NewInt(3)), 3, math.LegacyNewDecFromInt(math.NewInt(27))}, // 3 ^ 3 => 27 - {math.LegacyNewDecFromInt(math.NewInt(-3)), 4, math.LegacyNewDecFromInt(math.NewInt(81))}, // -3 ^ 4 = 81 - {math.LegacyNewDecWithPrec(1414213562373095049, 18), 2, math.LegacyNewDecFromInt(math.NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 + "zero value": { + src: 0, + exp: "0", + }, + "positive value": { + src: 123, + exp: "123", + }, + "negative value": { + src: -123, + exp: "-123", + }, + "max value": { + src: math.MaxInt64, + exp: strconv.Itoa(math.MaxInt64), + }, + "min value": { + src: math.MinInt64, + exp: strconv.Itoa(math.MinInt64), + }, } - - for i, tc := range testCases { - res := tc.input.Power(tc.power) - s.Require().True(tc.expected.Sub(res).Abs().LTE(math.LegacySmallestDec()), "unexpected result for test case %d, normal power, input: %v", i, tc.input) - - mutableInput := tc.input - mutableInput.PowerMut(tc.power) - s.Require().True(tc.expected.Sub(mutableInput).Abs().LTE(math.LegacySmallestDec()), - "unexpected result for test case %d, input %v", i, tc.input) - s.Require().True(res.Equal(tc.input), "unexpected result for test case %d, mutable power, input: %v", i, tc.input) + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got := NewDecFromInt64(spec.src) + assert.Equal(t, spec.exp, got.String()) + }) } } -func (s *decimalTestSuite) TestApproxRoot() { - testCases := []struct { - input math.LegacyDec - root uint64 - expected math.LegacyDec +func TestAdd(t *testing.T) { + specs := map[string]struct { + x Dec + y Dec + exp Dec + expErr error }{ - {math.LegacyNewDecFromInt(math.NewInt(2)), 0, math.LegacyOneDec()}, // 2 ^ 0 => 1.0 - {math.LegacyNewDecWithPrec(4, 2), 0, math.LegacyOneDec()}, // 0.04 ^ 0 => 1.0 - {math.LegacyNewDec(0), 1, math.LegacyNewDec(0)}, // 0 ^ 1 => 0 - {math.LegacyOneDec(), 10, math.LegacyOneDec()}, // 1.0 ^ (0.1) => 1.0 - {math.LegacyNewDecWithPrec(25, 2), 2, math.LegacyNewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 - {math.LegacyNewDecWithPrec(4, 2), 2, math.LegacyNewDecWithPrec(2, 1)}, // 0.04 ^ (0.5) => 0.2 - {math.LegacyNewDecFromInt(math.NewInt(27)), 3, math.LegacyNewDecFromInt(math.NewInt(3))}, // 27 ^ (1/3) => 3 - {math.LegacyNewDecFromInt(math.NewInt(-81)), 4, math.LegacyNewDecFromInt(math.NewInt(-3))}, // -81 ^ (0.25) => -3 - {math.LegacyNewDecFromInt(math.NewInt(2)), 2, math.LegacyNewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 - {math.LegacyNewDecWithPrec(1005, 3), 31536000, math.LegacyMustNewDecFromStr("1.000000000158153904")}, // 1.005 ^ (1/31536000) ≈ 1.00000000016 - {math.LegacySmallestDec(), 2, math.LegacyNewDecWithPrec(1, 9)}, // 1e-18 ^ (0.5) => 1e-9 - {math.LegacySmallestDec(), 3, math.LegacyMustNewDecFromStr("0.000000999999999997")}, // 1e-18 ^ (1/3) => 1e-6 - {math.LegacyNewDecWithPrec(1, 8), 3, math.LegacyMustNewDecFromStr("0.002154434690031900")}, // 1e-8 ^ (1/3) ≈ 0.00215443469 - {math.LegacyMustNewDecFromStr("9000002314687921634000000000000000000021394871242000000000000000"), 2, math.LegacyMustNewDecFromStr("94868342004527103646332858502867.899477053226766107")}, + "0 + 0 = 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(0), + exp: NewDecFromInt64(0), + }, + "0 + 123 = 123": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(123), + }, + "0 + -123 = -123": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(-123), + exp: NewDecFromInt64(-123), + }, + "123 + 123 = 246": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(246), + }, + "-123 + 123 = 0": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(0), + }, + "-123 + -123 = -246": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(-123), + exp: NewDecFromInt64(-246), + }, + "1.234 + 1.234 = 2.468": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1234, -3), + exp: NewDecWithExp(2468, -3), + }, + "1.234 + 123 = 124.234": { + x: NewDecWithExp(1234, -3), + y: NewDecFromInt64(123), + exp: NewDecWithExp(124234, -3), + }, + "1.234 + -123 = -121.766": { + x: NewDecWithExp(1234, -3), + y: NewDecFromInt64(-123), + exp: must(NewDecFromString("-121.766")), + }, + "1.234 + -1.234 = 0": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(-1234, -3), + exp: NewDecWithExp(0, -3), + }, + "-1.234 + -1.234 = -2.468": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(-1234, -3), + exp: NewDecWithExp(-2468, -3), + }, + "1e100000 + 9e900000 -> Err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(9, 900_000), + expErr: ErrInvalidDec, + }, + "1e100000 + -9e900000 -> Err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(9, 900_000), + expErr: ErrInvalidDec, + }, + "1e100000 + 1e^-1 -> err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(1, -1), + expErr: ErrInvalidDec, + }, + "1e100000 + -1e^-1 -> err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(-1, -1), + expErr: ErrInvalidDec, + }, + "1e100000 + 1 -> 100..1": { + x: NewDecWithExp(1, 100_000), + y: NewDecFromInt64(1), + exp: must(NewDecWithExp(1, 100_000).Add(NewDecFromInt64(1))), + }, + "1e100001 + 0 -> err": { + x: NewDecWithExp(1, 100_001), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "-1e100001 + 0 -> err": { + x: NewDecWithExp(1, -100_001), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, } - - // In the case of 1e-8 ^ (1/3), the result repeats every 5 iterations starting from iteration 24 - // (i.e. 24, 29, 34, ... give the same result) and never converges enough. The maximum number of - // iterations (300) causes the result at iteration 300 to be returned, regardless of convergence. - - for i, tc := range testCases { - res, err := tc.input.ApproxRoot(tc.root) - s.Require().NoError(err) - s.Require().True(tc.expected.Sub(res).Abs().LTE(math.LegacySmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := spec.x.Add(spec.y) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr, got) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.exp, got) + }) } } -func (s *decimalTestSuite) TestApproxSqrt() { - testCases := []struct { - input math.LegacyDec - expected math.LegacyDec +func TestSub(t *testing.T) { + specs := map[string]struct { + x Dec + y Dec + exp Dec + expErr error }{ - {math.LegacyOneDec(), math.LegacyOneDec()}, // 1.0 => 1.0 - {math.LegacyNewDecWithPrec(25, 2), math.LegacyNewDecWithPrec(5, 1)}, // 0.25 => 0.5 - {math.LegacyNewDecWithPrec(4, 2), math.LegacyNewDecWithPrec(2, 1)}, // 0.09 => 0.3 - {math.LegacyNewDec(9), math.LegacyNewDecFromInt(math.NewInt(3))}, // 9 => 3 - {math.LegacyNewDec(-9), math.LegacyNewDecFromInt(math.NewInt(-3))}, // -9 => -3 - {math.LegacyNewDec(2), math.LegacyNewDecWithPrec(1414213562373095049, 18)}, // 2 => 1.414213562373095049 - { // 2^127 - 1 => 13043817825332782212.3495718062525083688 which rounds to 13043817825332782212.3495718062525083689 - math.LegacyNewDec(2).Power(127).Sub(math.LegacyOneDec()), - math.LegacyMustNewDecFromStr("13043817825332782212.349571806252508369"), - }, - {math.LegacyMustNewDecFromStr("1.000000011823380862"), math.LegacyMustNewDecFromStr("1.000000005911690414")}, + "0 - 0 = 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(0), + exp: NewDecFromInt64(0), + }, + "0 - 123 = -123": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(-123), + }, + "0 - -123 = 123": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(-123), + exp: NewDecFromInt64(123), + }, + "123 - 123 = 0": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(0), + }, + "-123 - 123 = -246": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(-246), + }, + "-123 - -123 = 0": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(-123), + exp: NewDecFromInt64(0), + }, + "1.234 - 1.234 = 0.000": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1234, -3), + exp: NewDecWithExp(0, -3), + }, + "1.234 - 123 = -121.766": { + x: NewDecWithExp(1234, -3), + y: NewDecFromInt64(123), + exp: NewDecWithExp(-121766, -3), + }, + "1.234 - -123 = 124.234": { + x: NewDecWithExp(1234, -3), + y: NewDecFromInt64(-123), + exp: NewDecWithExp(124234, -3), + }, + "1.234 - -1.234 = 2.468": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(-1234, -3), + exp: NewDecWithExp(2468, -3), + }, + "-1.234 - -1.234 = 2.468": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(-1234, -3), + exp: NewDecWithExp(0, -3), + }, + "1 - 0.999 = 0.001 - rounding after comma": { + x: NewDecFromInt64(1), + y: NewDecWithExp(999, -3), + exp: NewDecWithExp(1, -3), + }, + "1e100000 - 1^-1 -> Err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(1, -1), + expErr: ErrInvalidDec, + }, + "1e100000 - 1^1-> Err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(1, -1), + expErr: ErrInvalidDec, + }, + "upper exp limit exceeded": { + x: NewDecWithExp(1, 100_001), + y: NewDecWithExp(1, 100_001), + expErr: ErrInvalidDec, + }, + "lower exp limit exceeded": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(1, -100_001), + expErr: ErrInvalidDec, + }, + "1e100000 - 1 = 999..9": { + x: NewDecWithExp(1, 100_000), + y: NewDecFromInt64(1), + exp: must(NewDecFromString(strings.Repeat("9", 100_000))), + }, + "1e100000 - 0 = 1e100000": { + x: NewDecWithExp(1, 100_000), + y: NewDecFromInt64(0), + exp: must(NewDecFromString("1e100000")), + }, + "1e100001 - 0 -> err": { + x: NewDecWithExp(1, 100_001), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "1e100000 - -1 -> 100..1": { + x: NewDecWithExp(1, 100_000), + y: must(NewDecFromString("-9e100000")), + expErr: ErrInvalidDec, + }, + "1e-100000 - 0 = 1e-100000": { + x: NewDecWithExp(1, -100_000), + y: NewDecFromInt64(0), + exp: must(NewDecFromString("1e-100000")), + }, + "1e-100001 - 0 -> err": { + x: NewDecWithExp(1, -100_001), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "1e-100000 - -1 -> 0.000..01": { + x: NewDecWithExp(1, -100_000), + y: NewDecFromInt64(-1), + exp: must(NewDecFromString("1." + strings.Repeat("0", 99999) + "1")), + }, } - - for i, tc := range testCases { - res, err := tc.input.ApproxSqrt() - s.Require().NoError(err) - s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := spec.x.Sub(spec.y) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + assert.True(t, spec.exp.Equal(got), got.String()) + }) } } -func (s *decimalTestSuite) TestDecSortableBytes() { - tests := []struct { - d math.LegacyDec - want []byte +func TestQuo(t *testing.T) { + specs := map[string]struct { + src string + x Dec + y Dec + exp Dec + expErr error }{ - {math.LegacyNewDec(0), []byte("000000000000000000.000000000000000000")}, - {math.LegacyNewDec(1), []byte("000000000000000001.000000000000000000")}, - {math.LegacyNewDec(10), []byte("000000000000000010.000000000000000000")}, - {math.LegacyNewDec(12340), []byte("000000000000012340.000000000000000000")}, - {math.LegacyNewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")}, - {math.LegacyNewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")}, - {math.LegacyNewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")}, - {math.LegacyNewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")}, - {math.LegacyNewDecWithPrec(-1009009009009009009, 17), []byte("-000000000000000010.090090090090090090")}, - {math.LegacyNewDec(1000000000000000000), []byte("max")}, - {math.LegacyNewDec(-1000000000000000000), []byte("--")}, + "0 / 0 -> Err": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + " 0 / 123 = 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(0), + }, + "123 / 0 = 0": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "-123 / 0 = 0": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "123 / 123 = 1": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(123), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "-123 / 123 = -1": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(123), + exp: must(NewDecFromString("-1.000000000000000000000000000000000")), + }, + "-123 / -123 = 1": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(-123), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "1.234 / 1.234 = 1": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1234, -3), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "-1.234 / 1234 = -1": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(1234, -3), + exp: must(NewDecFromString("-1.000000000000000000000000000000000")), + }, + "1.234 / -123 = 1.0100": { + x: NewDecWithExp(1234, -3), + y: NewDecFromInt64(-123), + exp: must(NewDecFromString("-0.01003252032520325203252032520325203")), + }, + "1.234 / -1.234 = -1": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(-1234, -3), + exp: must(NewDecFromString("-1.000000000000000000000000000000000")), + }, + "-1.234 / -1.234 = 1": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(-1234, -3), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "3 / -9 = -0.3333...3 - round down": { + x: NewDecFromInt64(3), + y: NewDecFromInt64(-9), + exp: must(NewDecFromString("-0.3333333333333333333333333333333333")), + }, + "4 / 9 = 0.4444...4 - round down": { + x: NewDecFromInt64(4), + y: NewDecFromInt64(9), + exp: must(NewDecFromString("0.4444444444444444444444444444444444")), + }, + "5 / 9 = 0.5555...6 - round up": { + x: NewDecFromInt64(5), + y: NewDecFromInt64(9), + exp: must(NewDecFromString("0.5555555555555555555555555555555556")), + }, + "6 / 9 = 0.6666...7 - round up": { + x: NewDecFromInt64(6), + y: NewDecFromInt64(9), + exp: must(NewDecFromString("0.6666666666666666666666666666666667")), + }, + "7 / 9 = 0.7777...8 - round up": { + x: NewDecFromInt64(7), + y: NewDecFromInt64(9), + exp: must(NewDecFromString("0.7777777777777777777777777777777778")), + }, + "8 / 9 = 0.8888...9 - round up": { + x: NewDecFromInt64(8), + y: NewDecFromInt64(9), + exp: must(NewDecFromString("0.8888888888888888888888888888888889")), + }, + "9e-34 / 10 = 9e-35 - no rounding": { + x: NewDecWithExp(9, -34), + y: NewDecFromInt64(10), + exp: must(NewDecFromString("9e-35")), + }, + "9e-35 / 10 = 9e-36 - no rounding": { + x: NewDecWithExp(9, -35), + y: NewDecFromInt64(10), + exp: must(NewDecFromString("9e-36")), + }, + "high precision - min/0.1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(1, -1), + exp: NewDecWithExp(1, -99_999), + }, + "high precision - min/1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(1, 0), + exp: NewDecWithExp(1, -100_000), + }, + "high precision - min/10": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(1, 1), + expErr: ErrInvalidDec, + }, + "high precision - <_min/0.1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(1, -1), + exp: NewDecWithExp(1, -100_000), + }, + "high precision - <_min/1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(1, 0), + expErr: ErrInvalidDec, + }, + "high precision - <_min/10": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(1, 1), + expErr: ErrInvalidDec, + }, + "high precision - min/-0.1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(-1, -1), + exp: NewDecWithExp(-1, -99_999), + }, + "high precision - min/-1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(-1, 0), + exp: NewDecWithExp(-1, -100_000), + }, + "high precision - min/-10": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(-1, 1), + expErr: ErrInvalidDec, + }, + "high precision - <_min/-0.1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, -1), + exp: NewDecWithExp(-1, -100_000), + }, + "high precision - <_min/-1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, 0), + expErr: ErrInvalidDec, + }, + "high precision - <_min/-10": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, 1), + expErr: ErrInvalidDec, + }, } - for tcIndex, tc := range tests { - s.Require().Equal(tc.want, math.LegacySortableDecBytes(tc.d), "bad String(), index: %v", tcIndex) + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := spec.x.Quo(spec.y) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + last35 := func(s string) string { + var x int + if len(s) < 36 { + x = 0 + } else { + x = len(s) - 36 + } + return fmt.Sprintf("%s(%d)", s[x:], len(s)) + } + gotReduced, _ := got.Reduce() + assert.True(t, spec.exp.Equal(gotReduced), "exp %s, got: %s", last35(spec.exp.String()), last35(gotReduced.String())) + }) } - - s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(1000000000000000001)) }) - s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(-1000000000000000001)) }) } -func (s *decimalTestSuite) TestDecEncoding() { - largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) - s.Require().True(ok) - - smallestBigInt, ok := new(big.Int).SetString("-33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) - s.Require().True(ok) - - const maxDecBitLen = 315 - maxInt, ok := new(big.Int).SetString(strings.Repeat("1", maxDecBitLen), 2) - s.Require().True(ok) - - testCases := []struct { - input math.LegacyDec - rawBz string - jsonStr string - yamlStr string +func TestQuoExact(t *testing.T) { + specs := map[string]struct { + src string + x Dec + y Dec + exp Dec + expErr error }{ - { - math.LegacyNewDec(0), "30", - "\"0.000000000000000000\"", - "\"0.000000000000000000\"\n", - }, - { - math.LegacyNewDecWithPrec(4, 2), - "3430303030303030303030303030303030", - "\"0.040000000000000000\"", - "\"0.040000000000000000\"\n", - }, - { - math.LegacyNewDecWithPrec(-4, 2), - "2D3430303030303030303030303030303030", - "\"-0.040000000000000000\"", - "\"-0.040000000000000000\"\n", - }, - { - math.LegacyNewDecWithPrec(1414213562373095049, 18), - "31343134323133353632333733303935303439", - "\"1.414213562373095049\"", - "\"1.414213562373095049\"\n", - }, - { - math.LegacyNewDecWithPrec(-1414213562373095049, 18), - "2D31343134323133353632333733303935303439", - "\"-1.414213562373095049\"", - "\"-1.414213562373095049\"\n", - }, - { - math.LegacyNewDecFromBigIntWithPrec(largestBigInt, 18), - "3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", - "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", - "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", - }, - { - math.LegacyNewDecFromBigIntWithPrec(smallestBigInt, 18), - "2D3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", - "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", - "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", - }, - { - math.LegacyNewDecFromBigIntWithPrec(maxInt, 18), - "3636373439353934383732353238343430303734383434343238333137373938353033353831333334353136333233363435333939303630383435303530323434343434333636343330363435303137313838323137353635323136373637", - "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"", - "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"\n", + "0 / 0 -> Err": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + " 0 / 123 = 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(0), + }, + "123 / 0 -> Err": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "-123 / 0 -> Err": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "123 / 123 = 1": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(123), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "-123 / 123 = 1": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(123), + exp: must(NewDecFromString("-1.000000000000000000000000000000000")), + }, + "-123 / -123 = 1": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(-123), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "1.234 / 1.234 = 1": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1234, -3), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "-1.234 / 1.234 = -1": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(1234, -3), + exp: must(NewDecFromString("-1.000000000000000000000000000000000")), + }, + "1.234 / -123 -> Err": { + x: NewDecWithExp(1234, -3), + y: NewDecFromInt64(-123), + expErr: ErrUnexpectedRounding, + }, + "1.234 / -1.234 = -1": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(-1234, -3), + exp: must(NewDecFromString("-1.000000000000000000000000000000000")), + }, + "-1.234 / -1.234 = 1": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(-1234, -3), + exp: must(NewDecFromString("1.000000000000000000000000000000000")), + }, + "3 / -9 -> Err": { + x: NewDecFromInt64(3), + y: NewDecFromInt64(-9), + expErr: ErrUnexpectedRounding, + }, + "4 / 9 -> Err": { + x: NewDecFromInt64(4), + y: NewDecFromInt64(9), + expErr: ErrUnexpectedRounding, + }, + "5 / 9 -> Err": { + x: NewDecFromInt64(5), + y: NewDecFromInt64(9), + expErr: ErrUnexpectedRounding, + }, + "6 / 9 -> Err": { + x: NewDecFromInt64(6), + y: NewDecFromInt64(9), + expErr: ErrUnexpectedRounding, + }, + "7 / 9 -> Err": { + x: NewDecFromInt64(7), + y: NewDecFromInt64(9), + expErr: ErrUnexpectedRounding, + }, + "8 / 9 -> Err": { + x: NewDecFromInt64(8), + y: NewDecFromInt64(9), + expErr: ErrUnexpectedRounding, + }, + "9e-34 / 10 = 9e-35 - no rounding": { + x: NewDecWithExp(9, -34), + y: NewDecFromInt64(10), + exp: must(NewDecFromString("0.00000000000000000000000000000000009000000000000000000000000000000000")), + }, + "9e-35 / 10 = 9e-36 - no rounding": { + x: NewDecWithExp(9, -35), + y: NewDecFromInt64(10), + exp: must(NewDecFromString("9e-36")), + }, + "high precision - min/0.1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(1, -1), + exp: NewDecWithExp(1, -99_999), + }, + "high precision - min/1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(1, 0), + exp: NewDecWithExp(1, -100_000), + }, + "high precision - min/10": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(1, 1), + expErr: ErrInvalidDec, + }, + "high precision - <_min/0.1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(1, -1), + exp: NewDecWithExp(1, -100_000), + }, + "high precision - <_min/1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(1, 0), + expErr: ErrInvalidDec, + }, + "high precision - <_min/10 -> Err": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(1, 1), + expErr: ErrInvalidDec, + }, + "high precision - min/-0.1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(-1, -1), + exp: NewDecWithExp(-1, -99_999), + }, + "high precision - min/-1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(-1, 0), + exp: NewDecWithExp(-1, -100_000), + }, + "high precision - min/-10 -> Err": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(-1, 1), + expErr: ErrInvalidDec, + }, + "high precision - <_min/-0.1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, -1), + exp: NewDecWithExp(-1, -100_000), + }, + "high precision - <_min/-1": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, 0), + expErr: ErrInvalidDec, + }, + "high precision - <_min/-10": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, 1), + expErr: ErrInvalidDec, }, } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := spec.x.QuoExact(spec.y) - for _, tc := range testCases { - bz, err := tc.input.Marshal() - s.Require().NoError(err) - s.Require().Equal(tc.rawBz, fmt.Sprintf("%X", bz)) - - var other math.LegacyDec - s.Require().NoError((&other).Unmarshal(bz)) - s.Require().True(tc.input.Equal(other)) - - bz, err = json.Marshal(tc.input) - s.Require().NoError(err) - s.Require().Equal(tc.jsonStr, string(bz)) - s.Require().NoError(json.Unmarshal(bz, &other)) - s.Require().True(tc.input.Equal(other)) - - bz, err = yaml.Marshal(tc.input) - s.Require().NoError(err) - s.Require().Equal(tc.yamlStr, string(bz)) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + assert.True(t, spec.exp.Equal(got)) + }) } } -// Showcase that different orders of operations causes different results. -func (s *decimalTestSuite) TestOperationOrders() { - n1 := math.LegacyNewDec(10) - n2 := math.LegacyNewDec(1000000010) - s.Require().Equal(n1.Mul(n2).Quo(n2), math.LegacyNewDec(10)) - s.Require().NotEqual(n1.Mul(n2).Quo(n2), n1.Quo(n2).Mul(n2)) -} - -func BenchmarkMarshalTo(b *testing.B) { - b.ReportAllocs() - bis := []struct { - in math.LegacyDec - want []byte +func TestQuoInteger(t *testing.T) { + specs := map[string]struct { + src string + x Dec + y Dec + exp Dec + expErr error }{ - { - math.LegacyNewDec(1e8), []byte{ - 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - }, - }, - {math.LegacyNewDec(0), []byte{0x30}}, + "0 / 0 -> Err": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + " 0 / 123 = 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(0), + }, + "123 / 0 -> Err": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "-123 / -> Err": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "123 / 123 = 1": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(1), + }, + "-123 / 123 = -1": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(-1), + }, + "-123 / -123 = 1": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(-123), + exp: NewDecFromInt64(1), + }, + "1.234 / 1.234": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1234, -3), + exp: NewDecFromInt64(1), + }, + "-1.234 / 1234 = -121.766": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(1234, -3), + exp: NewDecFromInt64(-1), + }, + "1.234 / -1.234 = 2.468": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(-1234, -3), + exp: NewDecFromInt64(-1), + }, + "-1.234 / -1.234 = 1": { + x: NewDecWithExp(-1234, -3), + y: NewDecWithExp(-1234, -3), + exp: NewDecFromInt64(1), + }, + "3 / -9 = 0": { + x: NewDecFromInt64(3), + y: NewDecFromInt64(-9), + exp: must(NewDecFromString("0")), + }, + "8 / 9 = 0": { + x: NewDecFromInt64(8), + y: NewDecFromInt64(9), + exp: must(NewDecFromString("0")), + }, + "high precision - min/0.1": { + x: NewDecWithExp(1, -100_000), + y: NewDecWithExp(1, -1), + exp: NewDecFromInt64(0), + }, + "high precision - <_min/-1 -> Err": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, 0), + expErr: ErrInvalidDec, + }, + "high precision - <_min/-10 -> Err": { + x: NewDecWithExp(1, -100_001), + y: NewDecWithExp(-1, 1), + expErr: ErrInvalidDec, + }, + "1e000 / 1 -> Err": { + x: NewDecWithExp(1, 100_000), + y: NewDecFromInt64(1), + expErr: ErrInvalidDec, + }, + "1e100000 - 1^1 -> Err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(1, -1), + expErr: ErrInvalidDec, + }, } - data := make([]byte, 100) - - b.ReportAllocs() - b.ResetTimer() + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := spec.x.QuoInteger(spec.y) - for i := 0; i < b.N; i++ { - for _, bi := range bis { - if n, err := bi.in.MarshalTo(data); err != nil { - b.Fatal(err) - } else if !bytes.Equal(data[:n], bi.want) { - b.Fatalf("Mismatch\nGot: % x\nWant: % x\n", data[:n], bi.want) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + return } - } - } -} - -var sink interface{} - -func BenchmarkLegacyQuoMut(b *testing.B) { - b1 := math.LegacyNewDec(17e2 + 8371) - b2 := math.LegacyNewDec(4371) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - sink = b1.QuoMut(b2) - } - - if sink == nil { - b.Fatal("Benchmark did not run") - } - sink = (interface{})(nil) -} - -func BenchmarkLegacyQuoTruncateMut(b *testing.B) { - b1 := math.LegacyNewDec(17e2 + 8371) - baseArr := make([]math.LegacyDec, b.N) - for i := 0; i < b.N; i++ { - baseArr[i] = b1.Clone() - } - b2 := math.LegacyNewDec(4371) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - sink = baseArr[i].QuoTruncateMut(b2) - } - - if sink == nil { - b.Fatal("Benchmark did not run") - } - sink = (interface{})(nil) -} - -func BenchmarkLegacySqrtOnMersennePrime(b *testing.B) { - b1 := math.LegacyNewDec(2).Power(127).Sub(math.LegacyOneDec()) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - sink, _ = b1.ApproxSqrt() - } - - if sink == nil { - b.Fatal("Benchmark did not run") - } - sink = (interface{})(nil) -} - -func BenchmarkLegacyQuoRoundupMut(b *testing.B) { - b1 := math.LegacyNewDec(17e2 + 8371) - baseArr := make([]math.LegacyDec, b.N) - for i := 0; i < b.N; i++ { - baseArr[i] = b1.Clone() - } - b2 := math.LegacyNewDec(4371) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - sink = baseArr[i].QuoRoundupMut(b2) - } - - if sink == nil { - b.Fatal("Benchmark did not run") - } - sink = (interface{})(nil) -} - -func TestFormatDec(t *testing.T) { - type decimalTest []string - var testcases []decimalTest - raw, err := os.ReadFile("./testdata/decimals.json") - require.NoError(t, err) - err = json.Unmarshal(raw, &testcases) - require.NoError(t, err) - - for _, tc := range testcases { - t.Run(tc[0], func(t *testing.T) { - out, err := math.FormatDec(tc[0]) - require.NoError(t, err) - require.Equal(t, tc[1], out) + require.NoError(t, gotErr) + assert.True(t, spec.exp.Equal(got)) }) } } -func TestFormatDecNonDigits(t *testing.T) { - badCases := []string{ - "10.a", - "1a.10", - "p1a10.", - "0.10p", - "--10", - "12.😎😎", - "11111111111133333333333333333333333333333a", - "11111111111133333333333333333333333333333 192892", +func TestModulo(t *testing.T) { + specs := map[string]struct { + x Dec + y Dec + exp Dec + expErr error + }{ + "0 / 123 = 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(123), + exp: NewDecFromInt64(0), + }, + "123 / 10 = 3": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(10), + exp: NewDecFromInt64(3), + }, + "123 / -10 = 3": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(-10), + exp: NewDecFromInt64(3), + }, + "-123 / 10 = -3": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(10), + exp: NewDecFromInt64(-3), + }, + "1.234 / 1 = 0.234": { + x: NewDecWithExp(1234, -3), + y: NewDecFromInt64(1), + exp: NewDecWithExp(234, -3), + }, + "1.234 / 0.1 = 0.034": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1, -1), + exp: NewDecWithExp(34, -3), + }, + "1.234 / 1.1 = 0.134": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(11, -1), + exp: NewDecWithExp(134, -3), + }, + "10 / 0 -> Err": { + x: NewDecFromInt64(10), + y: NewDecFromInt64(0), + expErr: ErrInvalidDec, + }, + "-1e0000 / 9e0000 = 1e0000": { + x: NewDecWithExp(-1, 100_000), + y: NewDecWithExp(9, 100_000), + exp: NewDecWithExp(-1, 100_000), + }, + "1e0000 / 9e0000 = 1e0000": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(9, 100_000), + exp: NewDecWithExp(1, 100_000), + }, } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := spec.x.Modulo(spec.y) - for _, value := range badCases { - value := value - t.Run(value, func(t *testing.T) { - s, err := math.FormatDec(value) - if err == nil { - t.Fatal("Expected an error") - } - if g, w := err.Error(), "non-digits"; !strings.Contains(g, w) { - t.Errorf("Error mismatch\nGot: %q\nWant substring: %q", g, w) - } - if s != "" { - t.Fatalf("Got a non-empty string: %q", s) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + return } + require.NoError(t, gotErr) + assert.True(t, spec.exp.Equal(got)) }) } } -func TestNegativePrecisionPanic(t *testing.T) { - require.Panics(t, func() { - math.LegacyNewDecWithPrec(10, -1) - }) -} - -func (s *decimalTestSuite) TestConvertToBigIntMutativeForLegacyDec() { - r := big.NewInt(30) - i := math.LegacyNewDecFromBigInt(r) - - // Compare value of BigInt & BigIntMut - s.Require().Equal(i.BigInt(), i.BigIntMut()) - - // Modify BigIntMut() pointer and ensure i.BigIntMut() & i.BigInt() change - p1 := i.BigIntMut() - p1.SetInt64(40) - s.Require().Equal(big.NewInt(40), i.BigIntMut()) - s.Require().Equal(big.NewInt(40), i.BigInt()) - - // Modify big.Int() pointer and ensure i.BigIntMut() & i.BigInt() don't change - p2 := i.BigInt() - p2.SetInt64(50) - s.Require().NotEqual(big.NewInt(50), i.BigIntMut()) - s.Require().NotEqual(big.NewInt(50), i.BigInt()) -} - -func TestQuoMut(t *testing.T) { +func TestNumDecimalPlaces(t *testing.T) { specs := map[string]struct { - dividend, divisor math.LegacyDec - expTruncated, expRoundedUp string - expPanic bool + src Dec + exp uint32 }{ - "0.0000000000000000001": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("10"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "0.0000000000000000002": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("5"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "0.0000000000000000003": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("3.333333333333333"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "0.0000000000000000004": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("2.5"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "0.0000000000000000005": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("2"), - expRoundedUp: "0.000000000000000001", - - expTruncated: "0.000000000000000000", + "integer": { + src: NewDecFromInt64(123), + exp: 0, }, - "0.0000000000000000006": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("1.666666666666666666"), - expRoundedUp: "0.000000000000000001", - - expTruncated: "0.000000000000000000", + "one decimal place": { + src: NewDecWithExp(1234, -1), + exp: 1, }, - "0.0000000000000000007": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("1.428571428571429"), - expRoundedUp: "0.000000000000000001", - - expTruncated: "0.000000000000000000", + "two decimal places": { + src: NewDecWithExp(12345, -2), + exp: 2, }, - "0.0000000000000000008": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("1.25"), - expRoundedUp: "0.000000000000000001", - - expTruncated: "0.000000000000000000", + "three decimal places": { + src: NewDecWithExp(123456, -3), + exp: 3, }, - "0.0000000000000000009": { - dividend: math.LegacyNewDecWithPrec(1, 18), - divisor: math.LegacyMustNewDecFromStr("1.111111111111111"), - expRoundedUp: "0.000000000000000001", - - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000001": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("10"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000002": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("5"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000003": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("3.333333333333333"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000004": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("2.5"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000005": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("2"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000006": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("1.666666666666666666"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000007": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("1.428571428571429"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000008": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("1.25"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "-0.0000000000000000009": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("1.111111111111111"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000001": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-10"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000002": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-5"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000003": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-3.333333333333333"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000004": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-2.5"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000005": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-2"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000006": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-1.666666666666666666"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000007": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-1.428571428571429"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000008": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-1.25"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "--0.0000000000000000009": { - dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), - divisor: math.LegacyMustNewDecFromStr("-1.111111111111111"), - expRoundedUp: "0.000000000000000001", - expTruncated: "0.000000000000000000", - }, - "big / small": { - dividend: math.LegacyMustNewDecFromStr("999999999999999999"), - divisor: math.LegacyNewDecWithPrec(1, 18), - expRoundedUp: "999999999999999999000000000000000000.000000000000000000", - expTruncated: "999999999999999999000000000000000000.000000000000000000", - }, - "divide by dividend": { - dividend: math.LegacyNewDecWithPrec(123, 0), - divisor: math.LegacyMustNewDecFromStr("123"), - expRoundedUp: "1.000000000000000000", - expTruncated: "1.000000000000000000", - }, - "zero divided": { - dividend: math.LegacyNewDecWithPrec(0, 0), - divisor: math.LegacyMustNewDecFromStr("1"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "zero divided by negative value": { - dividend: math.LegacyNewDecWithPrec(0, 0), - divisor: math.LegacyMustNewDecFromStr("-1"), - expRoundedUp: "0.000000000000000000", - expTruncated: "0.000000000000000000", - }, - "zero divided by zero": { - dividend: math.LegacyNewDecWithPrec(0, 0), - divisor: math.LegacyMustNewDecFromStr("0"), - expPanic: true, - }, - "divide by zero": { - dividend: math.LegacyNewDecWithPrec(1, 0), - divisor: math.LegacyMustNewDecFromStr("0"), - expPanic: true, + "trailing zeros": { + src: NewDecWithExp(123400, -4), + exp: 4, + }, + "zero value": { + src: NewDecFromInt64(0), + exp: 0, + }, + "negative value": { + src: NewDecWithExp(-12345, -3), + exp: 3, }, } for name, spec := range specs { t.Run(name, func(t *testing.T) { - t.Run("round up", func(t *testing.T) { - t.Parallel() - if !spec.expPanic { - got := spec.dividend.Clone().QuoRoundupMut(spec.divisor.Clone()) - require.Equal(t, spec.expRoundedUp, got.String()) - return - } - require.Panics(t, func() { - _ = spec.dividend.Clone().QuoRoundupMut(spec.divisor.Clone()) - }) - }) - t.Run("truncate", func(t *testing.T) { - t.Parallel() - if !spec.expPanic { - got := spec.dividend.Clone().QuoTruncateMut(spec.divisor.Clone()) - require.Equal(t, spec.expTruncated, got.String()) - return - } - require.Panics(t, func() { - _ = spec.dividend.Clone().QuoTruncateMut(spec.divisor.Clone()) - }) - }) + got := spec.src.NumDecimalPlaces() + assert.Equal(t, spec.exp, got) }) } } -func Test_DocumentLegacyAsymmetry(t *testing.T) { - zeroDec := math.LegacyZeroDec() - emptyDec := math.LegacyDec{} - - zeroDecBz, err := zeroDec.Marshal() - require.NoError(t, err) - zeroDecJSON, err := zeroDec.MarshalJSON() - require.NoError(t, err) - - emptyDecBz, err := emptyDec.Marshal() - require.NoError(t, err) - emptyDecJSON, err := emptyDec.MarshalJSON() - require.NoError(t, err) - - // makes sense, zero and empty are semantically different and render differently - require.NotEqual(t, zeroDecJSON, emptyDecJSON) - // but on the proto wire they encode to the same bytes - require.Equal(t, zeroDecBz, emptyDecBz) - - // zero values are symmetrical - zeroDecRoundTrip := math.LegacyDec{} - err = zeroDecRoundTrip.Unmarshal(zeroDecBz) - require.NoError(t, err) - zeroDecRoundTripJSON, err := zeroDecRoundTrip.MarshalJSON() - require.NoError(t, err) - require.Equal(t, zeroDecJSON, zeroDecRoundTripJSON) - require.Equal(t, zeroDec, zeroDecRoundTrip) - - // empty values are not - emptyDecRoundTrip := math.LegacyDec{} - err = emptyDecRoundTrip.Unmarshal(emptyDecBz) - require.NoError(t, err) - emptyDecRoundTripJSON, err := emptyDecRoundTrip.MarshalJSON() - require.NoError(t, err) - - // !!! this is the key point, they are not equal, it looks like a bug - require.NotEqual(t, emptyDecJSON, emptyDecRoundTripJSON) - require.NotEqual(t, emptyDec, emptyDecRoundTrip) +func TestCmp(t *testing.T) { + specs := map[string]struct { + x Dec + y Dec + exp int + }{ + "0 == 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(0), + exp: 0, + }, + "0 < 123 = -1": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(123), + exp: -1, + }, + "123 > 0 = 1": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(0), + exp: 1, + }, + "-123 < 0 = -1": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(0), + exp: -1, + }, + "123 == 123": { + x: NewDecFromInt64(123), + y: NewDecFromInt64(123), + exp: 0, + }, + "-123 == -123": { + x: NewDecFromInt64(-123), + y: NewDecFromInt64(-123), + exp: 0, + }, + "1.234 == 1.234": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1234, -3), + exp: 0, + }, + "1.234 > 1.233": { + x: NewDecWithExp(1234, -3), + y: NewDecWithExp(1233, -3), + exp: 1, + }, + "1.233 < 1.234": { + x: NewDecWithExp(1233, -3), + y: NewDecWithExp(1234, -3), + exp: -1, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got := spec.x.Cmp(spec.y) + assert.Equal(t, spec.exp, got) + }) + } } -// 2^256 * 10^18 -1 -const maxValidDecNumber = "115792089237316195423570985008687907853269984665640564039457584007913129639935999999999999999999" - -func TestDecOpsWithinLimits(t *testing.T) { - maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) - require.True(t, ok) - minValid := new(big.Int).Neg(maxValid) +func TestReduce(t *testing.T) { specs := map[string]struct { - src *big.Int - expErr bool + src string + exp string + decPlaces int }{ - "max": { - src: maxValid, - }, - "max + 1": { - src: new(big.Int).Add(maxValid, big.NewInt(1)), - expErr: true, - }, - "min": { - src: minValid, - }, - "min - 1": { - src: new(big.Int).Sub(minValid, big.NewInt(1)), - expErr: true, - }, - "max Int": { - // max Int is 2^256 -1 - src: math.NewIntFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))).BigIntMut(), - }, - "min Int": { - // max Int is -1 *(2^256 -1) - src: math.NewIntFromBigInt(new(big.Int).Neg(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1)))).BigIntMut(), + "positive value": { + src: "10", + exp: "10", + decPlaces: 1, + }, + "negative value": { + src: "-10", + exp: "-10", + decPlaces: 1, + }, + "positive decimal": { + src: "1.30000", + exp: "1.3", + decPlaces: 4, + }, + "negative decimal": { + src: "-1.30000", + exp: "-1.3", + decPlaces: 4, + }, + "zero decimal and decimal places": { + src: "0.00000", + exp: "0", + decPlaces: 0, }, } for name, spec := range specs { t.Run(name, func(t *testing.T) { - src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) - - ops := map[string]struct { - fn func(src math.LegacyDec) math.LegacyDec - }{ - "AddMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.AddMut(math.LegacyNewDec(0)) }, - }, - "SubMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.SubMut(math.LegacyNewDec(0)) }, - }, - "MulMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.MulMut(math.LegacyNewDec(1)) }, - }, - "MulTruncateMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.MulTruncateMut(math.LegacyNewDec(1)) }, - }, - "MulRoundUpMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.MulRoundUpMut(math.LegacyNewDec(1)) }, - }, - "MulIntMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.MulIntMut(math.NewInt(1)) }, - }, - "MulInt64Mut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.MulInt64Mut(1) }, - }, - "QuoMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.QuoMut(math.LegacyNewDec(1)) }, - }, - "QuoTruncateMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.QuoTruncateMut(math.LegacyNewDec(1)) }, - }, - "QuoRoundupMut": { - fn: func(src math.LegacyDec) math.LegacyDec { return src.QuoRoundupMut(math.LegacyNewDec(1)) }, - }, - } - for name, op := range ops { - t.Run(name, func(t *testing.T) { - if spec.expErr { - assert.Panics(t, func() { - got := op.fn(src) - t.Log(got.String()) - }) - return - } - exp := src.String() - // exp no panics - got := op.fn(src) - assert.Equal(t, exp, got.String()) - }) - } + src := must(NewDecFromString(spec.src)) + got, gotZerosRemoved := src.Reduce() + assert.Equal(t, spec.decPlaces, gotZerosRemoved) + assert.Equal(t, spec.exp, got.String()) }) } } -func TestDecCeilLimits(t *testing.T) { - maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) - require.True(t, ok) - minValid := new(big.Int).Neg(maxValid) - +func TestMulExact(t *testing.T) { specs := map[string]struct { - src *big.Int - exp string - expErr bool + x Dec + y Dec + exp Dec + expErr error }{ - "max": { - src: maxValid, - expErr: true, - }, - "max + 1": { - src: new(big.Int).Add(maxValid, big.NewInt(1)), - expErr: true, - }, - "max - 1e18, previous full number": { - src: new(big.Int).Sub(maxValid, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)), - exp: "115792089237316195423570985008687907853269984665640564039457584007913129639935.000000000000000000", - }, - "min": { - src: minValid, - exp: "-115792089237316195423570985008687907853269984665640564039457584007913129639935.000000000000000000", - }, - "min - 1": { - src: new(big.Int).Sub(minValid, big.NewInt(1)), - expErr: true, + "200 * 200 = 40000": { + x: NewDecFromInt64(200), + y: NewDecFromInt64(200), + exp: NewDecFromInt64(40000), + }, + "-200 * -200 = 40000": { + x: NewDecFromInt64(-200), + y: NewDecFromInt64(-200), + exp: NewDecFromInt64(40000), + }, + "-100 * -100 = 10000": { + x: NewDecFromInt64(-100), + y: NewDecFromInt64(-100), + exp: NewDecFromInt64(10000), + }, + "0 * 0 = 0": { + x: NewDecFromInt64(0), + y: NewDecFromInt64(0), + exp: NewDecFromInt64(0), + }, + "1.1 * 1.1 = 1.21": { + x: NewDecWithExp(11, -1), + y: NewDecWithExp(11, -1), + exp: NewDecWithExp(121, -2), + }, + "1.000 * 1.000 = 1.000000": { + x: NewDecWithExp(1000, -3), + y: NewDecWithExp(1000, -3), + exp: must(NewDecFromString("1.000000")), + }, + "0.0000001 * 0.0000001 = 0": { + x: NewDecWithExp(0o0000001, -7), + y: NewDecWithExp(0o0000001, -7), + exp: NewDecWithExp(1, -14), + }, + "0.12345678901234567890123456789012345 * 1": { + x: must(NewDecFromString("0.12345678901234567890123456789012345")), + y: NewDecWithExp(1, 0), + expErr: ErrUnexpectedRounding, + }, + "0.12345678901234567890123456789012345 * 0": { + x: must(NewDecFromString("0.12345678901234567890123456789012345")), + y: NewDecFromInt64(0), + exp: NewDecFromInt64(0), + }, + "0.12345678901234567890123456789012345 * 0.1": { + x: must(NewDecFromString("0.12345678901234567890123456789012345")), + y: NewDecWithExp(1, -1), + expErr: ErrUnexpectedRounding, + }, + "1000001 * 1.000001 = 1000002.000001": { + x: NewDecFromInt64(1000001), + y: NewDecWithExp(1000001, -6), + exp: must(NewDecFromString("1000002.000001")), + }, + "1000001 * 1000000 = 1000001000000 ": { + x: NewDecFromInt64(1000001), + y: NewDecFromInt64(1000000), + exp: NewDecFromInt64(1000001000000), + }, + "1e0000 * 1e0000 -> Err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(1, 100_000), + expErr: ErrInvalidDec, + }, + "1e0000 * 1 = 1e0000": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(1, 0), + exp: NewDecWithExp(1, 100_000), + }, + "1e100000 * 9 = 9e100000": { + x: NewDecWithExp(1, 100_000), + y: NewDecFromInt64(9), + exp: NewDecWithExp(9, 100_000), + }, + "1e100000 * 10 = err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(1, 1), + expErr: ErrInvalidDec, + }, + "1e0000 * -1 = -1e0000": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(-1, 0), + exp: NewDecWithExp(-1, 100_000), + }, + "1e100000 * -9 = 9e100000": { + x: NewDecWithExp(1, 100_000), + y: NewDecFromInt64(-9), + exp: NewDecWithExp(-9, 100_000), + }, + "1e100000 * -10 = err": { + x: NewDecWithExp(1, 100_000), + y: NewDecWithExp(-1, 1), + expErr: ErrInvalidDec, }, } for name, spec := range specs { t.Run(name, func(t *testing.T) { - src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) - if spec.expErr { - assert.Panics(t, func() { - got := src.Ceil() - t.Log(got.String()) - }) + got, gotErr := spec.x.MulExact(spec.y) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr, gotErr) return } - got := src.Ceil() - assert.Equal(t, spec.exp, got.String()) + require.NoError(t, gotErr) + assert.True(t, spec.exp.Equal(got), "exp: %s, got: %s", spec.exp.Text('E'), got.Text('E')) }) } } -func TestTruncateIntLimits(t *testing.T) { - maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) - require.True(t, ok) - minValid := new(big.Int).Neg(maxValid) +func TestToBigInt(t *testing.T) { + i1 := "1000000000000000000000000000000000000123456789" + tcs := []struct { + intStr string + out string + isError error + }{ + {i1, i1, nil}, + {"1000000000000000000000000000000000000123456789.00000000", i1, nil}, + {"123.456e6", "123456000", nil}, + {"12345.6", "", ErrNonIntegral}, + } + for idx, tc := range tcs { + a, err := NewDecFromString(tc.intStr) + require.NoError(t, err) + b, err := a.BigInt() + if tc.isError == nil { + require.NoError(t, err, "test_%d", idx) + require.Equal(t, tc.out, b.String(), "test_%d", idx) + } else { + require.ErrorIs(t, err, tc.isError, "test_%d", idx) + } + } +} - specs := map[string]struct { - src *big.Int +func TestToSdkInt(t *testing.T) { + maxIntValue := "115792089237316195423570985008687907853269984665640564039457584007913129639935" // 2^256 -1 + tcs := []struct { + src string exp string expErr bool }{ - "max": { - src: maxValid, - exp: "115792089237316195423570985008687907853269984665640564039457584007913129639935", - }, - "max + 1": { - src: new(big.Int).Add(maxValid, big.NewInt(1)), - expErr: true, - }, - "min": { - src: minValid, - exp: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", - }, - "min - 1": { - src: new(big.Int).Sub(minValid, big.NewInt(1)), - expErr: true, - }, + {src: maxIntValue, exp: maxIntValue}, + {src: "1000000000000000000000000000000000000123456789.00000001", exp: "1000000000000000000000000000000000000123456789"}, + {src: "123.456e6", exp: "123456000"}, + {src: "123.456e1", exp: "1234"}, + {src: "123.456", exp: "123"}, + {src: "123.956", exp: "123"}, + {src: "-123.456", exp: "-123"}, + {src: "-123.956", exp: "-123"}, + {src: "-0.956", exp: "0"}, + {src: "-0.9", exp: "0"}, + {src: "1E-100000", exp: "0"}, + {src: "115792089237316195423570985008687907853269984665640564039457584007913129639936", expErr: true}, // 2^256 + {src: "1E100000", expErr: true}, } - for name, spec := range specs { - t.Run(name, func(t *testing.T) { - src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) - if spec.expErr { - assert.Panics(t, func() { - got := src.TruncateInt() - t.Log(got.String()) - }) + for _, tc := range tcs { + t.Run(fmt.Sprintf(tc.src), func(t *testing.T) { + a, err := NewDecFromString(tc.src) + require.NoError(t, err) + b, gotErr := a.SdkIntTrim() + if tc.expErr { + require.Error(t, gotErr, "value: %s", b.String()) return } - got := src.TruncateInt() - assert.Equal(t, spec.exp, got.String()) + require.NoError(t, gotErr) + require.Equal(t, tc.exp, b.String()) }) } } -func TestRoundIntLimits(t *testing.T) { - maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) - require.True(t, ok) - minValid := new(big.Int).Neg(maxValid) - oneE18 := new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil) +func TestInfDecString(t *testing.T) { + _, err := NewDecFromString("iNf") + require.Error(t, err) + require.ErrorIs(t, err, ErrInvalidDec) +} +func must[T any](r T, err error) T { + if err != nil { + panic(err) + } + return r +} + +func TestMarshalUnmarshal(t *testing.T) { + t.Skip("not supported, yet") specs := map[string]struct { - src *big.Int + x Dec exp string - expErr bool + expErr error }{ - "max -1e18; previous full number": { - src: new(big.Int).Sub(maxValid, oneE18), - exp: "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "No trailing zeros": { + x: NewDecFromInt64(123456), + exp: "1.23456E+5", + }, + "Trailing zeros": { + x: NewDecFromInt64(123456000), + exp: "1.23456E+8", + }, + "Zero value": { + x: NewDecFromInt64(0), + exp: "0E+0", }, - "max": { - src: maxValid, - expErr: true, + "-0": { + x: NewDecFromInt64(-0), + exp: "0E+0", }, - "max + 1": { - src: new(big.Int).Add(maxValid, big.NewInt(1)), - expErr: true, + "Decimal value": { + x: must(NewDecFromString("1.30000")), + exp: "1.3E+0", }, - "min + 1e18; previous full number": { - src: new(big.Int).Add(minValid, oneE18), - exp: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", + "Positive value": { + x: NewDecFromInt64(10), + exp: "1E+1", }, - "min": { - src: minValid, - expErr: true, + "negative 10": { + x: NewDecFromInt64(-10), + exp: "-1E+1", }, - "min - 1": { - src: new(big.Int).Sub(minValid, big.NewInt(1)), - expErr: true, + "9 with trailing zeros": { + x: must(NewDecFromString("9." + strings.Repeat("0", 34))), + exp: "9E+0", + }, + "negative 1 with negative exponent zeros": { + x: must(NewDecFromString("-1.000001")), + exp: "-1.000001E+0", + }, + "negative 1 with trailing zeros": { + x: must(NewDecFromString("-1." + strings.Repeat("0", 34))), + exp: "-1E+0", + }, + "5 decimal places": { + x: must(NewDecFromString("0.00001")), + exp: "1E-5", + }, + "6 decimal places": { + x: must(NewDecFromString("0.000001")), + exp: "1E-6", + }, + "7 decimal places": { + x: must(NewDecFromString("0.0000001")), + exp: "1E-7", + }, + "4 decimal places before the comma": { + x: must(NewDecFromString("1000")), + exp: "1E+3", + }, + "5 decimal places before the comma": { + x: must(NewDecFromString("10000")), + exp: "1E+4", + }, + "6 decimal places before the comma": { + x: must(NewDecFromString("100000")), + exp: "1E+5", + }, + "7 decimal places before the comma": { + x: must(NewDecFromString("1000000")), + exp: "1E+6", + }, + "1e100000": { + x: NewDecWithExp(1, 100_000), + exp: "1E+100000", + }, + "1.1e100000": { + x: NewDecWithExp(11, 100_000), + expErr: ErrInvalidDec, + }, + "1.e100000": { + x: NewDecWithExp(1, 100_000), + exp: "1E+100000", }, } for name, spec := range specs { t.Run(name, func(t *testing.T) { - src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) - t.Log(src.String()) - if spec.expErr { - assert.Panics(t, func() { - got := src.RoundInt() - t.Log(got.String()) - }) + marshaled, gotErr := spec.x.Marshal() + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) return } - got := src.RoundInt() - assert.Equal(t, spec.exp, got.String()) - }) - } -} - -func BenchmarkIsInValidRange(b *testing.B) { - maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) - require.True(b, ok) - souceMax := math.LegacyNewDecFromBigIntWithPrec(maxValid, 18) - b.ResetTimer() - specs := map[string]math.LegacyDec{ - "max": souceMax, - "greater max": math.LegacyNewDecFromBigIntWithPrec(maxValid, 16), - "min": souceMax.Neg(), - "lower min": math.LegacyNewDecFromBigIntWithPrec(new(big.Int).Neg(maxValid), 16), - "zero": math.LegacyZeroDec(), - "one": math.LegacyOneDec(), - } - for name, source := range specs { - b.Run(name, func(b *testing.B) { - for i := 0; i < b.N; i++ { - _ = source.IsInValidRange() - } + require.NoError(t, gotErr) + unmarshalled := new(Dec) + require.NoError(t, unmarshalled.Unmarshal(marshaled)) + assert.Equal(t, spec.exp, unmarshalled.dec.Text('E')) }) } } diff --git a/math/go.mod b/math/go.mod index c18586f7560b..c9010281045c 100644 --- a/math/go.mod +++ b/math/go.mod @@ -3,17 +3,29 @@ module cosmossdk.io/math go 1.20 require ( + github.com/cockroachdb/apd/v3 v3.2.1 github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20221205204356-47842c84f3db + golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 sigs.k8s.io/yaml v1.4.0 ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.24.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5 // indirect + google.golang.org/grpc v1.64.1 // indirect + google.golang.org/protobuf v1.34.2 // indirect +) + +require ( + cosmossdk.io/errors v1.0.1 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + pgregory.net/rapid v1.1.0 ) // Issue with math.Int{}.Size() implementation. diff --git a/math/go.sum b/math/go.sum index a6d9afc96b85..8e1220a775b7 100644 --- a/math/go.sum +++ b/math/go.sum @@ -1,28 +1,45 @@ +cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= +cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5 h1:SbSDUWW1PAO24TNpLdeheoYPd7kllICcLU52x6eD4kQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240709173604-40e1e62336c5/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/math/int_test.go b/math/int_test.go index 36c2e453ea06..e09caf6ae566 100644 --- a/math/int_test.go +++ b/math/int_test.go @@ -499,7 +499,6 @@ func TestRoundTripMarshalToInt(t *testing.T) { } for _, value := range values { - value := value t.Run(fmt.Sprintf("%d", value), func(t *testing.T) { t.Parallel() @@ -548,7 +547,6 @@ func TestFormatIntNonDigits(t *testing.T) { } for _, value := range badCases { - value := value t.Run(value, func(t *testing.T) { s, err := math.FormatInt(value) if err == nil { diff --git a/math/legacy_dec.go b/math/legacy_dec.go new file mode 100644 index 000000000000..16bb0806861b --- /dev/null +++ b/math/legacy_dec.go @@ -0,0 +1,971 @@ +package math + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "strconv" + "strings" + "testing" +) + +// LegacyDec NOTE: never use new(Dec) or else we will panic unmarshalling into the +// nil embedded big.Int +type LegacyDec struct { + i *big.Int +} + +const ( + // LegacyPrecision number of decimal places + LegacyPrecision = 18 + + // LegacyDecimalPrecisionBits bits required to represent the above precision + // Ceiling[Log2[10^Precision - 1]] + // Deprecated: This is unused and will be removed + LegacyDecimalPrecisionBits = 60 + + // maxApproxRootIterations max number of iterations in ApproxRoot function + maxApproxRootIterations = 300 +) + +var ( + precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(LegacyPrecision), nil) + fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2)) + + upperLimit LegacyDec + lowerLimit LegacyDec + + precisionMultipliers []*big.Int + zeroInt = big.NewInt(0) + oneInt = big.NewInt(1) + tenInt = big.NewInt(10) + smallestDec = LegacySmallestDec() +) + +// Decimal errors +var ( + ErrLegacyEmptyDecimalStr = errors.New("decimal string cannot be empty") + ErrLegacyInvalidDecimalLength = errors.New("invalid decimal length") + ErrLegacyInvalidDecimalStr = errors.New("invalid decimal string") +) + +// Set precision multipliers +func init() { + precisionMultipliers = make([]*big.Int, LegacyPrecision+1) + for i := 0; i <= LegacyPrecision; i++ { + precisionMultipliers[i] = calcPrecisionMultiplier(int64(i)) + } + // 2^256 * 10^18 -1 + tmp := new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil) + tmp = new(big.Int).Sub(new(big.Int).Mul(tmp, precisionReuse), big.NewInt(1)) + upperLimit = LegacyNewDecFromBigIntWithPrec(tmp, LegacyPrecision) + lowerLimit = upperLimit.Neg() +} + +func precisionInt() *big.Int { + return new(big.Int).Set(precisionReuse) +} + +func LegacyZeroDec() LegacyDec { return LegacyDec{new(big.Int).Set(zeroInt)} } +func LegacyOneDec() LegacyDec { return LegacyDec{precisionInt()} } +func LegacySmallestDec() LegacyDec { return LegacyDec{new(big.Int).Set(oneInt)} } + +// calculate the precision multiplier +func calcPrecisionMultiplier(prec int64) *big.Int { + if prec < 0 { + panic(fmt.Sprintf("negative precision %v", prec)) + } + + if prec > LegacyPrecision { + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", LegacyPrecision, prec)) + } + zerosToAdd := LegacyPrecision - prec + multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) + return multiplier +} + +// get the precision multiplier, do not mutate result +func precisionMultiplier(prec int64) *big.Int { + if prec < 0 { + panic(fmt.Sprintf("negative precision %v", prec)) + } + + if prec > LegacyPrecision { + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", LegacyPrecision, prec)) + } + return precisionMultipliers[prec] +} + +// LegacyNewDec create a new Dec from integer assuming whole number +func LegacyNewDec(i int64) LegacyDec { + return LegacyNewDecWithPrec(i, 0) +} + +// LegacyNewDecWithPrec create a new Dec from integer with decimal place at prec +// CONTRACT: prec <= Precision +func LegacyNewDecWithPrec(i, prec int64) LegacyDec { + bi := big.NewInt(i) + return LegacyDec{ + bi.Mul(bi, precisionMultiplier(prec)), + } +} + +// LegacyNewDecFromBigInt create a new Dec from big integer assuming whole numbers +// CONTRACT: prec <= Precision +func LegacyNewDecFromBigInt(i *big.Int) LegacyDec { + return LegacyNewDecFromBigIntWithPrec(i, 0) +} + +// LegacyNewDecFromBigIntWithPrec create a new Dec from big integer assuming whole numbers +// CONTRACT: prec <= Precision +func LegacyNewDecFromBigIntWithPrec(i *big.Int, prec int64) LegacyDec { + return LegacyDec{ + new(big.Int).Mul(i, precisionMultiplier(prec)), + } +} + +// LegacyNewDecFromInt create a new Dec from big integer assuming whole numbers +// CONTRACT: prec <= Precision +func LegacyNewDecFromInt(i Int) LegacyDec { + return LegacyNewDecFromIntWithPrec(i, 0) +} + +// LegacyNewDecFromIntWithPrec create a new Dec from big integer with decimal place at prec +// CONTRACT: prec <= Precision +func LegacyNewDecFromIntWithPrec(i Int, prec int64) LegacyDec { + return LegacyDec{ + new(big.Int).Mul(i.BigIntMut(), precisionMultiplier(prec)), + } +} + +// LegacyNewDecFromStr create a decimal from an input decimal string. +// valid must come in the form: +// +// (-) whole integers (.) decimal integers +// +// examples of acceptable input include: +// +// -123.456 +// 456.7890 +// 345 +// -456789 +// +// NOTE - An error will return if more decimal places +// are provided in the string than the constant Precision. +// +// CONTRACT - This function does not mutate the input str. +func LegacyNewDecFromStr(str string) (LegacyDec, error) { + // first extract any negative symbol + neg := false + if len(str) > 0 && str[0] == '-' { + neg = true + str = str[1:] + } + + if len(str) == 0 { + return LegacyDec{}, ErrLegacyEmptyDecimalStr + } + + strs := strings.Split(str, ".") + lenDecs := 0 + combinedStr := strs[0] + + if len(strs) == 2 { // has a decimal place + lenDecs = len(strs[1]) + if lenDecs == 0 || len(combinedStr) == 0 { + return LegacyDec{}, ErrLegacyInvalidDecimalLength + } + combinedStr += strs[1] + } else if len(strs) > 2 { + return LegacyDec{}, ErrLegacyInvalidDecimalStr + } + + if lenDecs > LegacyPrecision { + return LegacyDec{}, fmt.Errorf("value '%s' exceeds max precision by %d decimal places: max precision %d", str, LegacyPrecision-lenDecs, LegacyPrecision) + } + + // add some extra zero's to correct to the Precision factor + zerosToAdd := LegacyPrecision - lenDecs + zeros := strings.Repeat("0", zerosToAdd) + combinedStr += zeros + + combined, ok := new(big.Int).SetString(combinedStr, 10) // base 10 + if !ok { + return LegacyDec{}, fmt.Errorf("failed to set decimal string with base 10: %s", combinedStr) + } + if neg { + combined = new(big.Int).Neg(combined) + } + + result := LegacyDec{i: combined} + if !result.IsInValidRange() { + return LegacyDec{}, fmt.Errorf("out of range: %w", ErrLegacyInvalidDecimalStr) + } + return result, nil +} + +// LegacyMustNewDecFromStr Decimal from string, panic on error +func LegacyMustNewDecFromStr(s string) LegacyDec { + dec, err := LegacyNewDecFromStr(s) + if err != nil { + panic(err) + } + return dec +} + +func (d LegacyDec) IsNil() bool { return d.i == nil } // is decimal nil +func (d LegacyDec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero +func (d LegacyDec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative +func (d LegacyDec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive +func (d LegacyDec) Equal(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals +func (d LegacyDec) GT(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than +func (d LegacyDec) GTE(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal +func (d LegacyDec) LT(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) < 0 } // less than +func (d LegacyDec) LTE(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal +func (d LegacyDec) Neg() LegacyDec { return LegacyDec{new(big.Int).Neg(d.i)} } // reverse the decimal sign +func (d LegacyDec) NegMut() LegacyDec { d.i.Neg(d.i); return d } // reverse the decimal sign, mutable +func (d LegacyDec) Abs() LegacyDec { return LegacyDec{new(big.Int).Abs(d.i)} } // absolute value +func (d LegacyDec) AbsMut() LegacyDec { d.i.Abs(d.i); return d } // absolute value, mutable +func (d LegacyDec) Set(d2 LegacyDec) LegacyDec { d.i.Set(d2.i); return d } // set to existing dec value +func (d LegacyDec) Clone() LegacyDec { return LegacyDec{new(big.Int).Set(d.i)} } // clone new dec + +// BigInt returns a copy of the underlying big.Int. +func (d LegacyDec) BigInt() *big.Int { + if d.IsNil() { + return nil + } + + cp := new(big.Int) + return cp.Set(d.i) +} + +// BigIntMut converts LegacyDec to big.Int, mutative the input +func (d LegacyDec) BigIntMut() *big.Int { + if d.IsNil() { + return nil + } + + return d.i +} + +func (d LegacyDec) ImmutOp(op func(LegacyDec, LegacyDec) LegacyDec, d2 LegacyDec) LegacyDec { + return op(d.Clone(), d2) +} + +func (d LegacyDec) ImmutOpInt(op func(LegacyDec, Int) LegacyDec, d2 Int) LegacyDec { + return op(d.Clone(), d2) +} + +func (d LegacyDec) ImmutOpInt64(op func(LegacyDec, int64) LegacyDec, d2 int64) LegacyDec { + // TODO: use already allocated operand bigint to avoid + // newint each time, add mutex for race condition + // Issue: https://github.com/cosmos/cosmos-sdk/issues/11166 + return op(d.Clone(), d2) +} + +func (d LegacyDec) SetInt64(i int64) LegacyDec { + d.i.SetInt64(i) + d.i.Mul(d.i, precisionReuse) + return d +} + +// Add addition +func (d LegacyDec) Add(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.AddMut, d2) +} + +// AddMut mutable addition +func (d LegacyDec) AddMut(d2 LegacyDec) LegacyDec { + d.i.Add(d.i, d2.i) + + d.assertInValidRange() + return d +} + +// Sub subtraction +func (d LegacyDec) Sub(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.SubMut, d2) +} + +// SubMut mutable subtraction +func (d LegacyDec) SubMut(d2 LegacyDec) LegacyDec { + d.i.Sub(d.i, d2.i) + + d.assertInValidRange() + return d +} + +func (d LegacyDec) assertInValidRange() { + if !d.IsInValidRange() { + panic("Int overflow") + } +} + +// IsInValidRange returns true when the value is between the upper limit of (2^256 * 10^18) +// and the lower limit of -1*(2^256 * 10^18). +func (d LegacyDec) IsInValidRange() bool { + return !(d.GT(upperLimit) || d.LT(lowerLimit)) +} + +// Mul multiplication +func (d LegacyDec) Mul(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.MulMut, d2) +} + +// MulMut mutable multiplication +func (d LegacyDec) MulMut(d2 LegacyDec) LegacyDec { + d.i.Mul(d.i, d2.i) + chopped := chopPrecisionAndRound(d.i) + + *d.i = *chopped + d.assertInValidRange() + return d +} + +// MulTruncate multiplication truncate +func (d LegacyDec) MulTruncate(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.MulTruncateMut, d2) +} + +// MulTruncateMut mutable multiplication truncate +func (d LegacyDec) MulTruncateMut(d2 LegacyDec) LegacyDec { + d.i.Mul(d.i, d2.i) + chopPrecisionAndTruncate(d.i) + d.assertInValidRange() + return d +} + +// MulRoundUp multiplication round up at precision end. +func (d LegacyDec) MulRoundUp(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.MulRoundUpMut, d2) +} + +// MulRoundUpMut mutable multiplication with round up at precision end. +func (d LegacyDec) MulRoundUpMut(d2 LegacyDec) LegacyDec { + d.i.Mul(d.i, d2.i) + chopPrecisionAndRoundUp(d.i) + + d.assertInValidRange() + return d +} + +// MulInt multiplication +func (d LegacyDec) MulInt(i Int) LegacyDec { + return d.ImmutOpInt(LegacyDec.MulIntMut, i) +} + +func (d LegacyDec) MulIntMut(i Int) LegacyDec { + d.i.Mul(d.i, i.BigIntMut()) + d.assertInValidRange() + return d +} + +// MulInt64 multiplication with int64 +func (d LegacyDec) MulInt64(i int64) LegacyDec { + return d.ImmutOpInt64(LegacyDec.MulInt64Mut, i) +} + +func (d LegacyDec) MulInt64Mut(i int64) LegacyDec { + d.i.Mul(d.i, big.NewInt(i)) + d.assertInValidRange() + return d +} + +// Quo quotient +func (d LegacyDec) Quo(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.QuoMut, d2) +} + +var squaredPrecisionReuse = new(big.Int).Mul(precisionReuse, precisionReuse) + +// QuoMut mutable quotient +func (d LegacyDec) QuoMut(d2 LegacyDec) LegacyDec { + // multiply by precision twice + d.i.Mul(d.i, squaredPrecisionReuse) + d.i.Quo(d.i, d2.i) + + chopPrecisionAndRound(d.i) + d.assertInValidRange() + return d +} + +// QuoTruncate quotient truncate +func (d LegacyDec) QuoTruncate(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.QuoTruncateMut, d2) +} + +// QuoTruncateMut divides the current LegacyDec value by the provided LegacyDec value, truncating the result. +func (d LegacyDec) QuoTruncateMut(d2 LegacyDec) LegacyDec { + // multiply precision once before performing division + d.i.Mul(d.i, precisionReuse) + d.i.Quo(d.i, d2.i) + + d.assertInValidRange() + return d +} + +// QuoRoundUp quotient, round up +func (d LegacyDec) QuoRoundUp(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.QuoRoundupMut, d2) +} + +// QuoRoundupMut mutable quotient, round up +func (d LegacyDec) QuoRoundupMut(d2 LegacyDec) LegacyDec { + // multiply precision twice + d.i.Mul(d.i, precisionReuse) + _, rem := d.i.QuoRem(d.i, d2.i, big.NewInt(0)) + if rem.Sign() > 0 && d.IsNegative() == d2.IsNegative() || + rem.Sign() < 0 && d.IsNegative() != d2.IsNegative() { + d.i.Add(d.i, oneInt) + } + d.assertInValidRange() + return d +} + +// QuoInt quotient +func (d LegacyDec) QuoInt(i Int) LegacyDec { + return d.ImmutOpInt(LegacyDec.QuoIntMut, i) +} + +func (d LegacyDec) QuoIntMut(i Int) LegacyDec { + d.i.Quo(d.i, i.BigIntMut()) + return d +} + +// QuoInt64 quotient with int64 +func (d LegacyDec) QuoInt64(i int64) LegacyDec { + return d.ImmutOpInt64(LegacyDec.QuoInt64Mut, i) +} + +func (d LegacyDec) QuoInt64Mut(i int64) LegacyDec { + d.i.Quo(d.i, big.NewInt(i)) + return d +} + +// ApproxRoot returns an approximate estimation of a Dec's positive real nth root +// using Newton's method (where n is positive). The algorithm starts with some guess and +// computes the sequence of improved guesses until an answer converges to an +// approximate answer. It returns `|d|.ApproxRoot() * -1` if input is negative. +// A maximum number of 100 iterations is used a backup boundary condition for +// cases where the answer never converges enough to satisfy the main condition. +func (d LegacyDec) ApproxRoot(root uint64) (guess LegacyDec, err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + err, ok = r.(error) + if !ok { + err = errors.New("out of bounds") + } + } + }() + + if root == 0 { + // Return 1 as root 0 of any number is considered 1. + return LegacyOneDec(), nil + } + + if d.IsNegative() { + absRoot, err := d.Neg().ApproxRoot(root) + return absRoot.NegMut(), err + } + + // Direct return for base cases: d^1 = d or when d is 0 or 1. + scratchOneDec := LegacyOneDec() + if root == 1 || d.IsZero() || d.Equal(scratchOneDec) { + return d, nil + } + + guess, delta := scratchOneDec, LegacyOneDec() + + for iter := 0; iter < maxApproxRootIterations; iter++ { + prev := guess.Power(root - 1) + if prev.IsZero() { + prev = smallestDec + } + + // Compute delta = (d/prev - guess) / root + delta.Set(d).QuoMut(prev) + delta.SubMut(guess) + delta.QuoInt64Mut(int64(root)) + + guess.AddMut(delta) + + // Stop when delta is small enough + if delta.Abs().LTE(smallestDec) { + break + } + } + + return guess, nil +} + +// Power returns the result of raising to a positive integer power +func (d LegacyDec) Power(power uint64) LegacyDec { + res := LegacyDec{new(big.Int).Set(d.i)} + return res.PowerMut(power) +} + +func (d LegacyDec) PowerMut(power uint64) LegacyDec { + if power == 0 { + // Set to 1 with the correct precision. + d.i.Set(precisionReuse) + return d + } + tmp := LegacyOneDec() + + for i := power; i > 1; { + if i%2 != 0 { + tmp.MulMut(d) + } + i /= 2 + d.MulMut(d) + } + + return d.MulMut(tmp) +} + +// ApproxSqrt is a wrapper around ApproxRoot for the common special case +// of finding the square root of a number. It returns -(sqrt(abs(d)) if input is negative. +func (d LegacyDec) ApproxSqrt() (LegacyDec, error) { + return d.ApproxRoot(2) +} + +// IsInteger is integer, e.g. decimals are zero +func (d LegacyDec) IsInteger() bool { + return new(big.Int).Rem(d.i, precisionReuse).Sign() == 0 +} + +// Format format decimal state +func (d LegacyDec) Format(s fmt.State, verb rune) { + _, err := s.Write([]byte(d.String())) + if err != nil { + panic(err) + } +} + +func (d LegacyDec) String() string { + if d.i == nil { + return d.i.String() + } + + isNeg := d.IsNegative() + + if isNeg { + d = d.Neg() + } + + bzInt, err := d.i.MarshalText() + if err != nil { + return "" + } + inputSize := len(bzInt) + + var bzStr []byte + + // TODO: Remove trailing zeros + // case 1, purely decimal + if inputSize <= LegacyPrecision { + bzStr = make([]byte, LegacyPrecision+2) + + // 0. prefix + bzStr[0] = byte('0') + bzStr[1] = byte('.') + + // set relevant digits to 0 + for i := 0; i < LegacyPrecision-inputSize; i++ { + bzStr[i+2] = byte('0') + } + + // set final digits + copy(bzStr[2+(LegacyPrecision-inputSize):], bzInt) + } else { + // inputSize + 1 to account for the decimal point that is being added + bzStr = make([]byte, inputSize+1) + decPointPlace := inputSize - LegacyPrecision + + copy(bzStr, bzInt[:decPointPlace]) // pre-decimal digits + bzStr[decPointPlace] = byte('.') // decimal point + copy(bzStr[decPointPlace+1:], bzInt[decPointPlace:]) // post-decimal digits + } + + if isNeg { + return "-" + string(bzStr) + } + + return string(bzStr) +} + +// Float64 returns the float64 representation of a Dec. +// Will return the error if the conversion failed. +func (d LegacyDec) Float64() (float64, error) { + return strconv.ParseFloat(d.String(), 64) +} + +// MustFloat64 returns the float64 representation of a Dec. +// Would panic if the conversion failed. +func (d LegacyDec) MustFloat64() float64 { + if value, err := strconv.ParseFloat(d.String(), 64); err != nil { + panic(err) + } else { + return value + } +} + +// ____ +// __| |__ "chop 'em +// ` \ round!" +// ___|| ~ _ -bankers +// | | __ +// | | | __|__|__ +// |_____: / | $$$ | +// |________| + +// Remove a Precision amount of rightmost digits and perform bankers rounding +// on the remainder (gaussian rounding) on the digits which have been removed. +// +// Mutates the input. Use the non-mutative version if that is undesired +func chopPrecisionAndRound(d *big.Int) *big.Int { + // remove the negative and add it back when returning + if d.Sign() == -1 { + // make d positive, compute chopped value, and then un-mutate d + d = d.Neg(d) + d = chopPrecisionAndRound(d) + d = d.Neg(d) + return d + } + + // get the truncated quotient and remainder + quo, rem := d, big.NewInt(0) + quo, rem = quo.QuoRem(d, precisionReuse, rem) + + if rem.Sign() == 0 { // remainder is zero + return quo + } + + switch rem.Cmp(fivePrecision) { + case -1: + return quo + case 1: + return quo.Add(quo, oneInt) + default: // bankers rounding must take place + // always round to an even number + if quo.Bit(0) == 0 { + return quo + } + return quo.Add(quo, oneInt) + } +} + +func chopPrecisionAndRoundUp(d *big.Int) *big.Int { + // remove the negative and add it back when returning + if d.Sign() == -1 { + // make d positive, compute chopped value, and then un-mutate d + d = d.Neg(d) + // truncate since d is negative... + chopPrecisionAndTruncate(d) + d = d.Neg(d) + return d + } + + // get the truncated quotient and remainder + quo, rem := d, big.NewInt(0) + quo, rem = quo.QuoRem(d, precisionReuse, rem) + + if rem.Sign() == 0 { // remainder is zero + return quo + } + + return quo.Add(quo, oneInt) +} + +func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int { + tmp := new(big.Int).Set(d) + return chopPrecisionAndRound(tmp) +} + +// RoundInt64 rounds the decimal using bankers rounding +func (d LegacyDec) RoundInt64() int64 { + chopped := chopPrecisionAndRoundNonMutative(d.i) + if !chopped.IsInt64() { + panic("Int64() out of bound") + } + return chopped.Int64() +} + +// RoundInt round the decimal using bankers rounding +func (d LegacyDec) RoundInt() Int { + return NewIntFromBigIntMut(chopPrecisionAndRoundNonMutative(d.i)) +} + +// chopPrecisionAndTruncate is similar to chopPrecisionAndRound, +// but always rounds down. It does not mutate the input. +func chopPrecisionAndTruncate(d *big.Int) { + d.Quo(d, precisionReuse) +} + +func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { + tmp := new(big.Int).Set(d) + chopPrecisionAndTruncate(tmp) + return tmp +} + +// TruncateInt64 truncates the decimals from the number and returns an int64 +func (d LegacyDec) TruncateInt64() int64 { + chopped := chopPrecisionAndTruncateNonMutative(d.i) + if !chopped.IsInt64() { + panic("Int64() out of bound") + } + return chopped.Int64() +} + +// TruncateInt truncates the decimals from the number and returns an Int +func (d LegacyDec) TruncateInt() Int { + return NewIntFromBigIntMut(chopPrecisionAndTruncateNonMutative(d.i)) +} + +// TruncateDec truncates the decimals from the number and returns a Dec +func (d LegacyDec) TruncateDec() LegacyDec { + return LegacyNewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) +} + +// Ceil returns the smallest integer value (as a decimal) that is greater than +// or equal to the given decimal. +func (d LegacyDec) Ceil() LegacyDec { + tmp := new(big.Int).Set(d.i) + + quo, rem := tmp, big.NewInt(0) + quo, rem = quo.QuoRem(tmp, precisionReuse, rem) + + // no need to round with a zero remainder regardless of sign + var r LegacyDec + switch rem.Sign() { + case 0: + r = LegacyNewDecFromBigInt(quo) + case -1: + r = LegacyNewDecFromBigInt(quo) + default: + r = LegacyNewDecFromBigInt(quo.Add(quo, oneInt)) + } + r.assertInValidRange() + return r +} + +// LegacyMaxSortableDec is the largest Dec that can be passed into SortableDecBytes() +// Its negative form is the least Dec that can be passed in. +var LegacyMaxSortableDec LegacyDec + +func init() { + LegacyMaxSortableDec = LegacyOneDec().Quo(LegacySmallestDec()) +} + +// LegacyValidSortableDec ensures that a Dec is within the sortable bounds, +// a Dec can't have a precision of less than 10^-18. +// Max sortable decimal was set to the reciprocal of SmallestDec. +func LegacyValidSortableDec(dec LegacyDec) bool { + return dec.Abs().LTE(LegacyMaxSortableDec) +} + +// LegacySortableDecBytes returns a byte slice representation of a Dec that can be sorted. +// Left and right pads with 0s so there are 18 digits to left and right of the decimal point. +// For this reason, there is a maximum and minimum value for this, enforced by ValidSortableDec. +func LegacySortableDecBytes(dec LegacyDec) []byte { + if !LegacyValidSortableDec(dec) { + panic("dec must be within bounds") + } + // Instead of adding an extra byte to all sortable decs in order to handle max sortable, we just + // makes its bytes be "max" which comes after all numbers in ASCIIbetical order + if dec.Equal(LegacyMaxSortableDec) { + return []byte("max") + } + // For the same reason, we make the bytes of minimum sortable dec be --, which comes before all numbers. + if dec.Equal(LegacyMaxSortableDec.Neg()) { + return []byte("--") + } + // We move the negative sign to the front of all the left padded 0s, to make negative numbers come before positive numbers + if dec.IsNegative() { + return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", LegacyPrecision*2+1), dec.Abs().String()))...) + } + return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", LegacyPrecision*2+1), dec.String())) +} + +// reuse nil values +var nilJSON []byte + +func init() { + empty := new(big.Int) + bz, _ := empty.MarshalText() + nilJSON, _ = json.Marshal(string(bz)) +} + +// MarshalJSON marshals the decimal +func (d LegacyDec) MarshalJSON() ([]byte, error) { + if d.i == nil { + return nilJSON, nil + } + return json.Marshal(d.String()) +} + +// UnmarshalJSON defines custom decoding scheme +func (d *LegacyDec) UnmarshalJSON(bz []byte) error { + if d.i == nil { + d.i = new(big.Int) + } + + var text string + err := json.Unmarshal(bz, &text) + if err != nil { + return err + } + + // TODO: Reuse dec allocation + newDec, err := LegacyNewDecFromStr(text) + if err != nil { + return err + } + + d.i = newDec.i + return nil +} + +// MarshalYAML returns the YAML representation. +func (d LegacyDec) MarshalYAML() (interface{}, error) { + return d.String(), nil +} + +// Marshal implements the gogo proto custom type interface. +func (d LegacyDec) Marshal() ([]byte, error) { + i := d.i + if i == nil { + i = new(big.Int) + } + return i.MarshalText() +} + +// MarshalTo implements the gogo proto custom type interface. +func (d *LegacyDec) MarshalTo(data []byte) (n int, err error) { + i := d.i + if i == nil { + i = new(big.Int) + } + + if i.Sign() == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := d.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil +} + +// Unmarshal implements the gogo proto custom type interface. +func (d *LegacyDec) Unmarshal(data []byte) error { + if len(data) == 0 { + d = nil + return nil + } + + if d.i == nil { + d.i = new(big.Int) + } + + if err := d.i.UnmarshalText(data); err != nil { + return err + } + + if !d.IsInValidRange() { + return errors.New("decimal out of range") + } + return nil +} + +// Size implements the gogo proto custom type interface. +func (d *LegacyDec) Size() int { + bz, _ := d.Marshal() + return len(bz) +} + +// MarshalAmino Override Amino binary serialization by proxying to protobuf. +func (d LegacyDec) MarshalAmino() ([]byte, error) { return d.Marshal() } +func (d *LegacyDec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } + +// helpers + +// LegacyDecsEqual return true if two decimal arrays are equal. +func LegacyDecsEqual(d1s, d2s []LegacyDec) bool { + if len(d1s) != len(d2s) { + return false + } + + for i, d1 := range d1s { + if !d1.Equal(d2s[i]) { + return false + } + } + return true +} + +// LegacyMinDec minimum decimal between two +func LegacyMinDec(d1, d2 LegacyDec) LegacyDec { + if d1.LT(d2) { + return d1 + } + return d2 +} + +// LegacyMaxDec maximum decimal between two +func LegacyMaxDec(d1, d2 LegacyDec) LegacyDec { + if d1.LT(d2) { + return d2 + } + return d1 +} + +// LegacyDecEq intended to be used with require/assert: require.True(DecEq(...)) +func LegacyDecEq(t *testing.T, exp, got LegacyDec) (*testing.T, bool, string, string, string) { + t.Helper() + return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String() +} + +func LegacyDecApproxEq(t *testing.T, d1, d2, tol LegacyDec) (*testing.T, bool, string, string, string) { + t.Helper() + diff := d1.Sub(d2).Abs() + return t, diff.LTE(tol), "expected |d1 - d2| <:\t%v\ngot |d1 - d2| = \t\t%v", tol.String(), diff.String() +} + +// FormatDec formats a decimal (as encoded in protobuf) into a value-rendered +// string following ADR-050. This function operates with string manipulation +// (instead of manipulating the sdk.Dec object). +func FormatDec(v string) (string, error) { + parts := strings.Split(v, ".") + if len(parts) > 2 { + return "", fmt.Errorf("invalid decimal: too many points in %s", v) + } + + intPart, err := FormatInt(parts[0]) + if err != nil { + return "", err + } + + if len(parts) == 1 { + return intPart, nil + } + + decPart := strings.TrimRight(parts[1], "0") + if len(decPart) == 0 { + return intPart, nil + } + + // Ensure that the decimal part has only digits. + // https://github.com/cosmos/cosmos-sdk/issues/12811 + if !hasOnlyDigits(decPart) { + return "", fmt.Errorf("non-digits detected after decimal point in: %q", decPart) + } + + return intPart + "." + decPart, nil +} diff --git a/math/fuzz_test.go b/math/legacy_dec_fuzz_test.go similarity index 100% rename from math/fuzz_test.go rename to math/legacy_dec_fuzz_test.go diff --git a/math/dec_internal_test.go b/math/legacy_dec_internal_test.go similarity index 100% rename from math/dec_internal_test.go rename to math/legacy_dec_internal_test.go diff --git a/math/legacy_dec_test.go b/math/legacy_dec_test.go new file mode 100644 index 000000000000..66a971186cff --- /dev/null +++ b/math/legacy_dec_test.go @@ -0,0 +1,1329 @@ +package math_test + +import ( + "bytes" + "encoding/json" + "fmt" + "math/big" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "sigs.k8s.io/yaml" + + "cosmossdk.io/math" +) + +type decimalTestSuite struct { + suite.Suite +} + +func TestDecimalTestSuite(t *testing.T) { + suite.Run(t, new(decimalTestSuite)) +} + +func TestDecApproxEq(t *testing.T) { + // d1 = 0.55, d2 = 0.6, tol = 0.1 + d1 := math.LegacyNewDecWithPrec(55, 2) + d2 := math.LegacyNewDecWithPrec(6, 1) + tol := math.LegacyNewDecWithPrec(1, 1) + + require.True(math.LegacyDecApproxEq(t, d1, d2, tol)) + + // d1 = 0.55, d2 = 0.6, tol = 1E-5 + d1 = math.LegacyNewDecWithPrec(55, 2) + d2 = math.LegacyNewDecWithPrec(6, 1) + tol = math.LegacyNewDecWithPrec(1, 5) + + require.False(math.LegacyDecApproxEq(t, d1, d2, tol)) + + // d1 = 0.6, d2 = 0.61, tol = 0.01 + d1 = math.LegacyNewDecWithPrec(6, 1) + d2 = math.LegacyNewDecWithPrec(61, 2) + tol = math.LegacyNewDecWithPrec(1, 2) + + require.True(math.LegacyDecApproxEq(t, d1, d2, tol)) +} + +// create a decimal from a decimal string (ex. "1234.5678") +func (s *decimalTestSuite) mustNewDecFromStr(str string) (d math.LegacyDec) { + d, err := math.LegacyNewDecFromStr(str) + s.Require().NoError(err) + + return d +} + +func (s *decimalTestSuite) TestNewDecFromStr() { + largeBigInt, ok := new(big.Int).SetString("3144605511029693144278234343371835", 10) + s.Require().True(ok) + + largerBigInt, ok := new(big.Int).SetString("8888888888888888888888888888888888888888888888888888888888888888888844444440", 10) + s.Require().True(ok) + + largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) + s.Require().True(ok) + + tests := []struct { + decimalStr string + expErr bool + exp math.LegacyDec + }{ + {"", true, math.LegacyDec{}}, + {"0.-75", true, math.LegacyDec{}}, + {"0", false, math.LegacyNewDec(0)}, + {"1", false, math.LegacyNewDec(1)}, + {"1.1", false, math.LegacyNewDecWithPrec(11, 1)}, + {"0.75", false, math.LegacyNewDecWithPrec(75, 2)}, + {"0.8", false, math.LegacyNewDecWithPrec(8, 1)}, + {"0.11111", false, math.LegacyNewDecWithPrec(11111, 5)}, + {"314460551102969.3144278234343371835", true, math.LegacyNewDec(3141203149163817869)}, + { + "314460551102969314427823434337.1835718092488231350", + true, math.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4), + }, + { + "314460551102969314427823434337.1835", + false, math.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4), + }, + {".", true, math.LegacyDec{}}, + {".0", true, math.LegacyNewDec(0)}, + {"1.", true, math.LegacyNewDec(1)}, + {"foobar", true, math.LegacyDec{}}, + {"0.foobar", true, math.LegacyDec{}}, + {"0.foobar.", true, math.LegacyDec{}}, + {"8888888888888888888888888888888888888888888888888888888888888888888844444440", false, math.LegacyNewDecFromBigInt(largerBigInt)}, + {"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535", false, math.LegacyNewDecFromBigIntWithPrec(largestBigInt, 18)}, + {"133499189745056880149688856635597007162669032647290798121690100488888732861291", true, math.LegacyDec{}}, + {"115792089237316195423570985008687907853269984665640564039457584007913129639936", true, math.LegacyDec{}}, // 2^256 + } + + for tcIndex, tc := range tests { + res, err := math.LegacyNewDecFromStr(tc.decimalStr) + if tc.expErr { + s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + } else { + s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + s.Require().True(res.Equal(tc.exp), "equality was incorrect, res %v, expTruncated %v, tc %v", res, tc.exp, tcIndex) + } + + // negative tc + res, err = math.LegacyNewDecFromStr("-" + tc.decimalStr) + if tc.expErr { + s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + } else { + s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + exp := tc.exp.Mul(math.LegacyNewDec(-1)) + s.Require().True(res.Equal(exp), "equality was incorrect, res %v, expTruncated %v, tc %v", res, exp, tcIndex) + } + } +} + +func (s *decimalTestSuite) TestDecString() { + tests := []struct { + d math.LegacyDec + want string + }{ + {math.LegacyNewDec(0), "0.000000000000000000"}, + {math.LegacyNewDec(1), "1.000000000000000000"}, + {math.LegacyNewDec(10), "10.000000000000000000"}, + {math.LegacyNewDec(12340), "12340.000000000000000000"}, + {math.LegacyNewDecWithPrec(12340, 4), "1.234000000000000000"}, + {math.LegacyNewDecWithPrec(12340, 5), "0.123400000000000000"}, + {math.LegacyNewDecWithPrec(12340, 8), "0.000123400000000000"}, + {math.LegacyNewDecWithPrec(1009009009009009009, 17), "10.090090090090090090"}, + } + for tcIndex, tc := range tests { + s.Require().Equal(tc.want, tc.d.String(), "bad String(), index: %v", tcIndex) + } +} + +func (s *decimalTestSuite) TestDecFloat64() { + tests := []struct { + d math.LegacyDec + want float64 + }{ + {math.LegacyNewDec(0), 0.000000000000000000}, + {math.LegacyNewDec(1), 1.000000000000000000}, + {math.LegacyNewDec(10), 10.000000000000000000}, + {math.LegacyNewDec(12340), 12340.000000000000000000}, + {math.LegacyNewDecWithPrec(12340, 4), 1.234000000000000000}, + {math.LegacyNewDecWithPrec(12340, 5), 0.123400000000000000}, + {math.LegacyNewDecWithPrec(12340, 8), 0.000123400000000000}, + {math.LegacyNewDecWithPrec(1009009009009009009, 17), 10.090090090090090090}, + } + for tcIndex, tc := range tests { + value, err := tc.d.Float64() + s.Require().Nil(err, "error getting Float64(), index: %v", tcIndex) + s.Require().Equal(tc.want, value, "bad Float64(), index: %v", tcIndex) + s.Require().Equal(tc.want, tc.d.MustFloat64(), "bad MustFloat64(), index: %v", tcIndex) + } +} + +func (s *decimalTestSuite) TestEqualities() { + tests := []struct { + d1, d2 math.LegacyDec + gt, lt, eq bool + }{ + {math.LegacyNewDec(0), math.LegacyNewDec(0), false, false, true}, + {math.LegacyNewDecWithPrec(0, 2), math.LegacyNewDecWithPrec(0, 4), false, false, true}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(100, 0), false, false, true}, + {math.LegacyNewDecWithPrec(-100, 0), math.LegacyNewDecWithPrec(-100, 0), false, false, true}, + {math.LegacyNewDecWithPrec(-1, 1), math.LegacyNewDecWithPrec(-1, 1), false, false, true}, + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(3333, 3), false, false, true}, + + {math.LegacyNewDecWithPrec(0, 0), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, + {math.LegacyNewDecWithPrec(0, 0), math.LegacyNewDecWithPrec(100, 0), false, true, false}, + {math.LegacyNewDecWithPrec(-1, 0), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, + {math.LegacyNewDecWithPrec(-1, 0), math.LegacyNewDecWithPrec(100, 0), false, true, false}, + {math.LegacyNewDecWithPrec(1111, 3), math.LegacyNewDecWithPrec(100, 0), false, true, false}, + {math.LegacyNewDecWithPrec(1111, 3), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, + {math.LegacyNewDecWithPrec(-3333, 3), math.LegacyNewDecWithPrec(-1111, 3), false, true, false}, + + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(0, 0), true, false, false}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(0, 0), true, false, false}, + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(-1, 0), true, false, false}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(-1, 0), true, false, false}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(1111, 3), true, false, false}, + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(1111, 3), true, false, false}, + {math.LegacyNewDecWithPrec(-1111, 3), math.LegacyNewDecWithPrec(-3333, 3), true, false, false}, + } + + for tcIndex, tc := range tests { + s.Require().Equal(tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc %d", tcIndex) + s.Require().Equal(tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc %d", tcIndex) + s.Require().Equal(tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestDecsEqual() { + tests := []struct { + d1s, d2s []math.LegacyDec + eq bool + }{ + {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(0)}, true}, + {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{}, false}, + {[]math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, []math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, true}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, true}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(2)}, []math.LegacyDec{math.LegacyNewDec(2), math.LegacyNewDec(4)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(3), math.LegacyNewDec(18)}, []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(6)}, false}, + } + + for tcIndex, tc := range tests { + s.Require().Equal(tc.eq, math.LegacyDecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) + s.Require().Equal(tc.eq, math.LegacyDecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestArithmetic() { + tests := []struct { + d1, d2 math.LegacyDec + expMul, expMulTruncate, expMulRoundUp math.LegacyDec + expQuo, expQuoRoundUp, expQuoTruncate math.LegacyDec + expAdd, expSub math.LegacyDec + }{ + // d1 d2 MUL MulTruncate MulRoundUp QUO QUORoundUp QUOTrunctate ADD SUB + {math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0)}, + {math.LegacyNewDec(1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(1)}, + {math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(-1)}, + {math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(1)}, + {math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(-1)}, + + {math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(2), math.LegacyNewDec(0)}, + {math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(-2), math.LegacyNewDec(0)}, + {math.LegacyNewDec(1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(2)}, + {math.LegacyNewDec(-1), math.LegacyNewDec(1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(-2)}, + + { + math.LegacyNewDec(3), math.LegacyNewDec(7), math.LegacyNewDec(21), math.LegacyNewDec(21), math.LegacyNewDec(21), + math.LegacyNewDecWithPrec(428571428571428571, 18), math.LegacyNewDecWithPrec(428571428571428572, 18), math.LegacyNewDecWithPrec(428571428571428571, 18), + math.LegacyNewDec(10), math.LegacyNewDec(-4), + }, + { + math.LegacyNewDec(2), math.LegacyNewDec(4), math.LegacyNewDec(8), math.LegacyNewDec(8), math.LegacyNewDec(8), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), + math.LegacyNewDec(6), math.LegacyNewDec(-2), + }, + + {math.LegacyNewDec(100), math.LegacyNewDec(100), math.LegacyNewDec(10000), math.LegacyNewDec(10000), math.LegacyNewDec(10000), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(200), math.LegacyNewDec(0)}, + + { + math.LegacyNewDecWithPrec(15, 1), math.LegacyNewDecWithPrec(15, 1), math.LegacyNewDecWithPrec(225, 2), math.LegacyNewDecWithPrec(225, 2), math.LegacyNewDecWithPrec(225, 2), + math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(3), math.LegacyNewDec(0), + }, + { + math.LegacyNewDecWithPrec(3333, 4), math.LegacyNewDecWithPrec(333, 4), math.LegacyNewDecWithPrec(1109889, 8), math.LegacyNewDecWithPrec(1109889, 8), math.LegacyNewDecWithPrec(1109889, 8), + math.LegacyMustNewDecFromStr("10.009009009009009009"), math.LegacyMustNewDecFromStr("10.009009009009009010"), math.LegacyMustNewDecFromStr("10.009009009009009009"), + math.LegacyNewDecWithPrec(3666, 4), math.LegacyNewDecWithPrec(3, 1), + }, + } + + for tcIndex, tc := range tests { + + resAdd := tc.d1.Add(tc.d2) + resSub := tc.d1.Sub(tc.d2) + resMul := tc.d1.Mul(tc.d2) + resMulTruncate := tc.d1.MulTruncate(tc.d2) + resMulRoundUp := tc.d1.MulRoundUp(tc.d2) + s.Require().True(tc.expAdd.Equal(resAdd), "expTruncated %v, res %v, tc %d", tc.expAdd, resAdd, tcIndex) + s.Require().True(tc.expSub.Equal(resSub), "expTruncated %v, res %v, tc %d", tc.expSub, resSub, tcIndex) + s.Require().True(tc.expMul.Equal(resMul), "expTruncated %v, res %v, tc %d", tc.expMul, resMul, tcIndex) + s.Require().True(tc.expMulTruncate.Equal(resMulTruncate), "expTruncated %v, res %v, tc %d", tc.expMulTruncate, resMulTruncate, tcIndex) + s.Require().True(tc.expMulRoundUp.Equal(resMulRoundUp), "expTruncated %v, res %v, tc %d", tc.expMulRoundUp, resMulRoundUp, tcIndex) + + if tc.d2.IsZero() { // panic for divide by zero + s.Require().Panics(func() { tc.d1.Quo(tc.d2) }) + } else { + resQuo := tc.d1.Quo(tc.d2) + s.Require().True(tc.expQuo.Equal(resQuo), "expTruncated %v, res %v, tc %d", tc.expQuo.String(), resQuo.String(), tcIndex) + + resQuoRoundUp := tc.d1.QuoRoundUp(tc.d2) + s.Require().True(tc.expQuoRoundUp.Equal(resQuoRoundUp), "expTruncated %v, res %v, tc %d", + tc.expQuoRoundUp.String(), resQuoRoundUp.String(), tcIndex) + + resQuoTruncate := tc.d1.QuoTruncate(tc.d2) + s.Require().True(tc.expQuoTruncate.Equal(resQuoTruncate), "expTruncated %v, res %v, tc %d", + tc.expQuoTruncate.String(), resQuoTruncate.String(), tcIndex) + } + } +} + +func (s *decimalTestSuite) TestMulRoundUp_RoundingAtPrecisionEnd() { + var ( + a = math.LegacyMustNewDecFromStr("0.000000000000000009") + b = math.LegacyMustNewDecFromStr("0.000000000000000009") + expectedRoundUp = math.LegacyMustNewDecFromStr("0.000000000000000001") + expectedTruncate = math.LegacyMustNewDecFromStr("0.000000000000000000") + ) + + actualRoundUp := a.MulRoundUp(b) + s.Require().Equal(expectedRoundUp.String(), actualRoundUp.String(), "expTruncated %v, res %v", expectedRoundUp, actualRoundUp) + + actualTruncate := a.MulTruncate(b) + s.Require().Equal(expectedTruncate.String(), actualTruncate.String(), "expTruncated %v, res %v", expectedRoundUp, actualTruncate) +} + +func (s *decimalTestSuite) TestBankerRoundChop() { + tests := []struct { + d1 math.LegacyDec + exp int64 + }{ + {s.mustNewDecFromStr("0.25"), 0}, + {s.mustNewDecFromStr("0"), 0}, + {s.mustNewDecFromStr("1"), 1}, + {s.mustNewDecFromStr("0.75"), 1}, + {s.mustNewDecFromStr("0.5"), 0}, + {s.mustNewDecFromStr("7.5"), 8}, + {s.mustNewDecFromStr("1.5"), 2}, + {s.mustNewDecFromStr("2.5"), 2}, + {s.mustNewDecFromStr("0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even + {s.mustNewDecFromStr("1.545"), 2}, + } + + for tcIndex, tc := range tests { + resNeg := tc.d1.Neg().RoundInt64() + s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) + + resPos := tc.d1.RoundInt64() + s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestTruncate() { + tests := []struct { + d1 math.LegacyDec + exp int64 + }{ + {s.mustNewDecFromStr("0"), 0}, + {s.mustNewDecFromStr("0.25"), 0}, + {s.mustNewDecFromStr("0.75"), 0}, + {s.mustNewDecFromStr("1"), 1}, + {s.mustNewDecFromStr("1.5"), 1}, + {s.mustNewDecFromStr("7.5"), 7}, + {s.mustNewDecFromStr("7.6"), 7}, + {s.mustNewDecFromStr("7.4"), 7}, + {s.mustNewDecFromStr("100.1"), 100}, + {s.mustNewDecFromStr("1000.1"), 1000}, + } + + for tcIndex, tc := range tests { + resNeg := tc.d1.Neg().TruncateInt64() + s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) + + resPos := tc.d1.TruncateInt64() + s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestStringOverflow() { + // two random 64 bit primes + dec1, err := math.LegacyNewDecFromStr("51643150036226787134389711697696177267") + s.Require().NoError(err) + dec2, err := math.LegacyNewDecFromStr("-31798496660535729618459429845579852627") + s.Require().NoError(err) + dec3 := dec1.Add(dec2) + s.Require().Equal( + "19844653375691057515930281852116324640.000000000000000000", + dec3.String(), + ) +} + +func (s *decimalTestSuite) TestDecMulInt() { + tests := []struct { + sdkDec math.LegacyDec + sdkInt math.Int + want math.LegacyDec + }{ + {math.LegacyNewDec(10), math.NewInt(2), math.LegacyNewDec(20)}, + {math.LegacyNewDec(1000000), math.NewInt(100), math.LegacyNewDec(100000000)}, + {math.LegacyNewDecWithPrec(1, 1), math.NewInt(10), math.LegacyNewDec(1)}, + {math.LegacyNewDecWithPrec(1, 5), math.NewInt(20), math.LegacyNewDecWithPrec(2, 4)}, + } + for i, tc := range tests { + got := tc.sdkDec.MulInt(tc.sdkInt) + s.Require().Equal(tc.want, got, "Incorrect result on test case %d", i) + } +} + +func (s *decimalTestSuite) TestDecCeil() { + testCases := []struct { + input math.LegacyDec + expected math.LegacyDec + }{ + {math.LegacyNewDecWithPrec(1000000000000000, math.LegacyPrecision), math.LegacyNewDec(1)}, // 0.001 => 1.0 + {math.LegacyNewDecWithPrec(-1000000000000000, math.LegacyPrecision), math.LegacyZeroDec()}, // -0.001 => 0.0 + {math.LegacyZeroDec(), math.LegacyZeroDec()}, // 0.0 => 0.0 + {math.LegacyNewDecWithPrec(900000000000000000, math.LegacyPrecision), math.LegacyNewDec(1)}, // 0.9 => 1.0 + {math.LegacyNewDecWithPrec(4001000000000000000, math.LegacyPrecision), math.LegacyNewDec(5)}, // 4.001 => 5.0 + {math.LegacyNewDecWithPrec(-4001000000000000000, math.LegacyPrecision), math.LegacyNewDec(-4)}, // -4.001 => -4.0 + {math.LegacyNewDecWithPrec(4700000000000000000, math.LegacyPrecision), math.LegacyNewDec(5)}, // 4.7 => 5.0 + {math.LegacyNewDecWithPrec(-4700000000000000000, math.LegacyPrecision), math.LegacyNewDec(-4)}, // -4.7 => -4.0 + } + + for i, tc := range testCases { + res := tc.input.Ceil() + s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestCeilOverflow() { + // (2^256 * 10^18 -1) / 10^18 + d, err := math.LegacyNewDecFromStr("115792089237316195423570985008687907853269984665640564039457584007913129639935.999999999999999999") + s.Require().NoError(err) + s.Require().True(d.IsInValidRange()) + // this call panics because the value is too large + s.Require().Panics(func() { d.Ceil() }, "Ceil should panic on overflow") +} + +func (s *decimalTestSuite) TestPower() { + testCases := []struct { + input math.LegacyDec + power uint64 + expected math.LegacyDec + }{ + {math.LegacyNewDec(100), 0, math.LegacyOneDec()}, // 10 ^ (0) => 1.0 + {math.LegacyOneDec(), 10, math.LegacyOneDec()}, // 1.0 ^ (10) => 1.0 + {math.LegacyNewDecWithPrec(5, 1), 2, math.LegacyNewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 + {math.LegacyNewDecWithPrec(2, 1), 2, math.LegacyNewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 + {math.LegacyNewDecFromInt(math.NewInt(3)), 3, math.LegacyNewDecFromInt(math.NewInt(27))}, // 3 ^ 3 => 27 + {math.LegacyNewDecFromInt(math.NewInt(-3)), 4, math.LegacyNewDecFromInt(math.NewInt(81))}, // -3 ^ 4 = 81 + {math.LegacyNewDecWithPrec(1414213562373095049, 18), 2, math.LegacyNewDecFromInt(math.NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 + } + + for i, tc := range testCases { + res := tc.input.Power(tc.power) + s.Require().True(tc.expected.Sub(res).Abs().LTE(math.LegacySmallestDec()), "unexpected result for test case %d, normal power, input: %v", i, tc.input) + + mutableInput := tc.input + mutableInput.PowerMut(tc.power) + s.Require().True(tc.expected.Sub(mutableInput).Abs().LTE(math.LegacySmallestDec()), + "unexpected result for test case %d, input %v", i, tc.input) + s.Require().True(res.Equal(tc.input), "unexpected result for test case %d, mutable power, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestApproxRoot() { + testCases := []struct { + input math.LegacyDec + root uint64 + expected math.LegacyDec + }{ + {math.LegacyNewDecFromInt(math.NewInt(2)), 0, math.LegacyOneDec()}, // 2 ^ 0 => 1.0 + {math.LegacyNewDecWithPrec(4, 2), 0, math.LegacyOneDec()}, // 0.04 ^ 0 => 1.0 + {math.LegacyNewDec(0), 1, math.LegacyNewDec(0)}, // 0 ^ 1 => 0 + {math.LegacyOneDec(), 10, math.LegacyOneDec()}, // 1.0 ^ (0.1) => 1.0 + {math.LegacyNewDecWithPrec(25, 2), 2, math.LegacyNewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 + {math.LegacyNewDecWithPrec(4, 2), 2, math.LegacyNewDecWithPrec(2, 1)}, // 0.04 ^ (0.5) => 0.2 + {math.LegacyNewDecFromInt(math.NewInt(27)), 3, math.LegacyNewDecFromInt(math.NewInt(3))}, // 27 ^ (1/3) => 3 + {math.LegacyNewDecFromInt(math.NewInt(-81)), 4, math.LegacyNewDecFromInt(math.NewInt(-3))}, // -81 ^ (0.25) => -3 + {math.LegacyNewDecFromInt(math.NewInt(2)), 2, math.LegacyNewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 + {math.LegacyNewDecWithPrec(1005, 3), 31536000, math.LegacyMustNewDecFromStr("1.000000000158153904")}, // 1.005 ^ (1/31536000) ≈ 1.00000000016 + {math.LegacySmallestDec(), 2, math.LegacyNewDecWithPrec(1, 9)}, // 1e-18 ^ (0.5) => 1e-9 + {math.LegacySmallestDec(), 3, math.LegacyMustNewDecFromStr("0.000000999999999997")}, // 1e-18 ^ (1/3) => 1e-6 + {math.LegacyNewDecWithPrec(1, 8), 3, math.LegacyMustNewDecFromStr("0.002154434690031900")}, // 1e-8 ^ (1/3) ≈ 0.00215443469 + {math.LegacyMustNewDecFromStr("9000002314687921634000000000000000000021394871242000000000000000"), 2, math.LegacyMustNewDecFromStr("94868342004527103646332858502867.899477053226766107")}, + } + + // In the case of 1e-8 ^ (1/3), the result repeats every 5 iterations starting from iteration 24 + // (i.e. 24, 29, 34, ... give the same result) and never converges enough. The maximum number of + // iterations (300) causes the result at iteration 300 to be returned, regardless of convergence. + + for i, tc := range testCases { + res, err := tc.input.ApproxRoot(tc.root) + s.Require().NoError(err) + s.Require().True(tc.expected.Sub(res).Abs().LTE(math.LegacySmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestApproxSqrt() { + testCases := []struct { + input math.LegacyDec + expected math.LegacyDec + }{ + {math.LegacyOneDec(), math.LegacyOneDec()}, // 1.0 => 1.0 + {math.LegacyNewDecWithPrec(25, 2), math.LegacyNewDecWithPrec(5, 1)}, // 0.25 => 0.5 + {math.LegacyNewDecWithPrec(4, 2), math.LegacyNewDecWithPrec(2, 1)}, // 0.09 => 0.3 + {math.LegacyNewDec(9), math.LegacyNewDecFromInt(math.NewInt(3))}, // 9 => 3 + {math.LegacyNewDec(-9), math.LegacyNewDecFromInt(math.NewInt(-3))}, // -9 => -3 + {math.LegacyNewDec(2), math.LegacyNewDecWithPrec(1414213562373095049, 18)}, // 2 => 1.414213562373095049 + { // 2^127 - 1 => 13043817825332782212.3495718062525083688 which rounds to 13043817825332782212.3495718062525083689 + math.LegacyNewDec(2).Power(127).Sub(math.LegacyOneDec()), + math.LegacyMustNewDecFromStr("13043817825332782212.349571806252508369"), + }, + {math.LegacyMustNewDecFromStr("1.000000011823380862"), math.LegacyMustNewDecFromStr("1.000000005911690414")}, + } + + for i, tc := range testCases { + res, err := tc.input.ApproxSqrt() + s.Require().NoError(err) + s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestDecSortableBytes() { + tests := []struct { + d math.LegacyDec + want []byte + }{ + {math.LegacyNewDec(0), []byte("000000000000000000.000000000000000000")}, + {math.LegacyNewDec(1), []byte("000000000000000001.000000000000000000")}, + {math.LegacyNewDec(10), []byte("000000000000000010.000000000000000000")}, + {math.LegacyNewDec(12340), []byte("000000000000012340.000000000000000000")}, + {math.LegacyNewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")}, + {math.LegacyNewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")}, + {math.LegacyNewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")}, + {math.LegacyNewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")}, + {math.LegacyNewDecWithPrec(-1009009009009009009, 17), []byte("-000000000000000010.090090090090090090")}, + {math.LegacyNewDec(1000000000000000000), []byte("max")}, + {math.LegacyNewDec(-1000000000000000000), []byte("--")}, + } + for tcIndex, tc := range tests { + s.Require().Equal(tc.want, math.LegacySortableDecBytes(tc.d), "bad String(), index: %v", tcIndex) + } + + s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(1000000000000000001)) }) + s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(-1000000000000000001)) }) +} + +func (s *decimalTestSuite) TestDecEncoding() { + largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) + s.Require().True(ok) + + smallestBigInt, ok := new(big.Int).SetString("-33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) + s.Require().True(ok) + + const maxDecBitLen = 315 + maxInt, ok := new(big.Int).SetString(strings.Repeat("1", maxDecBitLen), 2) + s.Require().True(ok) + + testCases := []struct { + input math.LegacyDec + rawBz string + jsonStr string + yamlStr string + }{ + { + math.LegacyNewDec(0), "30", + "\"0.000000000000000000\"", + "\"0.000000000000000000\"\n", + }, + { + math.LegacyNewDecWithPrec(4, 2), + "3430303030303030303030303030303030", + "\"0.040000000000000000\"", + "\"0.040000000000000000\"\n", + }, + { + math.LegacyNewDecWithPrec(-4, 2), + "2D3430303030303030303030303030303030", + "\"-0.040000000000000000\"", + "\"-0.040000000000000000\"\n", + }, + { + math.LegacyNewDecWithPrec(1414213562373095049, 18), + "31343134323133353632333733303935303439", + "\"1.414213562373095049\"", + "\"1.414213562373095049\"\n", + }, + { + math.LegacyNewDecWithPrec(-1414213562373095049, 18), + "2D31343134323133353632333733303935303439", + "\"-1.414213562373095049\"", + "\"-1.414213562373095049\"\n", + }, + { + math.LegacyNewDecFromBigIntWithPrec(largestBigInt, 18), + "3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", + "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", + "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", + }, + { + math.LegacyNewDecFromBigIntWithPrec(smallestBigInt, 18), + "2D3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", + "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", + "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", + }, + { + math.LegacyNewDecFromBigIntWithPrec(maxInt, 18), + "3636373439353934383732353238343430303734383434343238333137373938353033353831333334353136333233363435333939303630383435303530323434343434333636343330363435303137313838323137353635323136373637", + "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"", + "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"\n", + }, + } + + for _, tc := range testCases { + bz, err := tc.input.Marshal() + s.Require().NoError(err) + s.Require().Equal(tc.rawBz, fmt.Sprintf("%X", bz)) + + var other math.LegacyDec + s.Require().NoError((&other).Unmarshal(bz)) + s.Require().True(tc.input.Equal(other)) + + bz, err = json.Marshal(tc.input) + s.Require().NoError(err) + s.Require().Equal(tc.jsonStr, string(bz)) + s.Require().NoError(json.Unmarshal(bz, &other)) + s.Require().True(tc.input.Equal(other)) + + bz, err = yaml.Marshal(tc.input) + s.Require().NoError(err) + s.Require().Equal(tc.yamlStr, string(bz)) + } +} + +// Showcase that different orders of operations causes different results. +func (s *decimalTestSuite) TestOperationOrders() { + n1 := math.LegacyNewDec(10) + n2 := math.LegacyNewDec(1000000010) + s.Require().Equal(n1.Mul(n2).Quo(n2), math.LegacyNewDec(10)) + s.Require().NotEqual(n1.Mul(n2).Quo(n2), n1.Quo(n2).Mul(n2)) +} + +func BenchmarkMarshalTo(b *testing.B) { + b.ReportAllocs() + bis := []struct { + in math.LegacyDec + want []byte + }{ + { + math.LegacyNewDec(1e8), []byte{ + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + }, + }, + {math.LegacyNewDec(0), []byte{0x30}}, + } + data := make([]byte, 100) + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, bi := range bis { + if n, err := bi.in.MarshalTo(data); err != nil { + b.Fatal(err) + } else if !bytes.Equal(data[:n], bi.want) { + b.Fatalf("Mismatch\nGot: % x\nWant: % x\n", data[:n], bi.want) + } + } + } +} + +var sink interface{} + +func BenchmarkLegacyQuoMut(b *testing.B) { + b1 := math.LegacyNewDec(17e2 + 8371) + b2 := math.LegacyNewDec(4371) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + sink = b1.QuoMut(b2) + } + + if sink == nil { + b.Fatal("Benchmark did not run") + } + sink = (interface{})(nil) +} + +func BenchmarkLegacyQuoTruncateMut(b *testing.B) { + b1 := math.LegacyNewDec(17e2 + 8371) + baseArr := make([]math.LegacyDec, b.N) + for i := 0; i < b.N; i++ { + baseArr[i] = b1.Clone() + } + b2 := math.LegacyNewDec(4371) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + sink = baseArr[i].QuoTruncateMut(b2) + } + + if sink == nil { + b.Fatal("Benchmark did not run") + } + sink = (interface{})(nil) +} + +func BenchmarkLegacySqrtOnMersennePrime(b *testing.B) { + b1 := math.LegacyNewDec(2).Power(127).Sub(math.LegacyOneDec()) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + sink, _ = b1.ApproxSqrt() + } + + if sink == nil { + b.Fatal("Benchmark did not run") + } + sink = (interface{})(nil) +} + +func BenchmarkLegacyQuoRoundupMut(b *testing.B) { + b1 := math.LegacyNewDec(17e2 + 8371) + baseArr := make([]math.LegacyDec, b.N) + for i := 0; i < b.N; i++ { + baseArr[i] = b1.Clone() + } + b2 := math.LegacyNewDec(4371) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + sink = baseArr[i].QuoRoundupMut(b2) + } + + if sink == nil { + b.Fatal("Benchmark did not run") + } + sink = (interface{})(nil) +} + +func TestFormatDec(t *testing.T) { + type decimalTest []string + var testcases []decimalTest + raw, err := os.ReadFile("./testdata/decimals.json") + require.NoError(t, err) + err = json.Unmarshal(raw, &testcases) + require.NoError(t, err) + + for _, tc := range testcases { + t.Run(tc[0], func(t *testing.T) { + out, err := math.FormatDec(tc[0]) + require.NoError(t, err) + require.Equal(t, tc[1], out) + }) + } +} + +func TestFormatDecNonDigits(t *testing.T) { + badCases := []string{ + "10.a", + "1a.10", + "p1a10.", + "0.10p", + "--10", + "12.😎😎", + "11111111111133333333333333333333333333333a", + "11111111111133333333333333333333333333333 192892", + } + + for _, value := range badCases { + value := value + t.Run(value, func(t *testing.T) { + s, err := math.FormatDec(value) + if err == nil { + t.Fatal("Expected an error") + } + if g, w := err.Error(), "non-digits"; !strings.Contains(g, w) { + t.Errorf("Error mismatch\nGot: %q\nWant substring: %q", g, w) + } + if s != "" { + t.Fatalf("Got a non-empty string: %q", s) + } + }) + } +} + +func TestNegativePrecisionPanic(t *testing.T) { + require.Panics(t, func() { + math.LegacyNewDecWithPrec(10, -1) + }) +} + +func (s *decimalTestSuite) TestConvertToBigIntMutativeForLegacyDec() { + r := big.NewInt(30) + i := math.LegacyNewDecFromBigInt(r) + + // Compare value of BigInt & BigIntMut + s.Require().Equal(i.BigInt(), i.BigIntMut()) + + // Modify BigIntMut() pointer and ensure i.BigIntMut() & i.BigInt() change + p1 := i.BigIntMut() + p1.SetInt64(40) + s.Require().Equal(big.NewInt(40), i.BigIntMut()) + s.Require().Equal(big.NewInt(40), i.BigInt()) + + // Modify big.Int() pointer and ensure i.BigIntMut() & i.BigInt() don't change + p2 := i.BigInt() + p2.SetInt64(50) + s.Require().NotEqual(big.NewInt(50), i.BigIntMut()) + s.Require().NotEqual(big.NewInt(50), i.BigInt()) +} + +func TestQuoMut(t *testing.T) { + specs := map[string]struct { + dividend, divisor math.LegacyDec + expTruncated, expRoundedUp string + expPanic bool + }{ + "0.0000000000000000001": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("10"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000002": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("5"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000003": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("3.333333333333333"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000004": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("2.5"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000005": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("2"), + expRoundedUp: "0.000000000000000001", + + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000006": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("1.666666666666666666"), + expRoundedUp: "0.000000000000000001", + + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000007": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("1.428571428571429"), + expRoundedUp: "0.000000000000000001", + + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000008": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("1.25"), + expRoundedUp: "0.000000000000000001", + + expTruncated: "0.000000000000000000", + }, + "0.0000000000000000009": { + dividend: math.LegacyNewDecWithPrec(1, 18), + divisor: math.LegacyMustNewDecFromStr("1.111111111111111"), + expRoundedUp: "0.000000000000000001", + + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000001": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("10"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000002": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("5"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000003": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("3.333333333333333"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000004": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("2.5"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000005": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("2"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000006": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("1.666666666666666666"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000007": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("1.428571428571429"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000008": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("1.25"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "-0.0000000000000000009": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("1.111111111111111"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000001": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-10"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000002": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-5"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000003": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-3.333333333333333"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000004": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-2.5"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000005": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-2"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000006": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-1.666666666666666666"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000007": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-1.428571428571429"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000008": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-1.25"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "--0.0000000000000000009": { + dividend: math.LegacyNewDecWithPrec(1, 18).Neg(), + divisor: math.LegacyMustNewDecFromStr("-1.111111111111111"), + expRoundedUp: "0.000000000000000001", + expTruncated: "0.000000000000000000", + }, + "big / small": { + dividend: math.LegacyMustNewDecFromStr("999999999999999999"), + divisor: math.LegacyNewDecWithPrec(1, 18), + expRoundedUp: "999999999999999999000000000000000000.000000000000000000", + expTruncated: "999999999999999999000000000000000000.000000000000000000", + }, + "divide by dividend": { + dividend: math.LegacyNewDecWithPrec(123, 0), + divisor: math.LegacyMustNewDecFromStr("123"), + expRoundedUp: "1.000000000000000000", + expTruncated: "1.000000000000000000", + }, + "zero divided": { + dividend: math.LegacyNewDecWithPrec(0, 0), + divisor: math.LegacyMustNewDecFromStr("1"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "zero divided by negative value": { + dividend: math.LegacyNewDecWithPrec(0, 0), + divisor: math.LegacyMustNewDecFromStr("-1"), + expRoundedUp: "0.000000000000000000", + expTruncated: "0.000000000000000000", + }, + "zero divided by zero": { + dividend: math.LegacyNewDecWithPrec(0, 0), + divisor: math.LegacyMustNewDecFromStr("0"), + expPanic: true, + }, + "divide by zero": { + dividend: math.LegacyNewDecWithPrec(1, 0), + divisor: math.LegacyMustNewDecFromStr("0"), + expPanic: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + t.Run("round up", func(t *testing.T) { + t.Parallel() + if !spec.expPanic { + got := spec.dividend.Clone().QuoRoundupMut(spec.divisor.Clone()) + require.Equal(t, spec.expRoundedUp, got.String()) + return + } + require.Panics(t, func() { + _ = spec.dividend.Clone().QuoRoundupMut(spec.divisor.Clone()) + }) + }) + t.Run("truncate", func(t *testing.T) { + t.Parallel() + if !spec.expPanic { + got := spec.dividend.Clone().QuoTruncateMut(spec.divisor.Clone()) + require.Equal(t, spec.expTruncated, got.String()) + return + } + require.Panics(t, func() { + _ = spec.dividend.Clone().QuoTruncateMut(spec.divisor.Clone()) + }) + }) + }) + } +} + +func Test_DocumentLegacyAsymmetry(t *testing.T) { + zeroDec := math.LegacyZeroDec() + emptyDec := math.LegacyDec{} + + zeroDecBz, err := zeroDec.Marshal() + require.NoError(t, err) + zeroDecJSON, err := zeroDec.MarshalJSON() + require.NoError(t, err) + + emptyDecBz, err := emptyDec.Marshal() + require.NoError(t, err) + emptyDecJSON, err := emptyDec.MarshalJSON() + require.NoError(t, err) + + // makes sense, zero and empty are semantically different and render differently + require.NotEqual(t, zeroDecJSON, emptyDecJSON) + // but on the proto wire they encode to the same bytes + require.Equal(t, zeroDecBz, emptyDecBz) + + // zero values are symmetrical + zeroDecRoundTrip := math.LegacyDec{} + err = zeroDecRoundTrip.Unmarshal(zeroDecBz) + require.NoError(t, err) + zeroDecRoundTripJSON, err := zeroDecRoundTrip.MarshalJSON() + require.NoError(t, err) + require.Equal(t, zeroDecJSON, zeroDecRoundTripJSON) + require.Equal(t, zeroDec, zeroDecRoundTrip) + + // empty values are not + emptyDecRoundTrip := math.LegacyDec{} + err = emptyDecRoundTrip.Unmarshal(emptyDecBz) + require.NoError(t, err) + emptyDecRoundTripJSON, err := emptyDecRoundTrip.MarshalJSON() + require.NoError(t, err) + + // !!! this is the key point, they are not equal, it looks like a bug + require.NotEqual(t, emptyDecJSON, emptyDecRoundTripJSON) + require.NotEqual(t, emptyDec, emptyDecRoundTrip) +} + +// 2^256 * 10^18 -1 +const maxValidDecNumber = "115792089237316195423570985008687907853269984665640564039457584007913129639935999999999999999999" + +func TestDecOpsWithinLimits(t *testing.T) { + maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) + require.True(t, ok) + minValid := new(big.Int).Neg(maxValid) + specs := map[string]struct { + src *big.Int + expErr bool + }{ + "max": { + src: maxValid, + }, + "max + 1": { + src: new(big.Int).Add(maxValid, big.NewInt(1)), + expErr: true, + }, + "min": { + src: minValid, + }, + "min - 1": { + src: new(big.Int).Sub(minValid, big.NewInt(1)), + expErr: true, + }, + "max Int": { + // max Int is 2^256 -1 + src: math.NewIntFromBigInt(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))).BigIntMut(), + }, + "min Int": { + // max Int is -1 *(2^256 -1) + src: math.NewIntFromBigInt(new(big.Int).Neg(new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1)))).BigIntMut(), + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) + + ops := map[string]struct { + fn func(src math.LegacyDec) math.LegacyDec + }{ + "AddMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.AddMut(math.LegacyNewDec(0)) }, + }, + "SubMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.SubMut(math.LegacyNewDec(0)) }, + }, + "MulMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.MulMut(math.LegacyNewDec(1)) }, + }, + "MulTruncateMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.MulTruncateMut(math.LegacyNewDec(1)) }, + }, + "MulRoundUpMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.MulRoundUpMut(math.LegacyNewDec(1)) }, + }, + "MulIntMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.MulIntMut(math.NewInt(1)) }, + }, + "MulInt64Mut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.MulInt64Mut(1) }, + }, + "QuoMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.QuoMut(math.LegacyNewDec(1)) }, + }, + "QuoTruncateMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.QuoTruncateMut(math.LegacyNewDec(1)) }, + }, + "QuoRoundupMut": { + fn: func(src math.LegacyDec) math.LegacyDec { return src.QuoRoundupMut(math.LegacyNewDec(1)) }, + }, + } + for name, op := range ops { + t.Run(name, func(t *testing.T) { + if spec.expErr { + assert.Panics(t, func() { + got := op.fn(src) + t.Log(got.String()) + }) + return + } + exp := src.String() + // exp no panics + got := op.fn(src) + assert.Equal(t, exp, got.String()) + }) + } + }) + } +} + +func TestDecCeilLimits(t *testing.T) { + maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) + require.True(t, ok) + minValid := new(big.Int).Neg(maxValid) + + specs := map[string]struct { + src *big.Int + exp string + expErr bool + }{ + "max": { + src: maxValid, + expErr: true, + }, + "max + 1": { + src: new(big.Int).Add(maxValid, big.NewInt(1)), + expErr: true, + }, + "max - 1e18, previous full number": { + src: new(big.Int).Sub(maxValid, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)), + exp: "115792089237316195423570985008687907853269984665640564039457584007913129639935.000000000000000000", + }, + "min": { + src: minValid, + exp: "-115792089237316195423570985008687907853269984665640564039457584007913129639935.000000000000000000", + }, + "min - 1": { + src: new(big.Int).Sub(minValid, big.NewInt(1)), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) + if spec.expErr { + assert.Panics(t, func() { + got := src.Ceil() + t.Log(got.String()) + }) + return + } + got := src.Ceil() + assert.Equal(t, spec.exp, got.String()) + }) + } +} + +func TestTruncateIntLimits(t *testing.T) { + maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) + require.True(t, ok) + minValid := new(big.Int).Neg(maxValid) + + specs := map[string]struct { + src *big.Int + exp string + expErr bool + }{ + "max": { + src: maxValid, + exp: "115792089237316195423570985008687907853269984665640564039457584007913129639935", + }, + "max + 1": { + src: new(big.Int).Add(maxValid, big.NewInt(1)), + expErr: true, + }, + "min": { + src: minValid, + exp: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", + }, + "min - 1": { + src: new(big.Int).Sub(minValid, big.NewInt(1)), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) + if spec.expErr { + assert.Panics(t, func() { + got := src.TruncateInt() + t.Log(got.String()) + }) + return + } + got := src.TruncateInt() + assert.Equal(t, spec.exp, got.String()) + }) + } +} + +func TestRoundIntLimits(t *testing.T) { + maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) + require.True(t, ok) + minValid := new(big.Int).Neg(maxValid) + oneE18 := new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil) + + specs := map[string]struct { + src *big.Int + exp string + expErr bool + }{ + "max -1e18; previous full number": { + src: new(big.Int).Sub(maxValid, oneE18), + exp: "115792089237316195423570985008687907853269984665640564039457584007913129639935", + }, + "max": { + src: maxValid, + expErr: true, + }, + "max + 1": { + src: new(big.Int).Add(maxValid, big.NewInt(1)), + expErr: true, + }, + "min + 1e18; previous full number": { + src: new(big.Int).Add(minValid, oneE18), + exp: "-115792089237316195423570985008687907853269984665640564039457584007913129639935", + }, + "min": { + src: minValid, + expErr: true, + }, + "min - 1": { + src: new(big.Int).Sub(minValid, big.NewInt(1)), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + src := math.LegacyNewDecFromBigIntWithPrec(spec.src, 18) + t.Log(src.String()) + if spec.expErr { + assert.Panics(t, func() { + got := src.RoundInt() + t.Log(got.String()) + }) + return + } + got := src.RoundInt() + assert.Equal(t, spec.exp, got.String()) + }) + } +} + +func BenchmarkIsInValidRange(b *testing.B) { + maxValid, ok := new(big.Int).SetString(maxValidDecNumber, 10) + require.True(b, ok) + souceMax := math.LegacyNewDecFromBigIntWithPrec(maxValid, 18) + b.ResetTimer() + specs := map[string]math.LegacyDec{ + "max": souceMax, + "greater max": math.LegacyNewDecFromBigIntWithPrec(maxValid, 16), + "min": souceMax.Neg(), + "lower min": math.LegacyNewDecFromBigIntWithPrec(new(big.Int).Neg(maxValid), 16), + "zero": math.LegacyZeroDec(), + "one": math.LegacyOneDec(), + } + for name, source := range specs { + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = source.IsInValidRange() + } + }) + } +} diff --git a/math/uint_test.go b/math/uint_test.go index b02b442159b3..62a081d5151e 100644 --- a/math/uint_test.go +++ b/math/uint_test.go @@ -343,7 +343,6 @@ func TestRoundTripMarshalToUint(t *testing.T) { } for _, value := range values { - value := value t.Run(fmt.Sprintf("%d", value), func(t *testing.T) { t.Parallel() diff --git a/simapp/go.mod b/simapp/go.mod index 857f0cb1479c..168a4d3c2ef6 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -82,7 +82,7 @@ require ( github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect - github.com/cockroachdb/apd/v2 v2.0.2 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect diff --git a/simapp/go.sum b/simapp/go.sum index 600402370cd7..bd47ea8946ee 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -297,8 +297,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= -github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index 6ae03105dea0..f5aa09085ae0 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -85,7 +85,7 @@ require ( github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect - github.com/cockroachdb/apd/v2 v2.0.2 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index f742c0ec40e5..49355a5beb9b 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -296,8 +296,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= -github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= diff --git a/tests/go.mod b/tests/go.mod index c3405c108d0d..782f836d0794 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -95,7 +95,7 @@ require ( github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect - github.com/cockroachdb/apd/v2 v2.0.2 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect diff --git a/tests/go.sum b/tests/go.sum index 526000e4f603..cd55ba56ebf5 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -295,8 +295,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= -github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= diff --git a/x/group/go.mod b/x/group/go.mod index e4c04a1177f9..d0b4226678e5 100644 --- a/x/group/go.mod +++ b/x/group/go.mod @@ -18,7 +18,7 @@ require ( cosmossdk.io/x/gov v0.0.0-20230925135524-a1bc045b3190 cosmossdk.io/x/mint v0.0.0-00010101000000-000000000000 cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 - github.com/cockroachdb/apd/v2 v2.0.2 + github.com/cockroachdb/apd/v3 v3.2.1 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.53.0 github.com/cosmos/gogoproto v1.7.0 diff --git a/x/group/go.sum b/x/group/go.sum index 4a7a1a72b426..57f9e63c4f6e 100644 --- a/x/group/go.sum +++ b/x/group/go.sum @@ -94,8 +94,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= -github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= diff --git a/x/group/internal/math/dec.go b/x/group/internal/math/dec.go index 973aa7024a40..47f3ba18ab44 100644 --- a/x/group/internal/math/dec.go +++ b/x/group/internal/math/dec.go @@ -2,12 +2,12 @@ package math import ( - "errors" + "fmt" - "github.com/cockroachdb/apd/v2" + "github.com/cockroachdb/apd/v3" errorsmod "cosmossdk.io/errors" - grouperrors "cosmossdk.io/x/group/errors" + "cosmossdk.io/x/group/errors" ) // Dec is a wrapper struct around apd.Decimal that does no mutation of apd.Decimal's when performing @@ -23,10 +23,10 @@ type Dec struct { func NewPositiveDecFromString(s string) (Dec, error) { d, err := NewDecFromString(s) if err != nil { - return Dec{}, grouperrors.ErrInvalidDecString.Wrap(err.Error()) + return Dec{}, errors.ErrInvalidDecString.Wrap(err.Error()) } if !d.IsPositive() { - return Dec{}, grouperrors.ErrInvalidDecString.Wrapf("expected a positive decimal, got %s", s) + return Dec{}, errors.ErrInvalidDecString.Wrapf("expected a positive decimal, got %s", s) } return d, nil } @@ -34,10 +34,10 @@ func NewPositiveDecFromString(s string) (Dec, error) { func NewNonNegativeDecFromString(s string) (Dec, error) { d, err := NewDecFromString(s) if err != nil { - return Dec{}, grouperrors.ErrInvalidDecString.Wrap(err.Error()) + return Dec{}, errors.ErrInvalidDecString.Wrap(err.Error()) } if d.IsNegative() { - return Dec{}, grouperrors.ErrInvalidDecString.Wrapf("expected a non-negative decimal, got %s", s) + return Dec{}, errors.ErrInvalidDecString.Wrapf("expected a non-negative decimal, got %s", s) } return d, nil } @@ -51,11 +51,11 @@ func (x Dec) IsPositive() bool { func NewDecFromString(s string) (Dec, error) { d, _, err := apd.NewFromString(s) if err != nil { - return Dec{}, grouperrors.ErrInvalidDecString.Wrap(err.Error()) + return Dec{}, errors.ErrInvalidDecString.Wrap(err.Error()) } if d.Form != apd.Finite { - return Dec{}, grouperrors.ErrInvalidDecString.Wrapf("expected a finite decimal, got %s", s) + return Dec{}, errors.ErrInvalidDecString.Wrapf("expected a finite decimal, got %s", s) } return Dec{*d}, nil @@ -136,7 +136,7 @@ func SubNonNegative(x, y Dec) (Dec, error) { } if z.IsNegative() { - return z, errors.New("result negative during non-negative subtraction") + return z, fmt.Errorf("result negative during non-negative subtraction") } return z, nil From 9d6d1067bc1d2e6b4a9a34a25a9eadad931fda50 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 22 Nov 2024 11:36:30 +0100 Subject: [PATCH 2/2] fix: match comets bls implmentation (#22613) --- client/v2/go.mod | 1 - client/v2/go.sum | 2 -- crypto/codec/amino.go | 6 ++-- crypto/codec/pubkey.go | 6 ++-- crypto/keys/bls12_381/const.go | 21 ------------- crypto/keys/bls12_381/key.go | 7 +++-- crypto/keys/bls12_381/key_cgo.go | 49 +++++++++++++---------------- crypto/keys/jsonkey.go | 4 ++- crypto/keys/multisig/codec.go | 4 ++- go.mod | 1 - go.sum | 2 -- scripts/build/build.mk | 6 ++-- server/v2/cometbft/go.mod | 1 - server/v2/cometbft/go.sum | 2 -- simapp/go.mod | 1 - simapp/go.sum | 2 -- simapp/v2/go.mod | 1 - simapp/v2/go.sum | 2 -- tests/go.mod | 1 - tests/go.sum | 2 -- tests/integration/type_check.go | 4 +-- x/accounts/defaults/base/go.mod | 1 - x/accounts/defaults/base/go.sum | 2 -- x/accounts/defaults/lockup/go.mod | 1 - x/accounts/defaults/lockup/go.sum | 2 -- x/accounts/defaults/multisig/go.mod | 1 - x/accounts/defaults/multisig/go.sum | 2 -- x/accounts/go.mod | 1 - x/accounts/go.sum | 2 -- x/authz/go.mod | 1 - x/authz/go.sum | 2 -- x/bank/go.mod | 1 - x/bank/go.sum | 2 -- x/circuit/go.mod | 1 - x/circuit/go.sum | 2 -- x/consensus/go.mod | 1 - x/consensus/go.sum | 2 -- x/distribution/go.mod | 1 - x/distribution/go.sum | 2 -- x/epochs/go.mod | 1 - x/epochs/go.sum | 2 -- x/evidence/go.mod | 1 - x/evidence/go.sum | 2 -- x/feegrant/go.mod | 1 - x/feegrant/go.sum | 2 -- x/gov/go.mod | 1 - x/gov/go.sum | 2 -- x/group/go.mod | 1 - x/group/go.sum | 2 -- x/mint/go.mod | 1 - x/mint/go.sum | 2 -- x/nft/go.mod | 1 - x/nft/go.sum | 2 -- x/params/go.mod | 1 - x/params/go.sum | 2 -- x/protocolpool/go.mod | 1 - x/protocolpool/go.sum | 2 -- x/slashing/go.mod | 1 - x/slashing/go.sum | 2 -- x/staking/go.mod | 1 - x/staking/go.sum | 2 -- x/upgrade/go.mod | 1 - x/upgrade/go.sum | 2 -- 63 files changed, 44 insertions(+), 144 deletions(-) delete mode 100644 crypto/keys/bls12_381/const.go diff --git a/client/v2/go.mod b/client/v2/go.mod index bda385458943..06819fe3f462 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -63,7 +63,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.7.0 diff --git a/client/v2/go.sum b/client/v2/go.sum index fbdbc6c1c0bd..109e7bc264ee 100644 --- a/client/v2/go.sum +++ b/client/v2/go.sum @@ -127,8 +127,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/crypto/codec/amino.go b/crypto/codec/amino.go index b4d70055f7a4..53af143161e3 100644 --- a/crypto/codec/amino.go +++ b/crypto/codec/amino.go @@ -1,6 +1,8 @@ package codec import ( + "github.com/cometbft/cometbft/crypto/bls12381" + "cosmossdk.io/core/registry" bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381" @@ -18,7 +20,7 @@ func RegisterCrypto(registrar registry.AminoRegistrar) { ed25519.PubKeyName) registrar.RegisterConcrete(&secp256k1.PubKey{}, secp256k1.PubKeyName) - registrar.RegisterConcrete(&bls12_381.PubKey{}, bls12_381.PubKeyName) + registrar.RegisterConcrete(&bls12_381.PubKey{}, bls12381.PubKeyName) registrar.RegisterConcrete(&kmultisig.LegacyAminoPubKey{}, kmultisig.PubKeyAminoRoute) registrar.RegisterInterface((*cryptotypes.PrivKey)(nil), nil) @@ -26,5 +28,5 @@ func RegisterCrypto(registrar registry.AminoRegistrar) { ed25519.PrivKeyName) registrar.RegisterConcrete(&secp256k1.PrivKey{}, secp256k1.PrivKeyName) - registrar.RegisterConcrete(&bls12_381.PrivKey{}, bls12_381.PrivKeyName) + registrar.RegisterConcrete(&bls12_381.PrivKey{}, bls12381.PrivKeyName) } diff --git a/crypto/codec/pubkey.go b/crypto/codec/pubkey.go index 7710e9275abc..f28d88df3857 100644 --- a/crypto/codec/pubkey.go +++ b/crypto/codec/pubkey.go @@ -1,6 +1,8 @@ package codec import ( + "github.com/cometbft/cometbft/crypto/bls12381" + "cosmossdk.io/errors" cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys" @@ -29,7 +31,7 @@ func PubKeyToProto(pk cryptokeys.JSONPubkey) (cryptotypes.PubKey, error) { return &secp256k1.PubKey{ Key: pk.Value, }, nil - case bls12_381.PubKeyName: + case bls12381.PubKeyName: return &bls12_381.PubKey{ Key: pk.Value, }, nil @@ -60,7 +62,7 @@ func PubKeyFromProto(pk cryptotypes.PubKey) (cryptokeys.JSONPubkey, error) { }, nil case *bls12_381.PubKey: return cryptokeys.JSONPubkey{ - KeyType: bls12_381.PubKeyName, + KeyType: bls12381.PubKeyName, Value: pk.Bytes(), }, nil default: diff --git a/crypto/keys/bls12_381/const.go b/crypto/keys/bls12_381/const.go deleted file mode 100644 index 4a9169259bfe..000000000000 --- a/crypto/keys/bls12_381/const.go +++ /dev/null @@ -1,21 +0,0 @@ -package bls12_381 - -const ( - // PrivKeyName is the name of the private key as it is stored in the keystore. - PrivKeyName = "cometbft/PrivKeyBls12_381" - // PubKeyName is the name of the public key as it is stored in the keystore. - PubKeyName = "cometbft/PubKeyBls12_381" - // PubKeySize is the size, in bytes, of public keys as used in this package. - PubKeySize = 32 - // PrivKeySize is the size, in bytes, of private keys as used in this package. - PrivKeySize = 64 - // SignatureLength defines the byte length of a BLS signature. - SignatureLength = 96 - // SeedSize is the size, in bytes, of private key seeds. These are the - // private key representations used by RFC 8032. - SeedSize = 32 - // MaxMsgLen defines the maximum length of the message bytes as passed to Sign. - MaxMsgLen = 32 - // KeyType is the type of key this package provides. - KeyType = "bls12381" -) diff --git a/crypto/keys/bls12_381/key.go b/crypto/keys/bls12_381/key.go index fc146d5f80e3..1d9021d1503d 100644 --- a/crypto/keys/bls12_381/key.go +++ b/crypto/keys/bls12_381/key.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/cometbft/cometbft/crypto" + bls "github.com/cometbft/cometbft/crypto/bls12381" "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -54,7 +55,7 @@ func (privKey PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { // Type returns the type. func (PrivKey) Type() string { - return KeyType + return bls.KeyType } // Sign signs the given byte array. If msg is larger than @@ -70,7 +71,7 @@ func (privKey PrivKey) MarshalAmino() ([]byte, error) { // UnmarshalAmino overrides Amino binary marshaling. func (privKey *PrivKey) UnmarshalAmino(bz []byte) error { - if len(bz) != PrivKeySize { + if len(bz) != bls.PrivKeySize { return errors.New("invalid privkey size") } privKey.Key = bz @@ -119,7 +120,7 @@ func (pubKey PubKey) Bytes() []byte { // Type returns the key's type. func (PubKey) Type() string { - return KeyType + return bls.KeyType } // Equals returns true if the other's type is the same and their bytes are deeply equal. diff --git a/crypto/keys/bls12_381/key_cgo.go b/crypto/keys/bls12_381/key_cgo.go index 3e0fd433ae8f..2470e2c6ab6b 100644 --- a/crypto/keys/bls12_381/key_cgo.go +++ b/crypto/keys/bls12_381/key_cgo.go @@ -10,8 +10,7 @@ import ( "github.com/cometbft/cometbft/crypto" "github.com/cometbft/cometbft/crypto/tmhash" - - bls12381 "github.com/cosmos/crypto/curves/bls12381" + "github.com/cometbft/cometbft/crypto/bls12381" "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -32,20 +31,20 @@ var ( // NewPrivateKeyFromBytes build a new key from the given bytes. func NewPrivateKeyFromBytes(bz []byte) (PrivKey, error) { - secretKey, err := bls12381.SecretKeyFromBytes(bz) + secretKey, err := bls12381.NewPrivateKeyFromBytes(bz) if err != nil { return PrivKey{}, err } return PrivKey{ - Key: secretKey.Marshal(), + Key: secretKey.Bytes(), }, nil } // GenPrivKey generates a new key. func GenPrivKey() (PrivKey, error) { - secretKey, err := bls12381.RandKey() + secretKey, err := bls12381.GenPrivKey() return PrivKey{ - Key: secretKey.Marshal(), + Key: secretKey.Bytes(), }, err } @@ -57,13 +56,13 @@ func (privKey PrivKey) Bytes() []byte { // PubKey returns the private key's public key. If the privkey is not valid // it returns a nil value. func (privKey PrivKey) PubKey() cryptotypes.PubKey { - secretKey, err := bls12381.SecretKeyFromBytes(privKey.Key) + secretKey, err := bls12381.NewPrivateKeyFromBytes(privKey.Key) if err != nil { return nil } return &PubKey{ - Key: secretKey.PublicKey().Marshal(), + Key: secretKey.PubKey().Bytes(), } } @@ -74,24 +73,23 @@ func (privKey PrivKey) Equals(other cryptotypes.LedgerPrivKey) bool { // Type returns the type. func (PrivKey) Type() string { - return KeyType + return bls12381.KeyType } // Sign signs the given byte array. If msg is larger than // MaxMsgLen, SHA256 sum will be signed instead of the raw bytes. func (privKey PrivKey) Sign(msg []byte) ([]byte, error) { - secretKey, err := bls12381.SecretKeyFromBytes(privKey.Key) + secretKey, err := bls12381.NewPrivateKeyFromBytes(privKey.Key) if err != nil { return nil, err } - if len(msg) > MaxMsgLen { + if len(msg) > bls12381.MaxMsgLen { hash := sha256.Sum256(msg) - sig := secretKey.Sign(hash[:]) - return sig.Marshal(), nil + return secretKey.Sign(hash[:]) } - sig := secretKey.Sign(msg) - return sig.Marshal(), nil + + return secretKey.Sign(msg) } // MarshalAmino overrides Amino binary marshaling. @@ -101,7 +99,7 @@ func (privKey PrivKey) MarshalAmino() ([]byte, error) { // UnmarshalAmino overrides Amino binary marshaling. func (privKey *PrivKey) UnmarshalAmino(bz []byte) error { - if len(bz) != PrivKeySize { + if len(bz) != bls12381.PrivKeySize { return errors.New("invalid privkey size") } privKey.Key = bz @@ -135,8 +133,8 @@ var _ cryptotypes.PubKey = &PubKey{} // // The function will panic if the public key is invalid. func (pubKey PubKey) Address() crypto.Address { - pk, _ := bls12381.PublicKeyFromBytes(pubKey.Key) - if len(pk.Marshal()) != PubKeySize { + pk, _ := bls12381.NewPublicKeyFromBytes(pubKey.Key) + if len(pk.Bytes()) != bls12381.PubKeySize { panic("pubkey is incorrect size") } return crypto.Address(tmhash.SumTruncated(pubKey.Key)) @@ -144,26 +142,21 @@ func (pubKey PubKey) Address() crypto.Address { // VerifySignature verifies the given signature. func (pubKey PubKey) VerifySignature(msg, sig []byte) bool { - if len(sig) != SignatureLength { + if len(sig) != bls12381.SignatureLength { return false } - pubK, err := bls12381.PublicKeyFromBytes(pubKey.Key) + pubK, err := bls12381.NewPublicKeyFromBytes(pubKey.Key) if err != nil { // invalid pubkey return false } - if len(msg) > MaxMsgLen { + if len(msg) > bls12381.MaxMsgLen { hash := sha256.Sum256(msg) msg = hash[:] } - ok, err := bls12381.VerifySignature(sig, [MaxMsgLen]byte(msg[:MaxMsgLen]), pubK) - if err != nil { // bad signature - return false - } - - return ok + return pubK.VerifySignature(msg, sig) } // Bytes returns the byte format. @@ -173,7 +166,7 @@ func (pubKey PubKey) Bytes() []byte { // Type returns the key's type. func (PubKey) Type() string { - return KeyType + return bls12381.KeyType } // Equals returns true if the other's type is the same and their bytes are deeply equal. diff --git a/crypto/keys/jsonkey.go b/crypto/keys/jsonkey.go index 8edbd91e7246..a6b1dd72c719 100644 --- a/crypto/keys/jsonkey.go +++ b/crypto/keys/jsonkey.go @@ -1,6 +1,8 @@ package keys import ( + bls "github.com/cometbft/cometbft/crypto/bls12381" + "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -26,7 +28,7 @@ func (pk JSONPubkey) Address() types.Address { Key: pk.Value, } return secp256k1.Address() - case bls12_381.PubKeyName: + case bls.PubKeyName: bls12_381 := bls12_381.PubKey{ Key: pk.Value, } diff --git a/crypto/keys/multisig/codec.go b/crypto/keys/multisig/codec.go index aaadcea19796..b1e9a0d91602 100644 --- a/crypto/keys/multisig/codec.go +++ b/crypto/keys/multisig/codec.go @@ -1,6 +1,8 @@ package multisig import ( + "github.com/cometbft/cometbft/crypto/bls12381" + "github.com/cosmos/cosmos-sdk/codec" bls12_381 "github.com/cosmos/cosmos-sdk/crypto/keys/bls12_381" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -26,7 +28,7 @@ func init() { AminoCdc.RegisterConcrete(&secp256k1.PubKey{}, secp256k1.PubKeyName) AminoCdc.RegisterConcrete(&bls12_381.PubKey{}, - bls12_381.PubKeyName) + bls12381.PubKeyName) AminoCdc.RegisterConcrete(&LegacyAminoPubKey{}, PubKeyAminoRoute) } diff --git a/go.mod b/go.mod index 3fae0e4ea8f1..edc335bb0b75 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,6 @@ require ( github.com/cosmos/btcutil v1.0.5 github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 github.com/cosmos/cosmos-proto v1.0.0-beta.5 - github.com/cosmos/crypto v0.1.2 github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogogateway v1.2.0 github.com/cosmos/gogoproto v1.7.0 diff --git a/go.sum b/go.sum index 8e3981cc9b4f..172df44ab43d 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/scripts/build/build.mk b/scripts/build/build.mk index f68288ca8a5d..3537c3f23123 100644 --- a/scripts/build/build.mk +++ b/scripts/build/build.mk @@ -72,10 +72,10 @@ ifeq (boltdb,$(findstring boltdb,$(COSMOS_BUILD_OPTIONS))) build_tags += boltdb endif -# handle blst -ifeq (blst,$(findstring blst,$(COSMOS_BUILD_OPTIONS))) +# handle bls12381 +ifeq (bls12381,$(findstring bls12381,$(COSMOS_BUILD_OPTIONS))) CGO_ENABLED=1 - build_tags += blst + build_tags += bls12381 endif whitespace := diff --git a/server/v2/cometbft/go.mod b/server/v2/cometbft/go.mod index 464572d0deb8..6537a64c971e 100644 --- a/server/v2/cometbft/go.mod +++ b/server/v2/cometbft/go.mod @@ -75,7 +75,6 @@ require ( github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/server/v2/cometbft/go.sum b/server/v2/cometbft/go.sum index 3ef8ce70ab51..639b9f3e1603 100644 --- a/server/v2/cometbft/go.sum +++ b/server/v2/cometbft/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/simapp/go.mod b/simapp/go.mod index 168a4d3c2ef6..0a8a04e57010 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -93,7 +93,6 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/simapp/go.sum b/simapp/go.sum index bd47ea8946ee..97000b969709 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -328,8 +328,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index f5aa09085ae0..2c3da5965cd9 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -97,7 +97,6 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.7.0 // indirect diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 49355a5beb9b..b08342fe042d 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -327,8 +327,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/tests/go.mod b/tests/go.mod index 782f836d0794..b3fcc5cec907 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -104,7 +104,6 @@ require ( github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/tests/go.sum b/tests/go.sum index cd55ba56ebf5..22b367b6dcde 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -326,8 +326,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/tests/integration/type_check.go b/tests/integration/type_check.go index 9885981eb2a4..2982f79ea639 100644 --- a/tests/integration/type_check.go +++ b/tests/integration/type_check.go @@ -1,9 +1,9 @@ package integration import ( - coretesting "cosmossdk.io/core/testing" - db "github.com/cosmos/cosmos-db" + + coretesting "cosmossdk.io/core/testing" ) // This file contains a list of type checks that are used to ensure that implementations diff --git a/x/accounts/defaults/base/go.mod b/x/accounts/defaults/base/go.mod index 733721d61596..5077e31e48ca 100644 --- a/x/accounts/defaults/base/go.mod +++ b/x/accounts/defaults/base/go.mod @@ -53,7 +53,6 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/accounts/defaults/base/go.sum b/x/accounts/defaults/base/go.sum index b8bdc26661a9..593f59e1c4a2 100644 --- a/x/accounts/defaults/base/go.sum +++ b/x/accounts/defaults/base/go.sum @@ -117,8 +117,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/accounts/defaults/lockup/go.mod b/x/accounts/defaults/lockup/go.mod index 27f239dd2a79..dc7fa6c371b0 100644 --- a/x/accounts/defaults/lockup/go.mod +++ b/x/accounts/defaults/lockup/go.mod @@ -54,7 +54,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect github.com/cosmos/ics23/go v0.11.0 // indirect diff --git a/x/accounts/defaults/lockup/go.sum b/x/accounts/defaults/lockup/go.sum index 2c8b41d2dcf8..74bc7d41f7de 100644 --- a/x/accounts/defaults/lockup/go.sum +++ b/x/accounts/defaults/lockup/go.sum @@ -98,8 +98,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/accounts/defaults/multisig/go.mod b/x/accounts/defaults/multisig/go.mod index 313612ce2467..d2d272618e29 100644 --- a/x/accounts/defaults/multisig/go.mod +++ b/x/accounts/defaults/multisig/go.mod @@ -52,7 +52,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/accounts/defaults/multisig/go.sum b/x/accounts/defaults/multisig/go.sum index b8bdc26661a9..593f59e1c4a2 100644 --- a/x/accounts/defaults/multisig/go.sum +++ b/x/accounts/defaults/multisig/go.sum @@ -117,8 +117,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/accounts/go.mod b/x/accounts/go.mod index 52292c81762f..a5cfe853beee 100644 --- a/x/accounts/go.mod +++ b/x/accounts/go.mod @@ -61,7 +61,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/accounts/go.sum b/x/accounts/go.sum index b8bdc26661a9..593f59e1c4a2 100644 --- a/x/accounts/go.sum +++ b/x/accounts/go.sum @@ -117,8 +117,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/authz/go.mod b/x/authz/go.mod index 01794c84b2fc..37d5ecabf82b 100644 --- a/x/authz/go.mod +++ b/x/authz/go.mod @@ -50,7 +50,6 @@ require ( github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/authz/go.sum b/x/authz/go.sum index b8bdc26661a9..593f59e1c4a2 100644 --- a/x/authz/go.sum +++ b/x/authz/go.sum @@ -117,8 +117,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/bank/go.mod b/x/bank/go.mod index 6c0529bcdf35..b954bfd81a26 100644 --- a/x/bank/go.mod +++ b/x/bank/go.mod @@ -50,7 +50,6 @@ require ( github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/bank/go.sum b/x/bank/go.sum index b8bdc26661a9..593f59e1c4a2 100644 --- a/x/bank/go.sum +++ b/x/bank/go.sum @@ -117,8 +117,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/circuit/go.mod b/x/circuit/go.mod index a2fa36ec82f1..0f38ac9ce5ed 100644 --- a/x/circuit/go.mod +++ b/x/circuit/go.mod @@ -54,7 +54,6 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/circuit/go.sum b/x/circuit/go.sum index 6230f243f4dc..6c163aee66b2 100644 --- a/x/circuit/go.sum +++ b/x/circuit/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/consensus/go.mod b/x/consensus/go.mod index 71c25018bbbd..20a202aa6e2a 100644 --- a/x/consensus/go.mod +++ b/x/consensus/go.mod @@ -54,7 +54,6 @@ require ( github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/consensus/go.sum b/x/consensus/go.sum index 6230f243f4dc..6c163aee66b2 100644 --- a/x/consensus/go.sum +++ b/x/consensus/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/distribution/go.mod b/x/distribution/go.mod index 740ddebae648..1590e05ab120 100644 --- a/x/distribution/go.mod +++ b/x/distribution/go.mod @@ -57,7 +57,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/distribution/go.sum b/x/distribution/go.sum index b8bdc26661a9..593f59e1c4a2 100644 --- a/x/distribution/go.sum +++ b/x/distribution/go.sum @@ -117,8 +117,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/epochs/go.mod b/x/epochs/go.mod index 0ad651f26d0e..7eb2e0af4dbf 100644 --- a/x/epochs/go.mod +++ b/x/epochs/go.mod @@ -50,7 +50,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/epochs/go.sum b/x/epochs/go.sum index 6230f243f4dc..6c163aee66b2 100644 --- a/x/epochs/go.sum +++ b/x/epochs/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/evidence/go.mod b/x/evidence/go.mod index 77fda3b4507f..50f9ae8ffd96 100644 --- a/x/evidence/go.mod +++ b/x/evidence/go.mod @@ -57,7 +57,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/evidence/go.sum b/x/evidence/go.sum index 6230f243f4dc..6c163aee66b2 100644 --- a/x/evidence/go.sum +++ b/x/evidence/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/feegrant/go.mod b/x/feegrant/go.mod index 2231d120b9c8..0d0a961f035c 100644 --- a/x/feegrant/go.mod +++ b/x/feegrant/go.mod @@ -65,7 +65,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/feegrant/go.sum b/x/feegrant/go.sum index 85ccf3835aaf..19802266c772 100644 --- a/x/feegrant/go.sum +++ b/x/feegrant/go.sum @@ -125,8 +125,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/gov/go.mod b/x/gov/go.mod index 5e85f5dca011..7f42c349ce66 100644 --- a/x/gov/go.mod +++ b/x/gov/go.mod @@ -57,7 +57,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/gov/go.sum b/x/gov/go.sum index 73aeedb74aa1..85d8825a9a9b 100644 --- a/x/gov/go.sum +++ b/x/gov/go.sum @@ -123,8 +123,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/group/go.mod b/x/group/go.mod index d0b4226678e5..c1fd3b896e80 100644 --- a/x/group/go.mod +++ b/x/group/go.mod @@ -67,7 +67,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/group/go.sum b/x/group/go.sum index 57f9e63c4f6e..c103aa92f6f6 100644 --- a/x/group/go.sum +++ b/x/group/go.sum @@ -125,8 +125,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/mint/go.mod b/x/mint/go.mod index 3e49e748f776..5689e3406e16 100644 --- a/x/mint/go.mod +++ b/x/mint/go.mod @@ -50,7 +50,6 @@ require ( github.com/cometbft/cometbft v1.0.0-rc1.0.20240908111210-ab0be101882f // indirect github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/mint/go.sum b/x/mint/go.sum index 6230f243f4dc..6c163aee66b2 100644 --- a/x/mint/go.sum +++ b/x/mint/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/nft/go.mod b/x/nft/go.mod index f22a0a3991ba..eb3fa08d5653 100644 --- a/x/nft/go.mod +++ b/x/nft/go.mod @@ -55,7 +55,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/nft/go.sum b/x/nft/go.sum index 6230f243f4dc..6c163aee66b2 100644 --- a/x/nft/go.sum +++ b/x/nft/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/params/go.mod b/x/params/go.mod index 2f0fde03f324..2733943ad012 100644 --- a/x/params/go.mod +++ b/x/params/go.mod @@ -54,7 +54,6 @@ require ( github.com/cometbft/cometbft v1.0.0-rc1.0.20240908111210-ab0be101882f // indirect github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/params/go.sum b/x/params/go.sum index 2af58ebe3d81..55bd2faac1c8 100644 --- a/x/params/go.sum +++ b/x/params/go.sum @@ -109,8 +109,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/protocolpool/go.mod b/x/protocolpool/go.mod index fb6fee8636ce..32293de14812 100644 --- a/x/protocolpool/go.mod +++ b/x/protocolpool/go.mod @@ -56,7 +56,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/protocolpool/go.sum b/x/protocolpool/go.sum index 6230f243f4dc..6c163aee66b2 100644 --- a/x/protocolpool/go.sum +++ b/x/protocolpool/go.sum @@ -119,8 +119,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/slashing/go.mod b/x/slashing/go.mod index 021a56159419..7daff26398cd 100644 --- a/x/slashing/go.mod +++ b/x/slashing/go.mod @@ -58,7 +58,6 @@ require ( github.com/cometbft/cometbft/api v1.0.0-rc.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/slashing/go.sum b/x/slashing/go.sum index d5d6973d65d5..d629b4d4944c 100644 --- a/x/slashing/go.sum +++ b/x/slashing/go.sum @@ -121,8 +121,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/staking/go.mod b/x/staking/go.mod index 56af1cd856a4..60e73a2632a2 100644 --- a/x/staking/go.mod +++ b/x/staking/go.mod @@ -152,7 +152,6 @@ require ( require ( buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.35.2-20240701160653-fedbb9acfd2f.1 // indirect cosmossdk.io/log v1.5.0 - github.com/cosmos/crypto v0.1.2 // indirect github.com/dgraph-io/badger/v4 v4.3.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/flatbuffers v2.0.8+incompatible // indirect diff --git a/x/staking/go.sum b/x/staking/go.sum index b8bdc26661a9..593f59e1c4a2 100644 --- a/x/staking/go.sum +++ b/x/staking/go.sum @@ -117,8 +117,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/upgrade/go.mod b/x/upgrade/go.mod index ff74cd8f30cf..a4af182dc684 100644 --- a/x/upgrade/go.mod +++ b/x/upgrade/go.mod @@ -72,7 +72,6 @@ require ( github.com/cometbft/cometbft-db v0.15.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 // indirect - github.com/cosmos/crypto v0.1.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.3.1 // indirect diff --git a/x/upgrade/go.sum b/x/upgrade/go.sum index 1787bdf78cf3..f4d0cca069db 100644 --- a/x/upgrade/go.sum +++ b/x/upgrade/go.sum @@ -327,8 +327,6 @@ github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22 h1:V3WlarcZwlYY github.com/cosmos/cosmos-db v1.0.3-0.20240911104526-ddc3f09bfc22/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/crypto v0.1.2 h1:Yn500sPY+9sKVdhiPUSDtt8JOpBGMB515dOmla4zfls= -github.com/cosmos/crypto v0.1.2/go.mod h1:b6VWz3HczIpBaQPvI7KrbQeF3pXHh0al3T5e0uwMBQw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=