Skip to content

Commit

Permalink
Merge PR #3665: Uint overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
alessio authored and jackzampolin committed Feb 19, 2019
1 parent 95710f1 commit b67d024
Show file tree
Hide file tree
Showing 5 changed files with 427 additions and 509 deletions.
2 changes: 2 additions & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@

### SDK

* [\#3665] Overhaul sdk.Uint type in preparation for Coins's Int -> Uint migration.

### Tendermint

<!--------------------------------- BUG FIXES -------------------------------->
Expand Down
255 changes: 0 additions & 255 deletions types/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,6 @@ func (i Int) String() string {
return i.i.String()
}

// Testing purpose random Int generator
func randomInt(i Int) Int {
return NewIntFromBigInt(random(i.BigInt()))
}

// MarshalAmino defines custom encoding scheme
func (i Int) MarshalAmino() (string, error) {
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
Expand Down Expand Up @@ -355,256 +350,6 @@ func (i *Int) UnmarshalJSON(bz []byte) error {
return unmarshalJSON(i.i, bz)
}

// Int wraps integer with 256 bit range bound
// Checks overflow, underflow and division by zero
// Exists in range from 0 to 2^256-1
type Uint struct {
i *big.Int
}

// BigInt converts Uint to big.Unt
func (i Uint) BigInt() *big.Int {
return new(big.Int).Set(i.i)
}

// NewUint constructs Uint from int64
func NewUint(n uint64) Uint {
i := new(big.Int)
i.SetUint64(n)
return Uint{i}
}

// NewUintFromBigUint constructs Uint from big.Uint
func NewUintFromBigInt(i *big.Int) Uint {
res := Uint{i}
if UintOverflow(res) {
panic("Uint overflow")
}
return res
}

// NewUintFromString constructs Uint from string
func NewUintFromString(s string) (res Uint, ok bool) {
i, ok := newIntegerFromString(s)
if !ok {
return
}
// Check overflow
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
ok = false
return
}
return Uint{i}, true
}

// NewUintWithDecimal constructs Uint with decimal
// Result value is n*10^dec
func NewUintWithDecimal(n uint64, dec int) Uint {
if dec < 0 {
panic("NewUintWithDecimal() decimal is negative")
}
exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(dec)), nil)
i := new(big.Int)
i.Mul(new(big.Int).SetUint64(n), exp)

res := Uint{i}
if UintOverflow(res) {
panic("NewUintWithDecimal() out of bound")
}

return res
}

// ZeroUint returns Uint value with zero
func ZeroUint() Uint { return Uint{big.NewInt(0)} }

// OneUint returns Uint value with one
func OneUint() Uint { return Uint{big.NewInt(1)} }

// Uint64 converts Uint to uint64
// Panics if the value is out of range
func (i Uint) Uint64() uint64 {
if !i.i.IsUint64() {
panic("Uint64() out of bound")
}
return i.i.Uint64()
}

// IsUint64 returns true if Uint64() not panics
func (i Uint) IsUint64() bool {
return i.i.IsUint64()
}

// IsZero returns true if Uint is zero
func (i Uint) IsZero() bool {
return i.i.Sign() == 0
}

// Sign returns sign of Uint
func (i Uint) Sign() int {
return i.i.Sign()
}

// Equal compares two Uints
func (i Uint) Equal(i2 Uint) bool {
return equal(i.i, i2.i)
}

// GT returns true if first Uint is greater than second
func (i Uint) GT(i2 Uint) bool {
return gt(i.i, i2.i)
}

// LT returns true if first Uint is lesser than second
func (i Uint) LT(i2 Uint) bool {
return lt(i.i, i2.i)
}

// Add adds Uint from another
func (i Uint) Add(i2 Uint) (res Uint) {
res = Uint{add(i.i, i2.i)}
if UintOverflow(res) {
panic("Uint overflow")
}
return
}

// AddRaw adds uint64 to Uint
func (i Uint) AddRaw(i2 uint64) Uint {
return i.Add(NewUint(i2))
}

// Sub subtracts Uint from another
func (i Uint) Sub(i2 Uint) (res Uint) {
res = Uint{sub(i.i, i2.i)}
if UintOverflow(res) {
panic("Uint overflow")
}
return
}

// SafeSub attempts to subtract one Uint from another. A boolean is also returned
// indicating if the result contains integer overflow.
func (i Uint) SafeSub(i2 Uint) (Uint, bool) {
res := Uint{sub(i.i, i2.i)}
if UintOverflow(res) {
return res, true
}

return res, false
}

// SubRaw subtracts uint64 from Uint
func (i Uint) SubRaw(i2 uint64) Uint {
return i.Sub(NewUint(i2))
}

// Mul multiples two Uints
func (i Uint) Mul(i2 Uint) (res Uint) {
if i.i.BitLen()+i2.i.BitLen()-1 > 256 {
panic("Uint overflow")
}

res = Uint{mul(i.i, i2.i)}
if UintOverflow(res) {
panic("Uint overflow")
}

return
}

// MulRaw multipies Uint and uint64
func (i Uint) MulRaw(i2 uint64) Uint {
return i.Mul(NewUint(i2))
}

// Div divides Uint with Uint
func (i Uint) Div(i2 Uint) (res Uint) {
// Check division-by-zero
if i2.Sign() == 0 {
panic("division-by-zero")
}
return Uint{div(i.i, i2.i)}
}

// Div divides Uint with uint64
func (i Uint) DivRaw(i2 uint64) Uint {
return i.Div(NewUint(i2))
}

// Mod returns remainder after dividing with Uint
func (i Uint) Mod(i2 Uint) Uint {
if i2.Sign() == 0 {
panic("division-by-zero")
}
return Uint{mod(i.i, i2.i)}
}

// ModRaw returns remainder after dividing with uint64
func (i Uint) ModRaw(i2 uint64) Uint {
return i.Mod(NewUint(i2))
}

// Return the minimum of the Uints
func MinUint(i1, i2 Uint) Uint {
return Uint{min(i1.BigInt(), i2.BigInt())}
}

// MaxUint returns the maximum between two unsigned integers.
func MaxUint(i, i2 Uint) Uint {
return Uint{max(i.BigInt(), i2.BigInt())}
}

// Human readable string
func (i Uint) String() string {
return i.i.String()
}

// Testing purpose random Uint generator
func randomUint(i Uint) Uint {
return NewUintFromBigInt(random(i.BigInt()))
}

// MarshalAmino defines custom encoding scheme
func (i Uint) MarshalAmino() (string, error) {
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return marshalAmino(i.i)
}

// UnmarshalAmino defines custom decoding scheme
func (i *Uint) UnmarshalAmino(text string) error {
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return unmarshalAmino(i.i, text)
}

// MarshalJSON defines custom encoding scheme
func (i Uint) MarshalJSON() ([]byte, error) {
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return marshalJSON(i.i)
}

// UnmarshalJSON defines custom decoding scheme
func (i *Uint) UnmarshalJSON(bz []byte) error {
if i.i == nil { // Necessary since default Uint initialization has i.i as nil
i.i = new(big.Int)
}
return unmarshalJSON(i.i, bz)
}

//__________________________________________________________________________

// UintOverflow returns true if a given unsigned integer overflows and false
// otherwise.
func UintOverflow(x Uint) bool {
return x.i.Sign() == -1 || x.i.Sign() == 1 && x.i.BitLen() > 256
}

// intended to be used with require/assert: require.True(IntEq(...))
func IntEq(t *testing.T, exp, got Int) (*testing.T, bool, string, string, string) {
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String()
Expand Down
Loading

0 comments on commit b67d024

Please sign in to comment.