Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module github.com/cosmos/cosmos-sdk

require (
cosmossdk.io/errors v1.0.0-beta.7
cosmossdk.io/math v1.0.0-rc.0
cosmossdk.io/math v1.4.0
github.com/99designs/keyring v1.2.1
github.com/armon/go-metrics v0.4.1
github.com/bgentry/speakeasy v0.1.0
Expand Down Expand Up @@ -59,7 +59,7 @@ require (
google.golang.org/grpc v1.69.4
google.golang.org/protobuf v1.35.2
pgregory.net/rapid v0.4.7
sigs.k8s.io/yaml v1.3.0
sigs.k8s.io/yaml v1.4.0
)

require (
Expand Down Expand Up @@ -166,7 +166,6 @@ require (
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
)
Expand Down
9 changes: 5 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHX
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w=
cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE=
cosmossdk.io/math v1.0.0-rc.0 h1:ml46ukocrAAoBpYKMidF0R2tQJ1Uxfns0yH8wqgMAFc=
cosmossdk.io/math v1.0.0-rc.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k=
cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ=
cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
Expand Down Expand Up @@ -415,6 +415,7 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
Expand Down Expand Up @@ -1397,6 +1398,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
111 changes: 59 additions & 52 deletions types/decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,17 @@ const (
// Ceiling[Log2[10^Precision - 1]]
DecimalPrecisionBits = 60

// decimalTruncateBits is the minimum number of bits removed
// by a truncate operation. It is equal to
// Floor[Log2[10^Precision - 1]].
decimalTruncateBits = DecimalPrecisionBits - 1

maxDecBitLen = MaxBitLen + decimalTruncateBits

// max number of iterations in ApproxRoot function
maxApproxRootIterations = 300
)

var (
precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil)
fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2))
precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil)
fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2))

upperLimit Dec
lowerLimit Dec

precisionMultipliers []*big.Int
zeroInt = big.NewInt(0)
oneInt = big.NewInt(1)
Expand All @@ -59,6 +56,11 @@ func init() {
for i := 0; i <= Precision; 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 = NewDecFromBigIntWithPrec(tmp, Precision)
lowerLimit = upperLimit.Neg()
}

func precisionInt() *big.Int {
Expand All @@ -71,6 +73,10 @@ func SmallestDec() Dec { return Dec{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 > Precision {
panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec))
}
Expand All @@ -81,6 +87,10 @@ func calcPrecisionMultiplier(prec int64) *big.Int {

// 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 > Precision {
panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec))
}
Expand Down Expand Up @@ -187,14 +197,15 @@ func NewDecFromStr(str string) (Dec, error) {
if !ok {
return Dec{}, fmt.Errorf("failed to set decimal string with base 10: %s", combinedStr)
}
if combined.BitLen() > maxDecBitLen {
return Dec{}, fmt.Errorf("decimal '%s' out of range; bitLen: got %d, max %d", str, combined.BitLen(), maxDecBitLen)
}
if neg {
combined = new(big.Int).Neg(combined)
}

return Dec{combined}, nil
result := Dec{i: combined}
if !result.IsInValidRange() {
return Dec{}, fmt.Errorf("out of range: %w", ErrInvalidDecimalStr)
}
return result, nil
}

