aboutsummaryrefslogtreecommitdiffstats
path: root/common/math
diff options
context:
space:
mode:
Diffstat (limited to 'common/math')
-rw-r--r--common/math/big.go143
-rw-r--r--common/math/big_test.go196
-rw-r--r--common/math/dist.go96
-rw-r--r--common/math/dist_test.go82
-rw-r--r--common/math/exp.go47
-rw-r--r--common/math/integer.go65
-rw-r--r--common/math/integer_test.go75
7 files changed, 468 insertions, 236 deletions
diff --git a/common/math/big.go b/common/math/big.go
new file mode 100644
index 000000000..c0508c102
--- /dev/null
+++ b/common/math/big.go
@@ -0,0 +1,143 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package math provides integer math utilities.
+package math
+
+import (
+ "math/big"
+)
+
+var (
+ tt255 = BigPow(2, 255)
+ tt256 = BigPow(2, 256)
+ tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
+ MaxBig256 = new(big.Int).Set(tt256m1)
+)
+
+// ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax.
+// Leading zeros are accepted. The empty string parses as zero.
+func ParseBig256(s string) (*big.Int, bool) {
+ if s == "" {
+ return new(big.Int), true
+ }
+ var bigint *big.Int
+ var ok bool
+ if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
+ bigint, ok = new(big.Int).SetString(s[2:], 16)
+ } else {
+ bigint, ok = new(big.Int).SetString(s, 10)
+ }
+ if ok && bigint.BitLen() > 256 {
+ bigint, ok = nil, false
+ }
+ return bigint, ok
+}
+
+// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid.
+func MustParseBig256(s string) *big.Int {
+ v, ok := ParseBig256(s)
+ if !ok {
+ panic("invalid 256 bit integer: " + s)
+ }
+ return v
+}
+
+// BigPow returns a ** b as a big integer.
+func BigPow(a, b int64) *big.Int {
+ r := big.NewInt(a)
+ return r.Exp(r, big.NewInt(b), nil)
+}
+
+// BigMax returns the larger of x or y.
+func BigMax(x, y *big.Int) *big.Int {
+ if x.Cmp(y) < 0 {
+ return y
+ }
+ return x
+}
+
+// BigMin returns the smaller of x or y.
+func BigMin(x, y *big.Int) *big.Int {
+ if x.Cmp(y) > 0 {
+ return y
+ }
+ return x
+}
+
+// FirstBitSet returns the index of the first 1 bit in v, counting from LSB.
+func FirstBitSet(v *big.Int) int {
+ for i := 0; i < v.BitLen(); i++ {
+ if v.Bit(i) > 0 {
+ return i
+ }
+ }
+ return v.BitLen()
+}
+
+// PaddedBigBytes encodes a big integer as a big-endian byte slice. The length
+// of the slice is at least n bytes.
+func PaddedBigBytes(bigint *big.Int, n int) []byte {
+ bytes := bigint.Bytes()
+ if len(bytes) >= n {
+ return bytes
+ }
+ ret := make([]byte, n)
+ return append(ret[:len(ret)-len(bytes)], bytes...)
+}
+
+// U256 encodes as a 256 bit two's complement number. This operation is destructive.
+func U256(x *big.Int) *big.Int {
+ return x.And(x, tt256m1)
+}
+
+// S256 interprets x as a two's complement number.
+// x must not exceed 256 bits (the result is undefined if it does) and is not modified.
+//
+// S256(0) = 0
+// S256(1) = 1
+// S256(2**255) = -2**255
+// S256(2**256-1) = -1
+func S256(x *big.Int) *big.Int {
+ if x.Cmp(tt255) < 0 {
+ return x
+ } else {
+ return new(big.Int).Sub(x, tt256)
+ }
+}
+
+// wordSize is the size number of bits in a big.Word.
+const wordSize = 32 << (uint64(^big.Word(0)) >> 63)
+
+// Exp implements exponentiation by squaring.
+// Exp returns a newly-allocated big integer and does not change
+// base or exponent. The result is truncated to 256 bits.
+//
+// Courtesy @karalabe and @chfast
+func Exp(base, exponent *big.Int) *big.Int {
+ result := big.NewInt(1)
+
+ for _, word := range exponent.Bits() {
+ for i := 0; i < wordSize; i++ {
+ if word&1 == 1 {
+ U256(result.Mul(result, base))
+ }
+ U256(base.Mul(base, base))
+ word >>= 1
+ }
+ }
+ return result
+}
diff --git a/common/math/big_test.go b/common/math/big_test.go
new file mode 100644
index 000000000..a0f48a8eb
--- /dev/null
+++ b/common/math/big_test.go
@@ -0,0 +1,196 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package math
+
+import (
+ "bytes"
+ "math/big"
+ "testing"
+)
+
+func TestParseBig256(t *testing.T) {
+ tests := []struct {
+ input string
+ num *big.Int
+ ok bool
+ }{
+ {"", big.NewInt(0), true},
+ {"0", big.NewInt(0), true},
+ {"0x0", big.NewInt(0), true},
+ {"12345678", big.NewInt(12345678), true},
+ {"0x12345678", big.NewInt(0x12345678), true},
+ {"0X12345678", big.NewInt(0x12345678), true},
+ // Tests for leading zero behaviour:
+ {"0123456789", big.NewInt(123456789), true}, // note: not octal
+ {"00", big.NewInt(0), true},
+ {"0x00", big.NewInt(0), true},
+ {"0x012345678abc", big.NewInt(0x12345678abc), true},
+ // Invalid syntax:
+ {"abcdef", nil, false},
+ {"0xgg", nil, false},
+ // Larger than 256 bits:
+ {"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false},
+ }
+ for _, test := range tests {
+ num, ok := ParseBig256(test.input)
+ if ok != test.ok {
+ t.Errorf("ParseBig(%q) -> ok = %t, want %t", test.input, ok, test.ok)
+ continue
+ }
+ if num != nil && test.num != nil && num.Cmp(test.num) != 0 {
+ t.Errorf("ParseBig(%q) -> %d, want %d", test.input, num, test.num)
+ }
+ }
+}
+
+func TestMustParseBig256(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Error("MustParseBig should've panicked")
+ }
+ }()
+ MustParseBig256("ggg")
+}
+
+func TestBigMax(t *testing.T) {
+ a := big.NewInt(10)
+ b := big.NewInt(5)
+
+ max1 := BigMax(a, b)
+ if max1 != a {
+ t.Errorf("Expected %d got %d", a, max1)
+ }
+
+ max2 := BigMax(b, a)
+ if max2 != a {
+ t.Errorf("Expected %d got %d", a, max2)
+ }
+}
+
+func TestBigMin(t *testing.T) {
+ a := big.NewInt(10)
+ b := big.NewInt(5)
+
+ min1 := BigMin(a, b)
+ if min1 != b {
+ t.Errorf("Expected %d got %d", b, min1)
+ }
+
+ min2 := BigMin(b, a)
+ if min2 != b {
+ t.Errorf("Expected %d got %d", b, min2)
+ }
+}
+
+func TestFirstBigSet(t *testing.T) {
+ tests := []struct {
+ num *big.Int
+ ix int
+ }{
+ {big.NewInt(0), 0},
+ {big.NewInt(1), 0},
+ {big.NewInt(2), 1},
+ {big.NewInt(0x100), 8},
+ }
+ for _, test := range tests {
+ if ix := FirstBitSet(test.num); ix != test.ix {
+ t.Errorf("FirstBitSet(b%b) = %d, want %d", test.num, ix, test.ix)
+ }
+ }
+}
+
+func TestPaddedBigBytes(t *testing.T) {
+ tests := []struct {
+ num *big.Int
+ n int
+ result []byte
+ }{
+ {num: big.NewInt(0), n: 4, result: []byte{0, 0, 0, 0}},
+ {num: big.NewInt(1), n: 4, result: []byte{0, 0, 0, 1}},
+ {num: big.NewInt(512), n: 4, result: []byte{0, 0, 2, 0}},
+ {num: BigPow(2, 32), n: 4, result: []byte{1, 0, 0, 0, 0}},
+ }
+ for _, test := range tests {
+ if result := PaddedBigBytes(test.num, test.n); !bytes.Equal(result, test.result) {
+ t.Errorf("PaddedBigBytes(%d, %d) = %v, want %v", test.num, test.n, result, test.result)
+ }
+ }
+}
+
+func TestU256(t *testing.T) {
+ tests := []struct{ x, y *big.Int }{
+ {x: big.NewInt(0), y: big.NewInt(0)},
+ {x: big.NewInt(1), y: big.NewInt(1)},
+ {x: BigPow(2, 255), y: BigPow(2, 255)},
+ {x: BigPow(2, 256), y: big.NewInt(0)},
+ {x: new(big.Int).Add(BigPow(2, 256), big.NewInt(1)), y: big.NewInt(1)},
+ // negative values
+ {x: big.NewInt(-1), y: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1))},
+ {x: big.NewInt(-2), y: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2))},
+ {x: BigPow(2, -255), y: big.NewInt(1)},
+ }
+ for _, test := range tests {
+ if y := U256(new(big.Int).Set(test.x)); y.Cmp(test.y) != 0 {
+ t.Errorf("U256(%x) = %x, want %x", test.x, y, test.y)
+ }
+ }
+}
+
+func TestS256(t *testing.T) {
+ tests := []struct{ x, y *big.Int }{
+ {x: big.NewInt(0), y: big.NewInt(0)},
+ {x: big.NewInt(1), y: big.NewInt(1)},
+ {x: big.NewInt(2), y: big.NewInt(2)},
+ {
+ x: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
+ y: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
+ },
+ {
+ x: BigPow(2, 255),
+ y: new(big.Int).Neg(BigPow(2, 255)),
+ },
+ {
+ x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1)),
+ y: big.NewInt(-1),
+ },
+ {
+ x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2)),
+ y: big.NewInt(-2),
+ },
+ }
+ for _, test := range tests {
+ if y := S256(test.x); y.Cmp(test.y) != 0 {
+ t.Errorf("S256(%x) = %x, want %x", test.x, y, test.y)
+ }
+ }
+}
+
+func TestExp(t *testing.T) {
+ tests := []struct{ base, exponent, result *big.Int }{
+ {base: big.NewInt(0), exponent: big.NewInt(0), result: big.NewInt(1)},
+ {base: big.NewInt(1), exponent: big.NewInt(0), result: big.NewInt(1)},
+ {base: big.NewInt(1), exponent: big.NewInt(1), result: big.NewInt(1)},
+ {base: big.NewInt(1), exponent: big.NewInt(2), result: big.NewInt(1)},
+ {base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig256("507528786056415600719754159741696356908742250191663887263627442114881")},
+ {base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig256("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
+ }
+ for _, test := range tests {
+ if result := Exp(test.base, test.exponent); result.Cmp(test.result) != 0 {
+ t.Errorf("Exp(%d, %d) = %d, want %d", test.base, test.exponent, result, test.result)
+ }
+ }
+}
diff --git a/common/math/dist.go b/common/math/dist.go
deleted file mode 100644
index 913fbfbd4..000000000
--- a/common/math/dist.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package math
-
-import (
- "math/big"
- "sort"
-
- "github.com/ethereum/go-ethereum/common"
-)
-
-type Summer interface {
- Sum(i int) *big.Int
- Len() int
-}
-
-func Sum(slice Summer) (sum *big.Int) {
- sum = new(big.Int)
-
- for i := 0; i < slice.Len(); i++ {
- sum.Add(sum, slice.Sum(i))
- }
- return
-}
-
-type Vector struct {
- Gas, Price *big.Int
-}
-
-type VectorsBy func(v1, v2 Vector) bool
-
-func (self VectorsBy) Sort(vectors []Vector) {
- bs := vectorSorter{
- vectors: vectors,
- by: self,
- }
- sort.Sort(bs)
-}
-
-type vectorSorter struct {
- vectors []Vector
- by func(v1, v2 Vector) bool
-}
-
-func (v vectorSorter) Len() int { return len(v.vectors) }
-func (v vectorSorter) Less(i, j int) bool { return v.by(v.vectors[i], v.vectors[j]) }
-func (v vectorSorter) Swap(i, j int) { v.vectors[i], v.vectors[j] = v.vectors[j], v.vectors[i] }
-
-func PriceSort(v1, v2 Vector) bool { return v1.Price.Cmp(v2.Price) < 0 }
-func GasSort(v1, v2 Vector) bool { return v1.Gas.Cmp(v2.Gas) < 0 }
-
-type vectorSummer struct {
- vectors []Vector
- by func(v Vector) *big.Int
-}
-
-type VectorSum func(v Vector) *big.Int
-
-func (v VectorSum) Sum(vectors []Vector) *big.Int {
- vs := vectorSummer{
- vectors: vectors,
- by: v,
- }
- return Sum(vs)
-}
-
-func (v vectorSummer) Len() int { return len(v.vectors) }
-func (v vectorSummer) Sum(i int) *big.Int { return v.by(v.vectors[i]) }
-
-func GasSum(v Vector) *big.Int { return v.Gas }
-
-var etherInWei = new(big.Rat).SetInt(common.String2Big("1000000000000000000"))
-
-func GasPrice(bp, gl, ep *big.Int) *big.Int {
- BP := new(big.Rat).SetInt(bp)
- GL := new(big.Rat).SetInt(gl)
- EP := new(big.Rat).SetInt(ep)
- GP := new(big.Rat).Quo(BP, GL)
- GP = GP.Quo(GP, EP)
-
- return GP.Mul(GP, etherInWei).Num()
-}
diff --git a/common/math/dist_test.go b/common/math/dist_test.go
deleted file mode 100644
index f5857b6f8..000000000
--- a/common/math/dist_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package math
-
-import (
- "fmt"
- "math/big"
- "testing"
-)
-
-type summer struct {
- numbers []*big.Int
-}
-
-func (s summer) Len() int { return len(s.numbers) }
-func (s summer) Sum(i int) *big.Int {
- return s.numbers[i]
-}
-
-func TestSum(t *testing.T) {
- summer := summer{numbers: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}}
- sum := Sum(summer)
- if sum.Cmp(big.NewInt(6)) != 0 {
- t.Errorf("got sum = %d, want 6", sum)
- }
-}
-
-func TestDist(t *testing.T) {
- var vectors = []Vector{
- {big.NewInt(1000), big.NewInt(1234)},
- {big.NewInt(500), big.NewInt(10023)},
- {big.NewInt(1034), big.NewInt(1987)},
- {big.NewInt(1034), big.NewInt(1987)},
- {big.NewInt(8983), big.NewInt(1977)},
- {big.NewInt(98382), big.NewInt(1887)},
- {big.NewInt(12398), big.NewInt(1287)},
- {big.NewInt(12398), big.NewInt(1487)},
- {big.NewInt(12398), big.NewInt(1987)},
- {big.NewInt(12398), big.NewInt(128)},
- {big.NewInt(12398), big.NewInt(1987)},
- {big.NewInt(1398), big.NewInt(187)},
- {big.NewInt(12328), big.NewInt(1927)},
- {big.NewInt(12398), big.NewInt(1987)},
- {big.NewInt(22398), big.NewInt(1287)},
- {big.NewInt(1370), big.NewInt(1981)},
- {big.NewInt(12398), big.NewInt(1957)},
- {big.NewInt(42198), big.NewInt(1987)},
- }
-
- VectorsBy(GasSort).Sort(vectors)
- fmt.Println(vectors)
-
- BP := big.NewInt(15)
- GL := big.NewInt(1000000)
- EP := big.NewInt(100)
- fmt.Println("BP", BP, "GL", GL, "EP", EP)
- GP := GasPrice(BP, GL, EP)
- fmt.Println("GP =", GP, "Wei per GU")
-
- S := len(vectors) / 4
- fmt.Println("L", len(vectors), "S", S)
- for i := 1; i <= S*4; i += S {
- fmt.Printf("T%d = %v\n", i, vectors[i])
- }
-
- g := VectorSum(GasSum).Sum(vectors)
- fmt.Printf("G = ∑g* (%v)\n", g)
-}
diff --git a/common/math/exp.go b/common/math/exp.go
deleted file mode 100644
index 113b76b39..000000000
--- a/common/math/exp.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package math
-
-import (
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
-)
-
-// wordSize is the size number of bits in a big.Int Word.
-const wordSize = 32 << (uint64(^big.Word(0)) >> 63)
-
-// Exp implement exponentiation by squaring algorithm.
-//
-// Exp return a new variable; base and exponent must
-// not be changed under any circumstance.
-//
-// Courtesy @karalabe and @chfast
-func Exp(base, exponent *big.Int) *big.Int {
- result := big.NewInt(1)
-
- for _, word := range exponent.Bits() {
- for i := 0; i < wordSize; i++ {
- if word&1 == 1 {
- common.U256(result.Mul(result, base))
- }
- common.U256(base.Mul(base, base))
- word >>= 1
- }
- }
- return result
-}
diff --git a/common/math/integer.go b/common/math/integer.go
index 1689b6586..a3eeee27e 100644
--- a/common/math/integer.go
+++ b/common/math/integer.go
@@ -1,10 +1,63 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
package math
-import gmath "math"
+import "strconv"
+
+const (
+ // Integer limit values.
+ MaxInt8 = 1<<7 - 1
+ MinInt8 = -1 << 7
+ MaxInt16 = 1<<15 - 1
+ MinInt16 = -1 << 15
+ MaxInt32 = 1<<31 - 1
+ MinInt32 = -1 << 31
+ MaxInt64 = 1<<63 - 1
+ MinInt64 = -1 << 63
+ MaxUint8 = 1<<8 - 1
+ MaxUint16 = 1<<16 - 1
+ MaxUint32 = 1<<32 - 1
+ MaxUint64 = 1<<64 - 1
+)
+
+// ParseUint64 parses s as an integer in decimal or hexadecimal syntax.
+// Leading zeros are accepted. The empty string parses as zero.
+func ParseUint64(s string) (uint64, bool) {
+ if s == "" {
+ return 0, true
+ }
+ if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
+ v, err := strconv.ParseUint(s[2:], 16, 64)
+ return v, err == nil
+ }
+ v, err := strconv.ParseUint(s, 10, 64)
+ return v, err == nil
+}
+
+// MustParseUint64 parses s as an integer and panics if the string is invalid.
+func MustParseUint64(s string) uint64 {
+ v, ok := ParseUint64(s)
+ if !ok {
+ panic("invalid unsigned 64 bit integer: " + s)
+ }
+ return v
+}
-/*
- * NOTE: The following methods need to be optimised using either bit checking or asm
- */
+// NOTE: The following methods need to be optimised using either bit checking or asm
// SafeSub returns subtraction result and whether overflow occurred.
func SafeSub(x, y uint64) (uint64, bool) {
@@ -13,7 +66,7 @@ func SafeSub(x, y uint64) (uint64, bool) {
// SafeAdd returns the result and whether overflow occurred.
func SafeAdd(x, y uint64) (uint64, bool) {
- return x + y, y > gmath.MaxUint64-x
+ return x + y, y > MaxUint64-x
}
// SafeMul returns multiplication result and whether overflow occurred.
@@ -21,5 +74,5 @@ func SafeMul(x, y uint64) (uint64, bool) {
if x == 0 || y == 0 {
return 0, false
}
- return x * y, y > gmath.MaxUint64/x
+ return x * y, y > MaxUint64/x
}
diff --git a/common/math/integer_test.go b/common/math/integer_test.go
index 198114e5e..05bba221f 100644
--- a/common/math/integer_test.go
+++ b/common/math/integer_test.go
@@ -1,7 +1,22 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
package math
import (
- gmath "math"
"testing"
)
@@ -21,17 +36,18 @@ func TestOverflow(t *testing.T) {
op operation
}{
// add operations
- {gmath.MaxUint64, 1, true, add},
- {gmath.MaxUint64 - 1, 1, false, add},
+ {MaxUint64, 1, true, add},
+ {MaxUint64 - 1, 1, false, add},
// sub operations
{0, 1, true, sub},
{0, 0, false, sub},
// mul operations
+ {0, 0, false, mul},
{10, 10, false, mul},
- {gmath.MaxUint64, 2, true, mul},
- {gmath.MaxUint64, 1, false, mul},
+ {MaxUint64, 2, true, mul},
+ {MaxUint64, 1, false, mul},
} {
var overflows bool
switch test.op {
@@ -48,3 +64,52 @@ func TestOverflow(t *testing.T) {
}
}
}
+
+func TestParseUint64(t *testing.T) {
+ tests := []struct {
+ input string
+ num uint64
+ ok bool
+ }{
+ {"", 0, true},
+ {"0", 0, true},
+ {"0x0", 0, true},
+ {"12345678", 12345678, true},
+ {"0x12345678", 0x12345678, true},
+ {"0X12345678", 0x12345678, true},
+ // Tests for leading zero behaviour:
+ {"0123456789", 123456789, true}, // note: not octal
+ {"0x00", 0, true},
+ {"0x012345678abc", 0x12345678abc, true},
+ // Invalid syntax:
+ {"abcdef", 0, false},
+ {"0xgg", 0, false},
+ // Doesn't fit into 64 bits:
+ {"18446744073709551617", 0, false},
+ }
+ for _, test := range tests {
+ num, ok := ParseUint64(test.input)
+ if ok != test.ok {
+ t.Errorf("ParseUint64(%q) -> ok = %t, want %t", test.input, ok, test.ok)
+ continue
+ }
+ if ok && num != test.num {
+ t.Errorf("ParseUint64(%q) -> %d, want %d", test.input, num, test.num)
+ }
+ }
+}
+
+func TestMustParseUint64(t *testing.T) {
+ if v := MustParseUint64("12345"); v != 12345 {
+ t.Errorf(`MustParseUint64("12345") = %d, want 12345`, v)
+ }
+}
+
+func TestMustParseUint64Panic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Error("MustParseBig should've panicked")
+ }
+ }()
+ MustParseUint64("ggg")
+}