From 7061ab8d89110fe6992bb6d4c9c4103319537fae Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 21 Feb 2017 15:18:32 +0100 Subject: [PATCH] common: move big integer operations to common/math This commit consolidates all big integer operations into common/math and adds tests and documentation. There should be no change in semantics for BigPow, BigMin, BigMax, S256, U256, Exp and their behaviour is now locked in by tests. The BigD, BytesToBig and Bytes2Big functions don't provide additional value, all uses are replaced by new(big.Int).SetBytes(). BigToBytes is now called PaddedBigBytes, its minimum output size parameter is now specified as the number of bytes instead of bits. The single use of this function is in the EVM's MSTORE instruction. Big and String2Big are replaced by ParseBig, which is slightly stricter. It previously accepted leading zeros for hexadecimal inputs but treated decimal inputs as octal if a leading zero digit was present. ParseUint64 is used in places where String2Big was used to decode a uint64. The new functions MustParseBig and MustParseUint64 are now used in many places where parsing errors were previously ignored. --- accounts/abi/bind/backends/simulated.go | 5 +- accounts/abi/numbers.go | 3 +- cmd/evm/main.go | 13 +- common/big.go | 111 +------------- common/big_test.go | 89 ----------- common/math/big.go | 136 +++++++++++++++++ common/math/big_test.go | 194 ++++++++++++++++++++++++ common/math/dist.go | 96 ------------ common/math/dist_test.go | 82 ---------- common/math/exp.go | 47 ------ common/math/integer.go | 65 +++++++- common/math/integer_test.go | 75 ++++++++- core/bench_test.go | 3 +- core/block_validator.go | 9 +- core/database_util_test.go | 11 +- core/state_transition.go | 3 +- core/vm/common.go | 11 +- core/vm/instructions.go | 50 +++--- core/vm/memory_table.go | 8 +- crypto/crypto.go | 2 +- eth/api_backend.go | 3 +- internal/ethapi/api.go | 4 +- les/api_backend.go | 3 +- les/odr_test.go | 9 +- light/odr_test.go | 9 +- tests/state_test_util.go | 9 +- tests/transaction_test_util.go | 3 +- tests/util.go | 21 +-- tests/vm_test_util.go | 7 +- whisper/whisperv2/envelope.go | 5 +- whisper/whisperv5/envelope.go | 18 ++- 31 files changed, 575 insertions(+), 529 deletions(-) delete mode 100644 common/big_test.go create mode 100644 common/math/big.go create mode 100644 common/math/big_test.go delete mode 100644 common/math/dist.go delete mode 100644 common/math/dist_test.go delete mode 100644 common/math/exp.go diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 1c34ba0e79..5e2fcbae76 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -244,7 +245,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM } // Set infinite balance to the fake caller account. from := statedb.GetOrNewStateObject(call.From) - from.SetBalance(common.MaxBig) + from.SetBalance(math.MaxBig256) // Execute the call. msg := callmsg{call} @@ -252,7 +253,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{}) - gaspool := new(core.GasPool).AddGas(common.MaxBig) + gaspool := new(core.GasPool).AddGas(math.MaxBig256) ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() return ret, gasUsed, err } diff --git a/accounts/abi/numbers.go b/accounts/abi/numbers.go index 3d58422925..36fb6705e6 100644 --- a/accounts/abi/numbers.go +++ b/accounts/abi/numbers.go @@ -21,6 +21,7 @@ import ( "reflect" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" ) var ( @@ -58,7 +59,7 @@ var ( // U256 converts a big Int into a 256bit EVM number. func U256(n *big.Int) []byte { - return common.LeftPadBytes(common.U256(n).Bytes(), 32) + return common.LeftPadBytes(math.U256(n).Bytes(), 32) } // packNum packs the given number (using the reflect value) and will cast it to appropriate number representation diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 86e2493ca1..6c4b44220c 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm/runtime" @@ -160,9 +161,9 @@ func run(ctx *cli.Context) error { ret, _, err = runtime.Create(input, &runtime.Config{ Origin: sender.Address(), State: statedb, - GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(), - GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), - Value: common.Big(ctx.GlobalString(ValueFlag.Name)), + GasLimit: math.MustParseUint64(ctx.GlobalString(GasFlag.Name)), + GasPrice: math.MustParseBig(ctx.GlobalString(PriceFlag.Name)), + Value: math.MustParseBig(ctx.GlobalString(ValueFlag.Name)), EVMConfig: vm.Config{ Tracer: logger, Debug: ctx.GlobalBool(DebugFlag.Name), @@ -177,9 +178,9 @@ func run(ctx *cli.Context) error { ret, err = runtime.Call(receiverAddress, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ Origin: sender.Address(), State: statedb, - GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(), - GasPrice: common.Big(ctx.GlobalString(PriceFlag.Name)), - Value: common.Big(ctx.GlobalString(ValueFlag.Name)), + GasLimit: math.MustParseUint64(ctx.GlobalString(GasFlag.Name)), + GasPrice: math.MustParseBig(ctx.GlobalString(PriceFlag.Name)), + Value: math.MustParseBig(ctx.GlobalString(ValueFlag.Name)), EVMConfig: vm.Config{ Tracer: logger, Debug: ctx.GlobalBool(DebugFlag.Name), diff --git a/common/big.go b/common/big.go index 4ce87ee0c6..fb5a1da130 100644 --- a/common/big.go +++ b/common/big.go @@ -32,125 +32,22 @@ var ( Big98 = big.NewInt(98) Big256 = big.NewInt(0xff) Big257 = big.NewInt(257) - MaxBig = String2Big("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") ) -// Big pow -// -// Returns the power of two big integers -func BigPow(a, b int) *big.Int { - c := new(big.Int) - c.Exp(big.NewInt(int64(a)), big.NewInt(int64(b)), big.NewInt(0)) - - return c -} - -// Big -// -// Shortcut for new(big.Int).SetString(..., 0) -func Big(num string) *big.Int { - n := new(big.Int) - n.SetString(num, 0) - - return n -} - // Bytes2Big -// func BytesToBig(data []byte) *big.Int { n := new(big.Int) n.SetBytes(data) return n } -func Bytes2Big(data []byte) *big.Int { return BytesToBig(data) } -func BigD(data []byte) *big.Int { return BytesToBig(data) } + +func Bytes2Big(data []byte) *big.Int { + return BytesToBig(data) +} func String2Big(num string) *big.Int { n := new(big.Int) n.SetString(num, 0) return n } - -func BitTest(num *big.Int, i int) bool { - return num.Bit(i) > 0 -} - -// To256 -// -// "cast" the big int to a 256 big int (i.e., limit to) -var tt256 = new(big.Int).Lsh(big.NewInt(1), 256) -var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) -var tt255 = new(big.Int).Lsh(big.NewInt(1), 255) - -func U256(x *big.Int) *big.Int { - //if x.Cmp(Big0) < 0 { - // return new(big.Int).Add(tt256, x) - // } - - x.And(x, tt256m1) - - return x -} - -func S256(x *big.Int) *big.Int { - if x.Cmp(tt255) < 0 { - return x - } else { - // We don't want to modify x, ever - return new(big.Int).Sub(x, tt256) - } -} - -func FirstBitSet(v *big.Int) int { - for i := 0; i < v.BitLen(); i++ { - if v.Bit(i) > 0 { - return i - } - } - - return v.BitLen() -} - -// Big to bytes -// -// Returns the bytes of a big integer with the size specified by **base** -// Attempts to pad the byte array with zeros. -func BigToBytes(num *big.Int, base int) []byte { - ret := make([]byte, base/8) - - if len(num.Bytes()) > base/8 { - return num.Bytes() - } - - return append(ret[:len(ret)-len(num.Bytes())], num.Bytes()...) -} - -// Big copy -// -// Creates a copy of the given big integer -func BigCopy(src *big.Int) *big.Int { - return new(big.Int).Set(src) -} - -// Big max -// -// Returns the maximum size big integer -func BigMax(x, y *big.Int) *big.Int { - if x.Cmp(y) < 0 { - return y - } - - return x -} - -// Big min -// -// Returns the minimum size big integer -func BigMin(x, y *big.Int) *big.Int { - if x.Cmp(y) > 0 { - return y - } - - return x -} diff --git a/common/big_test.go b/common/big_test.go deleted file mode 100644 index 4d04a8db36..0000000000 --- a/common/big_test.go +++ /dev/null @@ -1,89 +0,0 @@ -// 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 . - -package common - -import ( - "bytes" - "testing" -) - -func TestMisc(t *testing.T) { - a := Big("10") - b := Big("57896044618658097711785492504343953926634992332820282019728792003956564819968") - c := []byte{1, 2, 3, 4} - z := BitTest(a, 1) - - if !z { - t.Error("Expected true got", z) - } - - U256(a) - S256(a) - - U256(b) - S256(b) - - BigD(c) -} - -func TestBigMax(t *testing.T) { - a := Big("10") - b := Big("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("10") - b := Big("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 TestBigCopy(t *testing.T) { - a := Big("10") - b := BigCopy(a) - c := Big("1000000000000") - y := BigToBytes(b, 16) - ybytes := []byte{0, 10} - z := BigToBytes(c, 16) - zbytes := []byte{232, 212, 165, 16, 0} - - if !bytes.Equal(y, ybytes) { - t.Error("Got", ybytes) - } - - if !bytes.Equal(z, zbytes) { - t.Error("Got", zbytes) - } -} diff --git a/common/math/big.go b/common/math/big.go new file mode 100644 index 0000000000..130a0615c9 --- /dev/null +++ b/common/math/big.go @@ -0,0 +1,136 @@ +// 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 . + +// 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) +) + +// ParseBig parses s as a big integer in decimal or hexadecimal syntax. +// Leading zeros are accepted. The empty string parses as zero. +func ParseBig(s string) (*big.Int, bool) { + if s == "" { + return new(big.Int), true + } + if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") { + return new(big.Int).SetString(s[2:], 16) + } + return new(big.Int).SetString(s, 10) +} + +// MustParseBig parses s as a big integer and panics if the string is invalid. +func MustParseBig(s string) *big.Int { + v, ok := ParseBig(s) + if !ok { + panic("invalid 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 0000000000..29727ce192 --- /dev/null +++ b/common/math/big_test.go @@ -0,0 +1,194 @@ +// 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 . + +package math + +import ( + "bytes" + "math/big" + "testing" +) + +func TestParseBig(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}, + } + for _, test := range tests { + num, ok := ParseBig(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 TestMustParseBig(t *testing.T) { + defer func() { + if recover() == nil { + t.Error("MustParseBig should've panicked") + } + }() + MustParseBig("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: MustParseBig("507528786056415600719754159741696356908742250191663887263627442114881")}, + {base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig("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 913fbfbd47..0000000000 --- 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 . - -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 f5857b6f80..0000000000 --- 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 . - -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 113b76b39b..0000000000 --- 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 . - -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 1689b65864..a3eeee27e7 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 . + package math -import gmath "math" +import "strconv" -/* - * NOTE: The following methods need to be optimised using either bit checking or asm - */ +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 // 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 198114e5e1..05bba221f9 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 . + 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") +} diff --git a/core/bench_test.go b/core/bench_test.go index 59b5ad7589..8a16005579 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -24,6 +24,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -73,7 +74,7 @@ var ( // This is the content of the genesis block used by the benchmarks. benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey) - benchRootFunds = common.BigPow(2, 100) + benchRootFunds = math.BigPow(2, 100) ) // genValueTx returns a block generator that includes a single diff --git a/core/block_validator.go b/core/block_validator.go index a23a4134b1..117974ee66 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -22,6 +22,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" @@ -209,7 +210,7 @@ func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Heade } if uncle { - if header.Time.Cmp(common.MaxBig) == 1 { + if header.Time.Cmp(math.MaxBig256) == 1 { return BlockTSTooBigErr } } else { @@ -344,7 +345,7 @@ func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *b expDiff := periodCount.Sub(periodCount, common.Big2) expDiff.Exp(common.Big2, expDiff, nil) diff.Add(diff, expDiff) - diff = common.BigMax(diff, params.MinimumDifficulty) + diff = math.BigMax(diff, params.MinimumDifficulty) } return diff @@ -372,13 +373,13 @@ func CalcGasLimit(parent *types.Block) *big.Int { */ gl := new(big.Int).Sub(parent.GasLimit(), decay) gl = gl.Add(gl, contrib) - gl.Set(common.BigMax(gl, params.MinGasLimit)) + gl.Set(math.BigMax(gl, params.MinGasLimit)) // however, if we're now below the target (TargetGasLimit) we increase the // limit as much as we can (parentGasLimit / 1024 -1) if gl.Cmp(params.TargetGasLimit) < 0 { gl.Add(parent.GasLimit(), decay) - gl.Set(common.BigMin(gl, params.TargetGasLimit)) + gl.Set(math.BigMin(gl, params.TargetGasLimit)) } return gl } diff --git a/core/database_util_test.go b/core/database_util_test.go index d96aa71ba8..8628fa483f 100644 --- a/core/database_util_test.go +++ b/core/database_util_test.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/sha3" @@ -53,11 +54,11 @@ func (d *diffTest) UnmarshalJSON(b []byte) (err error) { return err } - d.ParentTimestamp = common.String2Big(ext.ParentTimestamp).Uint64() - d.ParentDifficulty = common.String2Big(ext.ParentDifficulty) - d.CurrentTimestamp = common.String2Big(ext.CurrentTimestamp).Uint64() - d.CurrentBlocknumber = common.String2Big(ext.CurrentBlocknumber) - d.CurrentDifficulty = common.String2Big(ext.CurrentDifficulty) + d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp) + d.ParentDifficulty = math.MustParseBig(ext.ParentDifficulty) + d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp) + d.CurrentBlocknumber = math.MustParseBig(ext.CurrentBlocknumber) + d.CurrentDifficulty = math.MustParseBig(ext.CurrentDifficulty) return nil } diff --git a/core/state_transition.go b/core/state_transition.go index 8e7891b965..98a24af2b2 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -22,6 +22,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -281,7 +282,7 @@ func (self *StateTransition) refundGas() { // Apply refund counter, capped to half of the used gas. uhalf := remaining.Div(self.gasUsed(), common.Big2) - refund := common.BigMin(uhalf, self.state.GetRefund()) + refund := math.BigMin(uhalf, self.state.GetRefund()) self.gas += refund.Uint64() self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice)) diff --git a/core/vm/common.go b/core/vm/common.go index b7b9a6a9c7..f6a30bd15e 100644 --- a/core/vm/common.go +++ b/core/vm/common.go @@ -17,15 +17,10 @@ package vm import ( - "math" "math/big" "github.com/ethereum/go-ethereum/common" -) - -var ( - U256 = common.U256 // Shortcut to common.U256 - S256 = common.S256 // Shortcut to common.S256 + "github.com/ethereum/go-ethereum/common/math" ) // calculates the memory size required for a step @@ -42,8 +37,8 @@ func calcMemSize(off, l *big.Int) *big.Int { func getData(data []byte, start, size *big.Int) []byte { dlen := big.NewInt(int64(len(data))) - s := common.BigMin(start, dlen) - e := common.BigMin(new(big.Int).Add(s, size), dlen) + s := math.BigMin(start, dlen) + e := math.BigMin(new(big.Int).Add(s, size), dlen) return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64())) } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 39e5c05870..fb49b5130a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -31,7 +31,7 @@ var bigZero = new(big.Int) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() - stack.push(U256(x.Add(x, y))) + stack.push(math.U256(x.Add(x, y))) evm.interpreter.intPool.put(y) @@ -40,7 +40,7 @@ func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() - stack.push(U256(x.Sub(x, y))) + stack.push(math.U256(x.Sub(x, y))) evm.interpreter.intPool.put(y) @@ -49,7 +49,7 @@ func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() - stack.push(U256(x.Mul(x, y))) + stack.push(math.U256(x.Mul(x, y))) evm.interpreter.intPool.put(y) @@ -59,7 +59,7 @@ func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Cmp(common.Big0) != 0 { - stack.push(U256(x.Div(x, y))) + stack.push(math.U256(x.Div(x, y))) } else { stack.push(new(big.Int)) } @@ -70,7 +70,7 @@ func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac } func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := S256(stack.pop()), S256(stack.pop()) + x, y := math.S256(stack.pop()), math.S256(stack.pop()) if y.Cmp(common.Big0) == 0 { stack.push(new(big.Int)) return nil, nil @@ -85,7 +85,7 @@ func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta res := x.Div(x.Abs(x), y.Abs(y)) res.Mul(res, n) - stack.push(U256(res)) + stack.push(math.U256(res)) } evm.interpreter.intPool.put(y) return nil, nil @@ -96,14 +96,14 @@ func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac if y.Cmp(common.Big0) == 0 { stack.push(new(big.Int)) } else { - stack.push(U256(x.Mod(x, y))) + stack.push(math.U256(x.Mod(x, y))) } evm.interpreter.intPool.put(y) return nil, nil } func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := S256(stack.pop()), S256(stack.pop()) + x, y := math.S256(stack.pop()), math.S256(stack.pop()) if y.Cmp(common.Big0) == 0 { stack.push(new(big.Int)) @@ -118,7 +118,7 @@ func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta res := x.Mod(x.Abs(x), y.Abs(y)) res.Mul(res, n) - stack.push(U256(res)) + stack.push(math.U256(res)) } evm.interpreter.intPool.put(y) return nil, nil @@ -140,13 +140,13 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac num := stack.pop() mask := back.Lsh(common.Big1, bit) mask.Sub(mask, common.Big1) - if common.BitTest(num, int(bit)) { + if num.Bit(int(bit)) > 0 { num.Or(num, mask.Not(mask)) } else { num.And(num, mask) } - stack.push(U256(num)) + stack.push(math.U256(num)) } evm.interpreter.intPool.put(back) @@ -155,7 +155,7 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x := stack.pop() - stack.push(U256(x.Not(x))) + stack.push(math.U256(x.Not(x))) return nil, nil } @@ -184,8 +184,8 @@ func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack } func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := S256(stack.pop()), S256(stack.pop()) - if x.Cmp(S256(y)) < 0 { + x, y := math.S256(stack.pop()), math.S256(stack.pop()) + if x.Cmp(math.S256(y)) < 0 { stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) @@ -196,7 +196,7 @@ func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac } func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - x, y := S256(stack.pop()), S256(stack.pop()) + x, y := math.S256(stack.pop()), math.S256(stack.pop()) if x.Cmp(y) > 0 { stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { @@ -269,7 +269,7 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S if z.Cmp(bigZero) > 0 { add := x.Add(x, y) add.Mod(add, z) - stack.push(U256(add)) + stack.push(math.U256(add)) } else { stack.push(new(big.Int)) } @@ -282,7 +282,7 @@ func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S if z.Cmp(bigZero) > 0 { mul := x.Mul(x, y) mul.Mod(mul, z) - stack.push(U256(mul)) + stack.push(math.U256(mul)) } else { stack.push(new(big.Int)) } @@ -427,22 +427,22 @@ func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack } func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(evm.Time))) + stack.push(math.U256(new(big.Int).Set(evm.Time))) return nil, nil } func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(evm.BlockNumber))) + stack.push(math.U256(new(big.Int).Set(evm.BlockNumber))) return nil, nil } func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(evm.Difficulty))) + stack.push(math.U256(new(big.Int).Set(evm.Difficulty))) return nil, nil } func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(evm.GasLimit))) + stack.push(math.U256(new(big.Int).Set(evm.GasLimit))) return nil, nil } @@ -453,7 +453,7 @@ func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset := stack.pop() - val := common.BigD(memory.Get(offset.Int64(), 32)) + val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32)) stack.push(val) evm.interpreter.intPool.put(offset) @@ -463,7 +463,7 @@ func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // pop value of the stack mStart, val := stack.pop(), stack.pop() - memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256)) + memory.Set(mStart.Uint64(), 32, math.PaddedBigBytes(val, 32)) evm.interpreter.intPool.put(mStart, val) return nil, nil @@ -572,7 +572,7 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta gas := stack.pop().Uint64() // pop gas and value of the stack. addr, value := stack.pop(), stack.pop() - value = U256(value) + value = math.U256(value) // pop input size and offset inOffset, inSize := stack.pop(), stack.pop() // pop return size and offset @@ -605,7 +605,7 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack gas := stack.pop().Uint64() // pop gas and value of the stack. addr, value := stack.pop(), stack.pop() - value = U256(value) + value = math.U256(value) // pop input size and offset inOffset, inSize := stack.pop(), stack.pop() // pop return size and offset diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 4db9948375..3141a2f61a 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -3,7 +3,7 @@ package vm import ( "math/big" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" ) func memorySha3(stack *Stack) *big.Int { @@ -42,20 +42,20 @@ func memoryCall(stack *Stack) *big.Int { x := calcMemSize(stack.Back(5), stack.Back(6)) y := calcMemSize(stack.Back(3), stack.Back(4)) - return common.BigMax(x, y) + return math.BigMax(x, y) } func memoryCallCode(stack *Stack) *big.Int { x := calcMemSize(stack.Back(5), stack.Back(6)) y := calcMemSize(stack.Back(3), stack.Back(4)) - return common.BigMax(x, y) + return math.BigMax(x, y) } func memoryDelegateCall(stack *Stack) *big.Int { x := calcMemSize(stack.Back(4), stack.Back(5)) y := calcMemSize(stack.Back(2), stack.Back(3)) - return common.BigMax(x, y) + return math.BigMax(x, y) } func memoryReturn(stack *Stack) *big.Int { diff --git a/crypto/crypto.go b/crypto/crypto.go index 9d67d82e1d..ecc3be3ce5 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -71,7 +71,7 @@ func ToECDSA(prv []byte) *ecdsa.PrivateKey { priv := new(ecdsa.PrivateKey) priv.PublicKey.Curve = S256() - priv.D = common.BigD(prv) + priv.D = new(big.Int).SetBytes(prv) priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(prv) return priv } diff --git a/eth/api_backend.go b/eth/api_backend.go index 72ed76cc4a..5a5c4c532e 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -109,7 +110,7 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int { func (b *EthApiBackend) GetEVM(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) { statedb := state.(EthApiState).state from := statedb.GetOrNewStateObject(msg.From()) - from.SetBalance(common.MaxBig) + from.SetBalance(math.MaxBig256) vmError := func() error { return nil } context := core.NewEVMContext(msg, header, b.eth.BlockChain()) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b3d606b5e4..8f4bde4719 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -21,7 +21,6 @@ import ( "encoding/hex" "errors" "fmt" - "math" "math/big" "strings" "time" @@ -31,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -634,7 +634,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Setup the gas pool (also for unmetered requests) // and apply the message. - gp := new(core.GasPool).AddGas(common.MaxBig) + gp := new(core.GasPool).AddGas(math.MaxBig256) res, gas, err := core.ApplyMessage(evm, msg, gp) if err := vmError(); err != nil { return nil, common.Big0, err diff --git a/les/api_backend.go b/les/api_backend.go index ed2a7cd13e..264b381f51 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -95,7 +96,7 @@ func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state etha if err != nil { return nil, nil, err } - from.SetBalance(common.MaxBig) + from.SetBalance(math.MaxBig256) vmstate := light.NewVMState(ctx, stateDb) context := core.NewEVMContext(msg, header, b.eth.blockchain) diff --git a/les/odr_test.go b/les/odr_test.go index 622d89e5c7..4f1fccb248 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -118,7 +119,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai if err == nil { from := statedb.GetOrNewStateObject(testBankAddress) - from.SetBalance(common.MaxBig) + from.SetBalance(math.MaxBig256) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)} @@ -126,7 +127,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) - gp := new(core.GasPool).AddGas(common.MaxBig) + gp := new(core.GasPool).AddGas(math.MaxBig256) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) } @@ -136,7 +137,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai vmstate := light.NewVMState(ctx, state) from, err := state.GetOrNewStateObject(ctx, testBankAddress) if err == nil { - from.SetBalance(common.MaxBig) + from.SetBalance(math.MaxBig256) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)} @@ -144,7 +145,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai vmenv := vm.NewEVM(context, vmstate, config, vm.Config{}) //vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{}) - gp := new(core.GasPool).AddGas(common.MaxBig) + gp := new(core.GasPool).AddGas(math.MaxBig256) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) if vmstate.Error() == nil { res = append(res, ret...) diff --git a/light/odr_test.go b/light/odr_test.go index a76050a299..6987db6440 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -169,14 +170,14 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain statedb, err := state.New(header.Root, db) if err == nil { from := statedb.GetOrNewStateObject(testBankAddress) - from.SetBalance(common.MaxBig) + from.SetBalance(math.MaxBig256) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)} context := core.NewEVMContext(msg, header, bc) vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) - gp := new(core.GasPool).AddGas(common.MaxBig) + gp := new(core.GasPool).AddGas(math.MaxBig256) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) } @@ -186,12 +187,12 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain vmstate := NewVMState(ctx, state) from, err := state.GetOrNewStateObject(ctx, testBankAddress) if err == nil { - from.SetBalance(common.MaxBig) + from.SetBalance(math.MaxBig256) msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)} context := core.NewEVMContext(msg, header, lc) vmenv := vm.NewEVM(context, vmstate, config, vm.Config{}) - gp := new(core.GasPool).AddGas(common.MaxBig) + gp := new(core.GasPool).AddGas(math.MaxBig256) ret, _, _ := core.ApplyMessage(vmenv, msg, gp) if vmstate.Error() == nil { res = append(res, ret...) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 064bf45886..a5963ed89a 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -26,6 +26,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -170,11 +171,11 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error { return fmt.Errorf("did not find expected post-state account: %s", addr) } - if balance := statedb.GetBalance(address); balance.Cmp(common.Big(account.Balance)) != 0 { - return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], common.String2Big(account.Balance), balance) + if balance := statedb.GetBalance(address); balance.Cmp(math.MustParseBig(account.Balance)) != 0 { + return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], math.MustParseBig(account.Balance), balance) } - if nonce := statedb.GetNonce(address); nonce != common.String2Big(account.Nonce).Uint64() { + if nonce := statedb.GetNonce(address); nonce != math.MustParseUint64(account.Nonce) { return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", address[:4], account.Nonce, nonce) } @@ -205,7 +206,7 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error { func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx map[string]string) ([]byte, []*types.Log, *big.Int, error) { environment, msg := NewEVMEnvironment(false, chainConfig, statedb, env, tx) - gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"])) + gaspool := new(core.GasPool).AddGas(math.MustParseBig(env["currentGasLimit"])) root, _ := statedb.Commit(false) statedb.Reset(root) diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index d267258673..854971b0f3 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -24,6 +24,7 @@ import ( "runtime" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -161,7 +162,7 @@ func verifyTxFields(chainConfig *params.ChainConfig, txTest TransactionTest, dec var decodedSender common.Address - signer := types.MakeSigner(chainConfig, common.String2Big(txTest.Blocknumber)) + signer := types.MakeSigner(chainConfig, math.MustParseBig(txTest.Blocknumber)) decodedSender, err = types.Sender(signer, decodedTx) if err != nil { return err diff --git a/tests/util.go b/tests/util.go index c96c2e06dc..887adadd7d 100644 --- a/tests/util.go +++ b/tests/util.go @@ -24,6 +24,7 @@ import ( "os" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -119,8 +120,8 @@ func insertAccount(state *state.StateDB, saddr string, account Account) { } addr := common.HexToAddress(saddr) state.SetCode(addr, common.Hex2Bytes(account.Code)) - state.SetNonce(addr, common.Big(account.Nonce).Uint64()) - state.SetBalance(addr, common.Big(account.Balance)) + state.SetNonce(addr, math.MustParseUint64(account.Nonce)) + state.SetBalance(addr, math.MustParseBig(account.Balance)) for a, v := range account.Storage { state.SetState(addr, common.HexToHash(a), common.HexToHash(v)) } @@ -152,10 +153,10 @@ type VmTest struct { func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *state.StateDB, envValues map[string]string, tx map[string]string) (*vm.EVM, core.Message) { var ( data = common.FromHex(tx["data"]) - gas = common.Big(tx["gasLimit"]) - price = common.Big(tx["gasPrice"]) - value = common.Big(tx["value"]) - nonce = common.Big(tx["nonce"]).Uint64() + gas = math.MustParseBig(tx["gasLimit"]) + price = math.MustParseBig(tx["gasPrice"]) + value = math.MustParseBig(tx["value"]) + nonce = math.MustParseUint64(tx["nonce"]) ) origin := common.HexToAddress(tx["caller"]) @@ -198,10 +199,10 @@ func NewEVMEnvironment(vmTest bool, chainConfig *params.ChainConfig, statedb *st Origin: origin, Coinbase: common.HexToAddress(envValues["currentCoinbase"]), - BlockNumber: common.Big(envValues["currentNumber"]), - Time: common.Big(envValues["currentTimestamp"]), - GasLimit: common.Big(envValues["currentGasLimit"]), - Difficulty: common.Big(envValues["currentDifficulty"]), + BlockNumber: math.MustParseBig(envValues["currentNumber"]), + Time: math.MustParseBig(envValues["currentTimestamp"]), + GasLimit: math.MustParseBig(envValues["currentGasLimit"]), + Difficulty: math.MustParseBig(envValues["currentDifficulty"]), GasPrice: price, } if context.GasPrice == nil { diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 4bf2dbfe98..9c72221510 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -180,7 +181,7 @@ func runVmTest(test VmTest) error { if len(test.Gas) == 0 && err == nil { return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful") } else { - gexp := common.Big(test.Gas) + gexp := math.MustParseBig(test.Gas) if gexp.Cmp(gas) != 0 { return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas) } @@ -222,8 +223,8 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type to = common.HexToAddress(exec["address"]) from = common.HexToAddress(exec["caller"]) data = common.FromHex(exec["data"]) - gas = common.Big(exec["gas"]) - value = common.Big(exec["value"]) + gas = math.MustParseBig(exec["gas"]) + value = math.MustParseBig(exec["value"]) ) caller := statedb.GetOrNewStateObject(from) vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract) diff --git a/whisper/whisperv2/envelope.go b/whisper/whisperv2/envelope.go index 7110ab4571..9f1c682040 100644 --- a/whisper/whisperv2/envelope.go +++ b/whisper/whisperv2/envelope.go @@ -23,9 +23,11 @@ import ( "crypto/ecdsa" "encoding/binary" "fmt" + "math/big" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/rlp" @@ -66,7 +68,8 @@ func (self *Envelope) Seal(pow time.Duration) { for i := 0; i < 1024; i++ { binary.BigEndian.PutUint32(d[60:], nonce) - firstBit := common.FirstBitSet(common.BigD(crypto.Keccak256(d))) + d := new(big.Int).SetBytes(crypto.Keccak256(d)) + firstBit := math.FirstBitSet(d) if firstBit > bestBit { self.Nonce, bestBit = nonce, firstBit } diff --git a/whisper/whisperv5/envelope.go b/whisper/whisperv5/envelope.go index 8812ae207f..5d882d5dc2 100644 --- a/whisper/whisperv5/envelope.go +++ b/whisper/whisperv5/envelope.go @@ -23,10 +23,12 @@ import ( "encoding/binary" "errors" "fmt" - "math" + gmath "math" + "math/big" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" "github.com/ethereum/go-ethereum/rlp" @@ -103,8 +105,8 @@ func (e *Envelope) Seal(options *MessageParams) error { for nonce := uint64(0); time.Now().UnixNano() < finish; { for i := 0; i < 1024; i++ { binary.BigEndian.PutUint64(buf[56:], nonce) - h = crypto.Keccak256(buf) - firstBit := common.FirstBitSet(common.BigD(h)) + d := new(big.Int).SetBytes(crypto.Keccak256(buf)) + firstBit := math.FirstBitSet(d) if firstBit > bestBit { e.EnvNonce, bestBit = nonce, firstBit if target > 0 && bestBit >= target { @@ -138,9 +140,9 @@ func (e *Envelope) calculatePoW(diff uint32) { h := crypto.Keccak256(e.rlpWithoutNonce()) copy(buf[:32], h) binary.BigEndian.PutUint64(buf[56:], e.EnvNonce) - h = crypto.Keccak256(buf) - firstBit := common.FirstBitSet(common.BigD(h)) - x := math.Pow(2, float64(firstBit)) + d := new(big.Int).SetBytes(crypto.Keccak256(buf)) + firstBit := math.FirstBitSet(d) + x := gmath.Pow(2, float64(firstBit)) x /= float64(e.size()) x /= float64(e.TTL + diff) e.pow = x @@ -150,8 +152,8 @@ func (e *Envelope) powToFirstBit(pow float64) int { x := pow x *= float64(e.size()) x *= float64(e.TTL) - bits := math.Log2(x) - bits = math.Ceil(bits) + bits := gmath.Log2(x) + bits = gmath.Ceil(bits) return int(bits) }