// Decimal from string, panic on error
Expand Down Expand Up @@ -261,9 +272,7 @@ func (d Dec) Add(d2 Dec) Dec {
func (d Dec) AddMut(d2 Dec) Dec {
d.i.Add(d.i, d2.i)

if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
d.assertInValidRange()
return d
}

Expand All @@ -276,10 +285,20 @@ func (d Dec) Sub(d2 Dec) Dec {
func (d Dec) SubMut(d2 Dec) Dec {
d.i.Sub(d.i, d2.i)

if d.i.BitLen() > maxDecBitLen {
d.assertInValidRange()
return d
}

func (d Dec) assertInValidRange() {
if !d.IsInValidRange() {
panic("Int overflow")
}
return d
}

// 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 Dec) IsInValidRange() bool {
return !(d.GT(upperLimit) || d.LT(lowerLimit))
}

// multiplication
Expand All @@ -292,10 +311,8 @@ func (d Dec) MulMut(d2 Dec) Dec {
d.i.Mul(d.i, d2.i)
chopped := chopPrecisionAndRound(d.i)

if chopped.BitLen() > maxDecBitLen {
panic("Int overflow")
}
*d.i = *chopped
d.assertInValidRange()
return d
}

Expand All @@ -308,10 +325,7 @@ func (d Dec) MulTruncate(d2 Dec) Dec {
func (d Dec) MulTruncateMut(d2 Dec) Dec {
d.i.Mul(d.i, d2.i)
chopPrecisionAndTruncate(d.i)

if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
d.assertInValidRange()
return d
}

Expand All @@ -322,9 +336,7 @@ func (d Dec) MulInt(i Int) Dec {

func (d Dec) MulIntMut(i Int) Dec {
d.i.Mul(d.i, i.BigInt())
if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
d.assertInValidRange()
return d
}

Expand All @@ -335,10 +347,7 @@ func (d Dec) MulInt64(i int64) Dec {

func (d Dec) MulInt64Mut(i int64) Dec {
d.i.Mul(d.i, big.NewInt(i))

if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
d.assertInValidRange()
return d
}

Expand All @@ -355,9 +364,7 @@ func (d Dec) QuoMut(d2 Dec) Dec {
d.i.Quo(d.i, d2.i)

chopPrecisionAndRound(d.i)
if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
d.assertInValidRange()
return d
}

Expand All @@ -374,9 +381,7 @@ func (d Dec) QuoTruncateMut(d2 Dec) Dec {
d.i.Quo(d.i, d2.i)

chopPrecisionAndTruncate(d.i)
if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
d.assertInValidRange()
return d
}

Expand All @@ -393,9 +398,7 @@ func (d Dec) QuoRoundupMut(d2 Dec) Dec {
d.i.Quo(d.i, d2.i)

chopPrecisionAndRoundUp(d.i)
if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
d.assertInValidRange()
return d
}

Expand Down Expand Up @@ -703,15 +706,17 @@ func (d Dec) Ceil() Dec {
quo, rem = quo.QuoRem(tmp, precisionReuse, rem)

// no need to round with a zero remainder regardless of sign
if rem.Cmp(zeroInt) == 0 {
return NewDecFromBigInt(quo)
}

if rem.Sign() == -1 {
return NewDecFromBigInt(quo)
var r Dec
switch rem.Sign() {
case 0:
r = NewDecFromBigInt(quo)
case -1:
r = NewDecFromBigInt(quo)
default:
r = NewDecFromBigInt(quo.Add(quo, oneInt))
}

return NewDecFromBigInt(quo.Add(quo, oneInt))
r.assertInValidRange()
return r
}

// MaxSortableDec is the largest Dec that can be passed into SortableDecBytes()
Expand Down Expand Up @@ -839,8 +844,8 @@ func (d *Dec) Unmarshal(data []byte) error {
return err
}

if d.i.BitLen() > maxDecBitLen {
return fmt.Errorf("decimal out of range; got: %d, max: %d", d.i.BitLen(), maxDecBitLen)
if !d.IsInValidRange() {
return errors.New("decimal out of range")
}

return nil
Expand Down Expand Up @@ -894,10 +899,12 @@ func MaxDec(d1, d2 Dec) Dec {

// intended to be used with require/assert: require.True(DecEq(...))
func DecEq(t *testing.T, exp, got Dec) (*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 DecApproxEq(t *testing.T, d1 Dec, d2 Dec, tol Dec) (*testing.T, bool, string, string, string) {
func DecApproxEq(t *testing.T, d1, d2, tol Dec) (*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()
}
Loading
Loading