aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2016-11-28 19:29:16 +0800
committerGitHub <noreply@github.com>2016-11-28 19:29:16 +0800
commit8d0108fc5df81c71010b9dfb11a5db5658fcb80a (patch)
treeef60472426e44d6c31ca4fac123a8c872296c0e1
parentba41efa8a0365912ab26b24cb4ac46153e774d4f (diff)
parent91bceb4acee23b1c92b288dd3a301a98eba9f4d3 (diff)
downloadgo-tangerine-8d0108fc5df81c71010b9dfb11a5db5658fcb80a.tar
go-tangerine-8d0108fc5df81c71010b9dfb11a5db5658fcb80a.tar.gz
go-tangerine-8d0108fc5df81c71010b9dfb11a5db5658fcb80a.tar.bz2
go-tangerine-8d0108fc5df81c71010b9dfb11a5db5658fcb80a.tar.lz
go-tangerine-8d0108fc5df81c71010b9dfb11a5db5658fcb80a.tar.xz
go-tangerine-8d0108fc5df81c71010b9dfb11a5db5658fcb80a.tar.zst
go-tangerine-8d0108fc5df81c71010b9dfb11a5db5658fcb80a.zip
Merge pull request #3355 from fjl/hexutil-2
Improve hex encoding/decoding
-rw-r--r--accounts/addrcache.go9
-rw-r--r--common/hexutil/hexutil.go232
-rw-r--r--common/hexutil/hexutil_test.go186
-rw-r--r--common/hexutil/json.go271
-rw-r--r--common/hexutil/json_test.go258
-rw-r--r--common/types.go58
-rw-r--r--common/types_test.go32
-rw-r--r--core/types/block.go37
-rw-r--r--core/types/bloom9.go13
-rw-r--r--core/types/json.go108
-rw-r--r--core/types/json_test.go232
-rw-r--r--core/types/receipt.go9
-rw-r--r--core/types/transaction.go33
-rw-r--r--core/vm/log.go48
-rw-r--r--core/vm/log_test.go3
-rw-r--r--eth/filters/api.go91
-rw-r--r--ethclient/ethclient.go71
17 files changed, 1125 insertions, 566 deletions
diff --git a/accounts/addrcache.go b/accounts/addrcache.go
index 0a904f788..a99f23606 100644
--- a/accounts/addrcache.go
+++ b/accounts/addrcache.go
@@ -225,7 +225,7 @@ func (ac *addrCache) scan() ([]Account, error) {
buf = new(bufio.Reader)
addrs []Account
keyJSON struct {
- Address common.Address `json:"address"`
+ Address string `json:"address"`
}
)
for _, fi := range files {
@@ -241,15 +241,16 @@ func (ac *addrCache) scan() ([]Account, error) {
}
buf.Reset(fd)
// Parse the address.
- keyJSON.Address = common.Address{}
+ keyJSON.Address = ""
err = json.NewDecoder(buf).Decode(&keyJSON)
+ addr := common.HexToAddress(keyJSON.Address)
switch {
case err != nil:
glog.V(logger.Debug).Infof("can't decode key %s: %v", path, err)
- case (keyJSON.Address == common.Address{}):
+ case (addr == common.Address{}):
glog.V(logger.Debug).Infof("can't decode key %s: missing or zero address", path)
default:
- addrs = append(addrs, Account{Address: keyJSON.Address, File: path})
+ addrs = append(addrs, Account{Address: addr, File: path})
}
fd.Close()
}
diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go
new file mode 100644
index 000000000..29e6de333
--- /dev/null
+++ b/common/hexutil/hexutil.go
@@ -0,0 +1,232 @@
+// 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 hexutil implements hex encoding with 0x prefix.
+This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads.
+
+Encoding Rules
+
+All hex data must have prefix "0x".
+
+For byte slices, the hex data must be of even length. An empty byte slice
+encodes as "0x".
+
+Integers are encoded using the least amount of digits (no leading zero digits). Their
+encoding may be of uneven length. The number zero encodes as "0x0".
+*/
+package hexutil
+
+import (
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "math/big"
+ "strconv"
+)
+
+const uintBits = 32 << (uint64(^uint(0)) >> 63)
+
+var (
+ ErrEmptyString = errors.New("empty hex string")
+ ErrMissingPrefix = errors.New("missing 0x prefix for hex data")
+ ErrSyntax = errors.New("invalid hex")
+ ErrEmptyNumber = errors.New("hex number has no digits after 0x")
+ ErrLeadingZero = errors.New("hex number has leading zero digits after 0x")
+ ErrOddLength = errors.New("hex string has odd length")
+ ErrUint64Range = errors.New("hex number does not fit into 64 bits")
+ ErrUintRange = fmt.Errorf("hex number does not fit into %d bits", uintBits)
+)
+
+// Decode decodes a hex string with 0x prefix.
+func Decode(input string) ([]byte, error) {
+ if len(input) == 0 {
+ return nil, ErrEmptyString
+ }
+ if !has0xPrefix(input) {
+ return nil, ErrMissingPrefix
+ }
+ return hex.DecodeString(input[2:])
+}
+
+// MustDecode decodes a hex string with 0x prefix. It panics for invalid input.
+func MustDecode(input string) []byte {
+ dec, err := Decode(input)
+ if err != nil {
+ panic(err)
+ }
+ return dec
+}
+
+// Encode encodes b as a hex string with 0x prefix.
+func Encode(b []byte) string {
+ enc := make([]byte, len(b)*2+2)
+ copy(enc, "0x")
+ hex.Encode(enc[2:], b)
+ return string(enc)
+}
+
+// DecodeUint64 decodes a hex string with 0x prefix as a quantity.
+func DecodeUint64(input string) (uint64, error) {
+ raw, err := checkNumber(input)
+ if err != nil {
+ return 0, err
+ }
+ dec, err := strconv.ParseUint(raw, 16, 64)
+ if err != nil {
+ err = mapError(err)
+ }
+ return dec, err
+}
+
+// MustDecodeUint64 decodes a hex string with 0x prefix as a quantity.
+// It panics for invalid input.
+func MustDecodeUint64(input string) uint64 {
+ dec, err := DecodeUint64(input)
+ if err != nil {
+ panic(err)
+ }
+ return dec
+}
+
+// EncodeUint64 encodes i as a hex string with 0x prefix.
+func EncodeUint64(i uint64) string {
+ enc := make([]byte, 2, 10)
+ copy(enc, "0x")
+ return string(strconv.AppendUint(enc, i, 16))
+}
+
+var bigWordNibbles int
+
+func init() {
+ // This is a weird way to compute the number of nibbles required for big.Word.
+ // The usual way would be to use constant arithmetic but go vet can't handle that.
+ b, _ := new(big.Int).SetString("FFFFFFFFFF", 16)
+ switch len(b.Bits()) {
+ case 1:
+ bigWordNibbles = 16
+ case 2:
+ bigWordNibbles = 8
+ default:
+ panic("weird big.Word size")
+ }
+}
+
+// DecodeBig decodes a hex string with 0x prefix as a quantity.
+func DecodeBig(input string) (*big.Int, error) {
+ raw, err := checkNumber(input)
+ if err != nil {
+ return nil, err
+ }
+ words := make([]big.Word, len(raw)/bigWordNibbles+1)
+ end := len(raw)
+ for i := range words {
+ start := end - bigWordNibbles
+ if start < 0 {
+ start = 0
+ }
+ for ri := start; ri < end; ri++ {
+ nib := decodeNibble(raw[ri])
+ if nib == badNibble {
+ return nil, ErrSyntax
+ }
+ words[i] *= 16
+ words[i] += big.Word(nib)
+ }
+ end = start
+ }
+ dec := new(big.Int).SetBits(words)
+ return dec, nil
+}
+
+// MustDecodeBig decodes a hex string with 0x prefix as a quantity.
+// It panics for invalid input.
+func MustDecodeBig(input string) *big.Int {
+ dec, err := DecodeBig(input)
+ if err != nil {
+ panic(err)
+ }
+ return dec
+}
+
+// EncodeBig encodes bigint as a hex string with 0x prefix.
+// The sign of the integer is ignored.
+func EncodeBig(bigint *big.Int) string {
+ nbits := bigint.BitLen()
+ if nbits == 0 {
+ return "0x0"
+ }
+ enc := make([]byte, 2, (nbits/8)*2+2)
+ copy(enc, "0x")
+ for i := len(bigint.Bits()) - 1; i >= 0; i-- {
+ enc = strconv.AppendUint(enc, uint64(bigint.Bits()[i]), 16)
+ }
+ return string(enc)
+}
+
+func has0xPrefix(input string) bool {
+ return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
+}
+
+func checkNumber(input string) (raw string, err error) {
+ if len(input) == 0 {
+ return "", ErrEmptyString
+ }
+ if !has0xPrefix(input) {
+ return "", ErrMissingPrefix
+ }
+ input = input[2:]
+ if len(input) == 0 {
+ return "", ErrEmptyNumber
+ }
+ if len(input) > 1 && input[0] == '0' {
+ return "", ErrLeadingZero
+ }
+ return input, nil
+}
+
+const badNibble = ^uint64(0)
+
+func decodeNibble(in byte) uint64 {
+ switch {
+ case in >= '0' && in <= '9':
+ return uint64(in - '0')
+ case in >= 'A' && in <= 'F':
+ return uint64(in - 'A' + 10)
+ case in >= 'a' && in <= 'f':
+ return uint64(in - 'a' + 10)
+ default:
+ return badNibble
+ }
+}
+
+func mapError(err error) error {
+ if err, ok := err.(*strconv.NumError); ok {
+ switch err.Err {
+ case strconv.ErrRange:
+ return ErrUint64Range
+ case strconv.ErrSyntax:
+ return ErrSyntax
+ }
+ }
+ if _, ok := err.(hex.InvalidByteError); ok {
+ return ErrSyntax
+ }
+ if err == hex.ErrLength {
+ return ErrOddLength
+ }
+ return err
+}
diff --git a/common/hexutil/hexutil_test.go b/common/hexutil/hexutil_test.go
new file mode 100644
index 000000000..3f261c9a7
--- /dev/null
+++ b/common/hexutil/hexutil_test.go
@@ -0,0 +1,186 @@
+// 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 hexutil
+
+import (
+ "bytes"
+ "encoding/hex"
+ "math/big"
+ "testing"
+)
+
+type marshalTest struct {
+ input interface{}
+ want string
+}
+
+type unmarshalTest struct {
+ input string
+ want interface{}
+ wantErr error
+}
+
+var (
+ encodeBytesTests = []marshalTest{
+ {[]byte{}, "0x"},
+ {[]byte{0}, "0x00"},
+ {[]byte{0, 0, 1, 2}, "0x00000102"},
+ }
+
+ encodeBigTests = []marshalTest{
+ {referenceBig("0"), "0x0"},
+ {referenceBig("1"), "0x1"},
+ {referenceBig("ff"), "0xff"},
+ {referenceBig("112233445566778899aabbccddeeff"), "0x112233445566778899aabbccddeeff"},
+ }
+
+ encodeUint64Tests = []marshalTest{
+ {uint64(0), "0x0"},
+ {uint64(1), "0x1"},
+ {uint64(0xff), "0xff"},
+ {uint64(0x1122334455667788), "0x1122334455667788"},
+ }
+
+ decodeBytesTests = []unmarshalTest{
+ // invalid
+ {input: ``, wantErr: ErrEmptyString},
+ {input: `0`, wantErr: ErrMissingPrefix},
+ {input: `0x0`, wantErr: hex.ErrLength},
+ {input: `0x023`, wantErr: hex.ErrLength},
+ {input: `0xxx`, wantErr: hex.InvalidByteError('x')},
+ {input: `0x01zz01`, wantErr: hex.InvalidByteError('z')},
+ // valid
+ {input: `0x`, want: []byte{}},
+ {input: `0X`, want: []byte{}},
+ {input: `0x02`, want: []byte{0x02}},
+ {input: `0X02`, want: []byte{0x02}},
+ {input: `0xffffffffff`, want: []byte{0xff, 0xff, 0xff, 0xff, 0xff}},
+ {
+ input: `0xffffffffffffffffffffffffffffffffffff`,
+ want: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ },
+ }
+
+ decodeBigTests = []unmarshalTest{
+ // invalid
+ {input: `0`, wantErr: ErrMissingPrefix},
+ {input: `0x`, wantErr: ErrEmptyNumber},
+ {input: `0x01`, wantErr: ErrLeadingZero},
+ {input: `0xx`, wantErr: ErrSyntax},
+ {input: `0x1zz01`, wantErr: ErrSyntax},
+ // valid
+ {input: `0x0`, want: big.NewInt(0)},
+ {input: `0x2`, want: big.NewInt(0x2)},
+ {input: `0x2F2`, want: big.NewInt(0x2f2)},
+ {input: `0X2F2`, want: big.NewInt(0x2f2)},
+ {input: `0x1122aaff`, want: big.NewInt(0x1122aaff)},
+ {input: `0xbBb`, want: big.NewInt(0xbbb)},
+ {input: `0xfffffffff`, want: big.NewInt(0xfffffffff)},
+ {
+ input: `0x112233445566778899aabbccddeeff`,
+ want: referenceBig("112233445566778899aabbccddeeff"),
+ },
+ {
+ input: `0xffffffffffffffffffffffffffffffffffff`,
+ want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
+ },
+ }
+
+ decodeUint64Tests = []unmarshalTest{
+ // invalid
+ {input: `0`, wantErr: ErrMissingPrefix},
+ {input: `0x`, wantErr: ErrEmptyNumber},
+ {input: `0x01`, wantErr: ErrLeadingZero},
+ {input: `0xfffffffffffffffff`, wantErr: ErrUintRange},
+ {input: `0xx`, wantErr: ErrSyntax},
+ {input: `0x1zz01`, wantErr: ErrSyntax},
+ // valid
+ {input: `0x0`, want: uint64(0)},
+ {input: `0x2`, want: uint64(0x2)},
+ {input: `0x2F2`, want: uint64(0x2f2)},
+ {input: `0X2F2`, want: uint64(0x2f2)},
+ {input: `0x1122aaff`, want: uint64(0x1122aaff)},
+ {input: `0xbbb`, want: uint64(0xbbb)},
+ {input: `0xffffffffffffffff`, want: uint64(0xffffffffffffffff)},
+ }
+)
+
+func TestEncode(t *testing.T) {
+ for _, test := range encodeBytesTests {
+ enc := Encode(test.input.([]byte))
+ if enc != test.want {
+ t.Errorf("input %x: wrong encoding %s", test.input, enc)
+ }
+ }
+}
+
+func TestDecode(t *testing.T) {
+ for _, test := range decodeBytesTests {
+ dec, err := Decode(test.input)
+ if !checkError(t, test.input, err, test.wantErr) {
+ continue
+ }
+ if !bytes.Equal(test.want.([]byte), dec) {
+ t.Errorf("input %s: value mismatch: got %x, want %x", test.input, dec, test.want)
+ continue
+ }
+ }
+}
+
+func TestEncodeBig(t *testing.T) {
+ for _, test := range encodeBigTests {
+ enc := EncodeBig(test.input.(*big.Int))
+ if enc != test.want {
+ t.Errorf("input %x: wrong encoding %s", test.input, enc)
+ }
+ }
+}
+
+func TestDecodeBig(t *testing.T) {
+ for _, test := range decodeBigTests {
+ dec, err := DecodeBig(test.input)
+ if !checkError(t, test.input, err, test.wantErr) {
+ continue
+ }
+ if dec.Cmp(test.want.(*big.Int)) != 0 {
+ t.Errorf("input %s: value mismatch: got %x, want %x", test.input, dec, test.want)
+ continue
+ }
+ }
+}
+
+func TestEncodeUint64(t *testing.T) {
+ for _, test := range encodeUint64Tests {
+ enc := EncodeUint64(test.input.(uint64))
+ if enc != test.want {
+ t.Errorf("input %x: wrong encoding %s", test.input, enc)
+ }
+ }
+}
+
+func TestDecodeUint64(t *testing.T) {
+ for _, test := range decodeUint64Tests {
+ dec, err := DecodeUint64(test.input)
+ if !checkError(t, test.input, err, test.wantErr) {
+ continue
+ }
+ if dec != test.want.(uint64) {
+ t.Errorf("input %s: value mismatch: got %x, want %x", test.input, dec, test.want)
+ continue
+ }
+ }
+}
diff --git a/common/hexutil/json.go b/common/hexutil/json.go
new file mode 100644
index 000000000..cbbadbed6
--- /dev/null
+++ b/common/hexutil/json.go
@@ -0,0 +1,271 @@
+// 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 hexutil
+
+import (
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "math/big"
+ "strconv"
+)
+
+var (
+ jsonNull = []byte("null")
+ jsonZero = []byte(`"0x0"`)
+ errNonString = errors.New("cannot unmarshal non-string as hex data")
+ errNegativeBigInt = errors.New("hexutil.Big: can't marshal negative integer")
+)
+
+// Bytes marshals/unmarshals as a JSON string with 0x prefix.
+// The empty slice marshals as "0x".
+type Bytes []byte
+
+// MarshalJSON implements json.Marshaler.
+func (b Bytes) MarshalJSON() ([]byte, error) {
+ result := make([]byte, len(b)*2+4)
+ copy(result, `"0x`)
+ hex.Encode(result[3:], b)
+ result[len(result)-1] = '"'
+ return result, nil
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Bytes) UnmarshalJSON(input []byte) error {
+ raw, err := checkJSON(input)
+ if err != nil {
+ return err
+ }
+ dec := make([]byte, len(raw)/2)
+ if _, err = hex.Decode(dec, raw); err != nil {
+ err = mapError(err)
+ } else {
+ *b = dec
+ }
+ return err
+}
+
+// String returns the hex encoding of b.
+func (b Bytes) String() string {
+ return Encode(b)
+}
+
+// UnmarshalJSON decodes input as a JSON string with 0x prefix. The length of out
+// determines the required input length. This function is commonly used to implement the
+// UnmarshalJSON method for fixed-size types:
+//
+// type Foo [8]byte
+//
+// func (f *Foo) UnmarshalJSON(input []byte) error {
+// return hexutil.UnmarshalJSON("Foo", input, f[:])
+// }
+func UnmarshalJSON(typname string, input, out []byte) error {
+ raw, err := checkJSON(input)
+ if err != nil {
+ return err
+ }
+ if len(raw)/2 != len(out) {
+ return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
+ }
+ // Pre-verify syntax before modifying out.
+ for _, b := range raw {
+ if decodeNibble(b) == badNibble {
+ return ErrSyntax
+ }
+ }
+ hex.Decode(out, raw)
+ return nil
+}
+
+// Big marshals/unmarshals as a JSON string with 0x prefix. The zero value marshals as
+// "0x0". Negative integers are not supported at this time. Attempting to marshal them
+// will return an error.
+type Big big.Int
+
+// MarshalJSON implements json.Marshaler.
+func (b *Big) MarshalJSON() ([]byte, error) {
+ if b == nil {
+ return jsonNull, nil
+ }
+ bigint := (*big.Int)(b)
+ if bigint.Sign() == -1 {
+ return nil, errNegativeBigInt
+ }
+ nbits := bigint.BitLen()
+ if nbits == 0 {
+ return jsonZero, nil
+ }
+ enc := make([]byte, 3, (nbits/8)*2+4)
+ copy(enc, `"0x`)
+ for i := len(bigint.Bits()) - 1; i >= 0; i-- {
+ enc = strconv.AppendUint(enc, uint64(bigint.Bits()[i]), 16)
+ }
+ enc = append(enc, '"')
+ return enc, nil
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Big) UnmarshalJSON(input []byte) error {
+ raw, err := checkNumberJSON(input)
+ if err != nil {
+ return err
+ }
+ words := make([]big.Word, len(raw)/bigWordNibbles+1)
+ end := len(raw)
+ for i := range words {
+ start := end - bigWordNibbles
+ if start < 0 {
+ start = 0
+ }
+ for ri := start; ri < end; ri++ {
+ nib := decodeNibble(raw[ri])
+ if nib == badNibble {
+ return ErrSyntax
+ }
+ words[i] *= 16
+ words[i] += big.Word(nib)
+ }
+ end = start
+ }
+ var dec big.Int
+ dec.SetBits(words)
+ *b = (Big)(dec)
+ return nil
+}
+
+// ToInt converts b to a big.Int.
+func (b *Big) ToInt() *big.Int {
+ return (*big.Int)(b)
+}
+
+// String returns the hex encoding of b.
+func (b *Big) String() string {
+ return EncodeBig(b.ToInt())
+}
+
+// Uint64 marshals/unmarshals as a JSON string with 0x prefix.
+// The zero value marshals as "0x0".
+type Uint64 uint64
+
+// MarshalJSON implements json.Marshaler.
+func (b Uint64) MarshalJSON() ([]byte, error) {
+ buf := make([]byte, 3, 12)
+ copy(buf, `"0x`)
+ buf = strconv.AppendUint(buf, uint64(b), 16)
+ buf = append(buf, '"')
+ return buf, nil
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Uint64) UnmarshalJSON(input []byte) error {
+ raw, err := checkNumberJSON(input)
+ if err != nil {
+ return err
+ }
+ if len(raw) > 16 {
+ return ErrUint64Range
+ }
+ var dec uint64
+ for _, byte := range raw {
+ nib := decodeNibble(byte)
+ if nib == badNibble {
+ return ErrSyntax
+ }
+ dec *= 16
+ dec += uint64(nib)
+ }
+ *b = Uint64(dec)
+ return nil
+}
+
+// String returns the hex encoding of b.
+func (b Uint64) String() string {
+ return EncodeUint64(uint64(b))
+}
+
+// Uint marshals/unmarshals as a JSON string with 0x prefix.
+// The zero value marshals as "0x0".
+type Uint uint
+
+// MarshalJSON implements json.Marshaler.
+func (b Uint) MarshalJSON() ([]byte, error) {
+ return Uint64(b).MarshalJSON()
+}
+
+// UnmarshalJSON implements json.Unmarshaler.
+func (b *Uint) UnmarshalJSON(input []byte) error {
+ var u64 Uint64
+ err := u64.UnmarshalJSON(input)
+ if err != nil {
+ return err
+ } else if u64 > Uint64(^uint(0)) {
+ return ErrUintRange
+ }
+ *b = Uint(u64)
+ return nil
+}
+
+// String returns the hex encoding of b.
+func (b Uint) String() string {
+ return EncodeUint64(uint64(b))
+}
+
+func isString(input []byte) bool {
+ return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"'
+}
+
+func bytesHave0xPrefix(input []byte) bool {
+ return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
+}
+
+func checkJSON(input []byte) (raw []byte, err error) {
+ if !isString(input) {
+ return nil, errNonString
+ }
+ if len(input) == 2 {
+ return nil, ErrEmptyString
+ }
+ if !bytesHave0xPrefix(input[1:]) {
+ return nil, ErrMissingPrefix
+ }
+ input = input[3 : len(input)-1]
+ if len(input)%2 != 0 {
+ return nil, ErrOddLength
+ }
+ return input, nil
+}
+
+func checkNumberJSON(input []byte) (raw []byte, err error) {
+ if !isString(input) {
+ return nil, errNonString
+ }
+ input = input[1 : len(input)-1]
+ if len(input) == 0 {
+ return nil, ErrEmptyString
+ }
+ if !bytesHave0xPrefix(input) {
+ return nil, ErrMissingPrefix
+ }
+ input = input[2:]
+ if len(input) == 0 {
+ return nil, ErrEmptyNumber
+ }
+ if len(input) > 1 && input[0] == '0' {
+ return nil, ErrLeadingZero
+ }
+ return input, nil
+}
diff --git a/common/hexutil/json_test.go b/common/hexutil/json_test.go
new file mode 100644
index 000000000..16f1b9aa7
--- /dev/null
+++ b/common/hexutil/json_test.go
@@ -0,0 +1,258 @@
+// 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 hexutil
+
+import (
+ "bytes"
+ "encoding/hex"
+ "math/big"
+ "testing"
+)
+
+func checkError(t *testing.T, input string, got, want error) bool {
+ if got == nil {
+ if want != nil {
+ t.Errorf("input %s: got no error, want %q", input, want)
+ return false
+ }
+ return true
+ }
+ if want == nil {
+ t.Errorf("input %s: unexpected error %q", input, got)
+ } else if got.Error() != want.Error() {
+ t.Errorf("input %s: got error %q, want %q", input, got, want)
+ }
+ return false
+}
+
+func referenceBig(s string) *big.Int {
+ b, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic("invalid")
+ }
+ return b
+}
+
+func referenceBytes(s string) []byte {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+var unmarshalBytesTests = []unmarshalTest{
+ // invalid encoding
+ {input: "", wantErr: errNonString},
+ {input: "null", wantErr: errNonString},
+ {input: "10", wantErr: errNonString},
+ {input: `""`, wantErr: ErrEmptyString},
+ {input: `"0"`, wantErr: ErrMissingPrefix},
+ {input: `"0x0"`, wantErr: ErrOddLength},
+ {input: `"0xxx"`, wantErr: ErrSyntax},
+ {input: `"0x01zz01"`, wantErr: ErrSyntax},
+
+ // valid encoding
+ {input: `"0x"`, want: referenceBytes("")},
+ {input: `"0x02"`, want: referenceBytes("02")},
+ {input: `"0X02"`, want: referenceBytes("02")},
+ {input: `"0xffffffffff"`, want: referenceBytes("ffffffffff")},
+ {
+ input: `"0xffffffffffffffffffffffffffffffffffff"`,
+ want: referenceBytes("ffffffffffffffffffffffffffffffffffff"),
+ },
+}
+
+func TestUnmarshalBytes(t *testing.T) {
+ for _, test := range unmarshalBytesTests {
+ var v Bytes
+ err := v.UnmarshalJSON([]byte(test.input))
+ if !checkError(t, test.input, err, test.wantErr) {
+ continue
+ }
+ if !bytes.Equal(test.want.([]byte), []byte(v)) {
+ t.Errorf("input %s: value mismatch: got %x, want %x", test.input, &v, test.want)
+ continue
+ }
+ }
+}
+
+func BenchmarkUnmarshalBytes(b *testing.B) {
+ input := []byte(`"0x123456789abcdef123456789abcdef"`)
+ for i := 0; i < b.N; i++ {
+ var v Bytes
+ if err := v.UnmarshalJSON(input); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func TestMarshalBytes(t *testing.T) {
+ for _, test := range encodeBytesTests {
+ in := test.input.([]byte)
+ out, err := Bytes(in).MarshalJSON()
+ if err != nil {
+ t.Errorf("%x: %v", in, err)
+ continue
+ }
+ if want := `"` + test.want + `"`; string(out) != want {
+ t.Errorf("%x: MarshalJSON output mismatch: got %q, want %q", in, out, want)
+ continue
+ }
+ if out := Bytes(in).String(); out != test.want {
+ t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
+ continue
+ }
+ }
+}
+
+var unmarshalBigTests = []unmarshalTest{
+ // invalid encoding
+ {input: "", wantErr: errNonString},
+ {input: "null", wantErr: errNonString},
+ {input: "10", wantErr: errNonString},
+ {input: `""`, wantErr: ErrEmptyString},
+ {input: `"0"`, wantErr: ErrMissingPrefix},
+ {input: `"0x"`, wantErr: ErrEmptyNumber},
+ {input: `"0x01"`, wantErr: ErrLeadingZero},
+ {input: `"0xx"`, wantErr: ErrSyntax},
+ {input: `"0x1zz01"`, wantErr: ErrSyntax},
+
+ // valid encoding
+ {input: `"0x0"`, want: big.NewInt(0)},
+ {input: `"0x2"`, want: big.NewInt(0x2)},
+ {input: `"0x2F2"`, want: big.NewInt(0x2f2)},
+ {input: `"0X2F2"`, want: big.NewInt(0x2f2)},
+ {input: `"0x1122aaff"`, want: big.NewInt(0x1122aaff)},
+ {input: `"0xbBb"`, want: big.NewInt(0xbbb)},
+ {input: `"0xfffffffff"`, want: big.NewInt(0xfffffffff)},
+ {
+ input: `"0x112233445566778899aabbccddeeff"`,
+ want: referenceBig("112233445566778899aabbccddeeff"),
+ },
+ {
+ input: `"0xffffffffffffffffffffffffffffffffffff"`,
+ want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
+ },
+}
+
+func TestUnmarshalBig(t *testing.T) {
+ for _, test := range unmarshalBigTests {
+ var v Big
+ err := v.UnmarshalJSON([]byte(test.input))
+ if !checkError(t, test.input, err, test.wantErr) {
+ continue
+ }
+ if test.want != nil && test.want.(*big.Int).Cmp((*big.Int)(&v)) != 0 {
+ t.Errorf("input %s: value mismatch: got %x, want %x", test.input, (*big.Int)(&v), test.want)
+ continue
+ }
+ }
+}
+
+func BenchmarkUnmarshalBig(b *testing.B) {
+ input := []byte(`"0x123456789abcdef123456789abcdef"`)
+ for i := 0; i < b.N; i++ {
+ var v Big
+ if err := v.UnmarshalJSON(input); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func TestMarshalBig(t *testing.T) {
+ for _, test := range encodeBigTests {
+ in := test.input.(*big.Int)
+ out, err := (*Big)(in).MarshalJSON()
+ if err != nil {
+ t.Errorf("%d: %v", in, err)
+ continue
+ }
+ if want := `"` + test.want + `"`; string(out) != want {
+ t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
+ continue
+ }
+ if out := (*Big)(in).String(); out != test.want {
+ t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
+ continue
+ }
+ }
+}
+
+var unmarshalUint64Tests = []unmarshalTest{
+ // invalid encoding
+ {input: "", wantErr: errNonString},
+ {input: "null", wantErr: errNonString},
+ {input: "10", wantErr: errNonString},
+ {input: `""`, wantErr: ErrEmptyString},
+ {input: `"0"`, wantErr: ErrMissingPrefix},
+ {input: `"0x"`, wantErr: ErrEmptyNumber},
+ {input: `"0x01"`, wantErr: ErrLeadingZero},
+ {input: `"0xfffffffffffffffff"`, wantErr: ErrUintRange},
+ {input: `"0xx"`, wantErr: ErrSyntax},
+ {input: `"0x1zz01"`, wantErr: ErrSyntax},
+
+ // valid encoding
+ {input: `"0x0"`, want: uint64(0)},
+ {input: `"0x2"`, want: uint64(0x2)},
+ {input: `"0x2F2"`, want: uint64(0x2f2)},
+ {input: `"0X2F2"`, want: uint64(0x2f2)},
+ {input: `"0x1122aaff"`, want: uint64(0x1122aaff)},
+ {input: `"0xbbb"`, want: uint64(0xbbb)},
+ {input: `"0xffffffffffffffff"`, want: uint64(0xffffffffffffffff)},
+}
+
+func TestUnmarshalUint64(t *testing.T) {
+ for _, test := range unmarshalUint64Tests {
+ var v Uint64
+ err := v.UnmarshalJSON([]byte(test.input))
+ if !checkError(t, test.input, err, test.wantErr) {
+ continue
+ }
+ if uint64(v) != test.want.(uint64) {
+ t.Errorf("input %s: value mismatch: got %d, want %d", test.input, v, test.want)
+ continue
+ }
+ }
+}
+
+func BenchmarkUnmarshalUint64(b *testing.B) {
+ input := []byte(`"0x123456789abcdf"`)
+ for i := 0; i < b.N; i++ {
+ var v Uint64
+ v.UnmarshalJSON(input)
+ }
+}
+
+func TestMarshalUint64(t *testing.T) {
+ for _, test := range encodeUint64Tests {
+ in := test.input.(uint64)
+ out, err := Uint64(in).MarshalJSON()
+ if err != nil {
+ t.Errorf("%d: %v", in, err)
+ continue
+ }
+ if want := `"` + test.want + `"`; string(out) != want {
+ t.Errorf("%d: MarshalJSON output mismatch: got %q, want %q", in, out, want)
+ continue
+ }
+ if out := (Uint64)(in).String(); out != test.want {
+ t.Errorf("%x: String mismatch: got %q, want %q", in, out, test.want)
+ continue
+ }
+ }
+}
diff --git a/common/types.go b/common/types.go
index 70b7e7aae..8a456e965 100644
--- a/common/types.go
+++ b/common/types.go
@@ -17,14 +17,12 @@
package common
import (
- "encoding/hex"
- "encoding/json"
- "errors"
"fmt"
"math/big"
"math/rand"
"reflect"
- "strings"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
)
const (
@@ -32,8 +30,6 @@ const (
AddressLength = 20
)
-var hashJsonLengthErr = errors.New("common: unmarshalJSON failed: hash must be exactly 32 bytes")
-
type (
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
Hash [HashLength]byte
@@ -57,30 +53,16 @@ func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) }
func (h Hash) Str() string { return string(h[:]) }
func (h Hash) Bytes() []byte { return h[:] }
func (h Hash) Big() *big.Int { return Bytes2Big(h[:]) }
-func (h Hash) Hex() string { return "0x" + Bytes2Hex(h[:]) }
+func (h Hash) Hex() string { return hexutil.Encode(h[:]) }
// UnmarshalJSON parses a hash in its hex from to a hash.
func (h *Hash) UnmarshalJSON(input []byte) error {
- length := len(input)
- if length >= 2 && input[0] == '"' && input[length-1] == '"' {
- input = input[1 : length-1]
- }
- // strip "0x" for length check
- if len(input) > 1 && strings.ToLower(string(input[:2])) == "0x" {
- input = input[2:]
- }
-
- // validate the length of the input hash
- if len(input) != HashLength*2 {
- return hashJsonLengthErr
- }
- h.SetBytes(FromHex(string(input)))
- return nil
+ return hexutil.UnmarshalJSON("Hash", input, h[:])
}
// Serialize given hash to JSON
func (h Hash) MarshalJSON() ([]byte, error) {
- return json.Marshal(h.Hex())
+ return hexutil.Bytes(h[:]).MarshalJSON()
}
// Sets the hash to the value of b. If b is larger than len(h) it will panic
@@ -142,7 +124,7 @@ func (a Address) Str() string { return string(a[:]) }
func (a Address) Bytes() []byte { return a[:] }
func (a Address) Big() *big.Int { return Bytes2Big(a[:]) }
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
-func (a Address) Hex() string { return "0x" + Bytes2Hex(a[:]) }
+func (a Address) Hex() string { return hexutil.Encode(a[:]) }
// Sets the address to the value of b. If b is larger than len(a) it will panic
func (a *Address) SetBytes(b []byte) {
@@ -164,34 +146,12 @@ func (a *Address) Set(other Address) {
// Serialize given address to JSON
func (a Address) MarshalJSON() ([]byte, error) {
- return json.Marshal(a.Hex())
+ return hexutil.Bytes(a[:]).MarshalJSON()
}
// Parse address from raw json data
-func (a *Address) UnmarshalJSON(data []byte) error {
- if len(data) > 2 && data[0] == '"' && data[len(data)-1] == '"' {
- data = data[1 : len(data)-1]
- }
-
- if len(data) > 2 && data[0] == '0' && data[1] == 'x' {
- data = data[2:]
- }
-
- if len(data) != 2*AddressLength {
- return fmt.Errorf("Invalid address length, expected %d got %d bytes", 2*AddressLength, len(data))
- }
-
- n, err := hex.Decode(a[:], data)
- if err != nil {
- return err
- }
-
- if n != AddressLength {
- return fmt.Errorf("Invalid address")
- }
-
- a.Set(HexToAddress(string(data)))
- return nil
+func (a *Address) UnmarshalJSON(input []byte) error {
+ return hexutil.UnmarshalJSON("Address", input, a[:])
}
// PP Pretty Prints a byte slice in the following format:
diff --git a/common/types_test.go b/common/types_test.go
index de67cfcb5..e84780f43 100644
--- a/common/types_test.go
+++ b/common/types_test.go
@@ -18,7 +18,10 @@ package common
import (
"math/big"
+ "strings"
"testing"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
)
func TestBytesConversion(t *testing.T) {
@@ -38,19 +41,26 @@ func TestHashJsonValidation(t *testing.T) {
var tests = []struct {
Prefix string
Size int
- Error error
+ Error string
}{
- {"", 2, hashJsonLengthErr},
- {"", 62, hashJsonLengthErr},
- {"", 66, hashJsonLengthErr},
- {"", 65, hashJsonLengthErr},
- {"0X", 64, nil},
- {"0x", 64, nil},
- {"0x", 62, hashJsonLengthErr},
+ {"", 62, hexutil.ErrMissingPrefix.Error()},
+ {"0x", 66, "hex string has length 66, want 64 for Hash"},
+ {"0x", 63, hexutil.ErrOddLength.Error()},
+ {"0x", 0, "hex string has length 0, want 64 for Hash"},
+ {"0x", 64, ""},
+ {"0X", 64, ""},
}
- for i, test := range tests {
- if err := h.UnmarshalJSON(append([]byte(test.Prefix), make([]byte, test.Size)...)); err != test.Error {
- t.Errorf("test #%d: error mismatch: have %v, want %v", i, err, test.Error)
+ for _, test := range tests {
+ input := `"` + test.Prefix + strings.Repeat("0", test.Size) + `"`
+ err := h.UnmarshalJSON([]byte(input))
+ if err == nil {
+ if test.Error != "" {
+ t.Errorf("%s: error mismatch: have nil, want %q", input, test.Error)
+ }
+ } else {
+ if err.Error() != test.Error {
+ t.Errorf("%s: error mismatch: have %q, want %q", input, err, test.Error)
+ }
}
}
}
diff --git a/core/types/block.go b/core/types/block.go
index 68504ffcc..2034bb0ff 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -29,6 +29,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -63,20 +64,12 @@ func (n BlockNonce) Uint64() uint64 {
// MarshalJSON implements json.Marshaler
func (n BlockNonce) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf(`"0x%x"`, n)), nil
+ return hexutil.Bytes(n[:]).MarshalJSON()
}
// UnmarshalJSON implements json.Unmarshaler
func (n *BlockNonce) UnmarshalJSON(input []byte) error {
- var b hexBytes
- if err := b.UnmarshalJSON(input); err != nil {
- return err
- }
- if len(b) != 8 {
- return errBadNonceSize
- }
- copy((*n)[:], b)
- return nil
+ return hexutil.UnmarshalJSON("BlockNonce", input, n[:])
}
// Header represents a block header in the Ethereum blockchain.
@@ -106,12 +99,12 @@ type jsonHeader struct {
TxHash *common.Hash `json:"transactionsRoot"`
ReceiptHash *common.Hash `json:"receiptsRoot"`
Bloom *Bloom `json:"logsBloom"`
- Difficulty *hexBig `json:"difficulty"`
- Number *hexBig `json:"number"`
- GasLimit *hexBig `json:"gasLimit"`
- GasUsed *hexBig `json:"gasUsed"`
- Time *hexBig `json:"timestamp"`
- Extra *hexBytes `json:"extraData"`
+ Difficulty *hexutil.Big `json:"difficulty"`
+ Number *hexutil.Big `json:"number"`
+ GasLimit *hexutil.Big `json:"gasLimit"`
+ GasUsed *hexutil.Big `json:"gasUsed"`
+ Time *hexutil.Big `json:"timestamp"`
+ Extra *hexutil.Bytes `json:"extraData"`
MixDigest *common.Hash `json:"mixHash"`
Nonce *BlockNonce `json:"nonce"`
}
@@ -151,12 +144,12 @@ func (h *Header) MarshalJSON() ([]byte, error) {
TxHash: &h.TxHash,
ReceiptHash: &h.ReceiptHash,
Bloom: &h.Bloom,
- Difficulty: (*hexBig)(h.Difficulty),
- Number: (*hexBig)(h.Number),
- GasLimit: (*hexBig)(h.GasLimit),
- GasUsed: (*hexBig)(h.GasUsed),
- Time: (*hexBig)(h.Time),
- Extra: (*hexBytes)(&h.Extra),
+ Difficulty: (*hexutil.Big)(h.Difficulty),
+ Number: (*hexutil.Big)(h.Number),
+ GasLimit: (*hexutil.Big)(h.GasLimit),
+ GasUsed: (*hexutil.Big)(h.GasUsed),
+ Time: (*hexutil.Big)(h.Time),
+ Extra: (*hexutil.Bytes)(&h.Extra),
MixDigest: &h.MixDigest,
Nonce: &h.Nonce,
})
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
index d3945a734..a1d13e218 100644
--- a/core/types/bloom9.go
+++ b/core/types/bloom9.go
@@ -21,6 +21,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
)
@@ -77,20 +78,12 @@ func (b Bloom) TestBytes(test []byte) bool {
// MarshalJSON encodes b as a hex string with 0x prefix.
func (b Bloom) MarshalJSON() ([]byte, error) {
- return []byte(fmt.Sprintf(`"%#x"`, b[:])), nil
+ return hexutil.Bytes(b[:]).MarshalJSON()
}
// UnmarshalJSON b as a hex string with 0x prefix.
func (b *Bloom) UnmarshalJSON(input []byte) error {
- var dec hexBytes
- if err := dec.UnmarshalJSON(input); err != nil {
- return err
- }
- if len(dec) != bloomLength {
- return fmt.Errorf("invalid bloom size, want %d bytes", bloomLength)
- }
- copy((*b)[:], dec)
- return nil
+ return hexutil.UnmarshalJSON("Bloom", input, b[:])
}
func CreateBloom(receipts Receipts) Bloom {
diff --git a/core/types/json.go b/core/types/json.go
deleted file mode 100644
index d2718a96d..000000000
--- a/core/types/json.go
+++ /dev/null
@@ -1,108 +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 types
-
-import (
- "encoding/hex"
- "fmt"
- "math/big"
-)
-
-// JSON unmarshaling utilities.
-
-type hexBytes []byte
-
-func (b *hexBytes) MarshalJSON() ([]byte, error) {
- if b != nil {
- return []byte(fmt.Sprintf(`"0x%x"`, []byte(*b))), nil
- }
- return nil, nil
-}
-
-func (b *hexBytes) UnmarshalJSON(input []byte) error {
- if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' {
- return fmt.Errorf("cannot unmarshal non-string into hexBytes")
- }
- input = input[1 : len(input)-1]
- if len(input) < 2 || input[0] != '0' || input[1] != 'x' {
- return fmt.Errorf("missing 0x prefix in hexBytes input %q", input)
- }
- dec := make(hexBytes, (len(input)-2)/2)
- if _, err := hex.Decode(dec, input[2:]); err != nil {
- return err
- }
- *b = dec
- return nil
-}
-
-type hexBig big.Int
-
-func (b *hexBig) MarshalJSON() ([]byte, error) {
- if b != nil {
- return []byte(fmt.Sprintf(`"0x%x"`, (*big.Int)(b))), nil
- }
- return nil, nil
-}
-
-func (b *hexBig) UnmarshalJSON(input []byte) error {
- raw, err := checkHexNumber(input)
- if err != nil {
- return err
- }
- dec, ok := new(big.Int).SetString(string(raw), 16)
- if !ok {
- return fmt.Errorf("invalid hex number")
- }
- *b = (hexBig)(*dec)
- return nil
-}
-
-type hexUint64 uint64
-
-func (b *hexUint64) MarshalJSON() ([]byte, error) {
- if b != nil {
- return []byte(fmt.Sprintf(`"0x%x"`, *(*uint64)(b))), nil
- }
- return nil, nil
-}
-
-func (b *hexUint64) UnmarshalJSON(input []byte) error {
- raw, err := checkHexNumber(input)
- if err != nil {
- return err
- }
- _, err = fmt.Sscanf(string(raw), "%x", b)
- return err
-}
-
-func checkHexNumber(input []byte) (raw []byte, err error) {
- if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' {
- return nil, fmt.Errorf("cannot unmarshal non-string into hex number")
- }
- input = input[1 : len(input)-1]
- if len(input) < 2 || input[0] != '0' || input[1] != 'x' {
- return nil, fmt.Errorf("missing 0x prefix in hex number input %q", input)
- }
- if len(input) == 2 {
- return nil, fmt.Errorf("empty hex number")
- }
- raw = input[2:]
- if len(raw)%2 != 0 {
- raw = append([]byte{'0'}, raw...)
- }
- return raw, nil
-}
diff --git a/core/types/json_test.go b/core/types/json_test.go
deleted file mode 100644
index d80cda68b..000000000
--- a/core/types/json_test.go
+++ /dev/null
@@ -1,232 +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 types
-
-import (
- "encoding/json"
- "reflect"
- "testing"
-
- "github.com/ethereum/go-ethereum/common"
-)
-
-var unmarshalHeaderTests = map[string]struct {
- input string
- wantHash common.Hash
- wantError error
-}{
- "block 0x1e2200": {
- input: `{"difficulty":"0x311ca98cebfe","extraData":"0x7777772e62772e636f6d","gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","mixHash":"0x1ccfddb506dac5afc09b6f92eb09a043ffc8e08f7592250af57b9c64c20f9b25","nonce":"0x670bd98c79585197","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptsRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`,
- wantHash: common.HexToHash("0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48"),
- },
- "bad nonce": {
- input: `{"difficulty":"0x311ca98cebfe","extraData":"0x7777772e62772e636f6d","gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","mixHash":"0x1ccfddb506dac5afc09b6f92eb09a043ffc8e08f7592250af57b9c64c20f9b25","nonce":"0x670bd98c7958","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptsRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`,
- wantError: errBadNonceSize,
- },
- "missing mixHash": {
- input: `{"difficulty":"0x311ca98cebfe","extraData":"0x7777772e62772e636f6d","gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","nonce":"0x670bd98c79585197","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptsRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`,
- wantError: errMissingHeaderMixDigest,
- },
- "missing fields": {
- input: `{"gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","mixHash":"0x1ccfddb506dac5afc09b6f92eb09a043ffc8e08f7592250af57b9c64c20f9b25","nonce":"0x670bd98c79585197","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptsRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`,
- wantError: errMissingHeaderFields,
- },
-}
-
-func TestUnmarshalHeader(t *testing.T) {
- for name, test := range unmarshalHeaderTests {
- var head *Header
- err := json.Unmarshal([]byte(test.input), &head)
- if !checkError(t, name, err, test.wantError) {
- continue
- }
- if head.Hash() != test.wantHash {
- t.Errorf("test %q: got hash %x, want %x", name, head.Hash(), test.wantHash)
- continue
- }
- }
-}
-
-func TestMarshalHeader(t *testing.T) {
- for name, test := range unmarshalHeaderTests {
- if test.wantError != nil {
- continue
- }
- var original *Header
- json.Unmarshal([]byte(test.input), &original)
-
- blob, err := json.Marshal(original)
- if err != nil {
- t.Errorf("test %q: failed to marshal header: %v", name, err)
- continue
- }
- var proced *Header
- if err := json.Unmarshal(blob, &proced); err != nil {
- t.Errorf("Test %q: failed to unmarshal marhsalled header: %v", name, err)
- continue
- }
- if !reflect.DeepEqual(original, proced) {
- t.Errorf("test %q: header mismatch: have %+v, want %+v", name, proced, original)
- continue
- }
- }
-}
-
-var unmarshalTransactionTests = map[string]struct {
- input string
- wantHash common.Hash
- wantFrom common.Address
- wantError error
-}{
- "value transfer": {
- input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x1c","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
- wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"),
- wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"),
- },
- /* TODO skipping this test as this type can not be tested with the current signing approach
- "bad signature fields": {
- input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x58","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
- wantError: ErrInvalidSig,
- },
- */
- "missing signature v": {
- input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
- wantError: errMissingTxSignatureFields,
- },
- "missing signature fields": {
- input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00"}`,
- wantError: errMissingTxSignatureFields,
- },
- "missing fields": {
- input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x1c","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
- wantError: errMissingTxFields,
- },
-}
-
-func TestUnmarshalTransaction(t *testing.T) {
- for name, test := range unmarshalTransactionTests {
- var tx *Transaction
- err := json.Unmarshal([]byte(test.input), &tx)
- if !checkError(t, name, err, test.wantError) {
- continue
- }
-
- if tx.Hash() != test.wantHash {
- t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash)
- continue
- }
- from, err := Sender(HomesteadSigner{}, tx)
- if err != nil {
- t.Errorf("test %q: From error %v", name, err)
- }
- if from != test.wantFrom {
- t.Errorf("test %q: sender mismatch: got %x, want %x", name, from, test.wantFrom)
- }
- }
-}
-
-func TestMarshalTransaction(t *testing.T) {
- for name, test := range unmarshalTransactionTests {
- if test.wantError != nil {
- continue
- }
- var original *Transaction
- json.Unmarshal([]byte(test.input), &original)
-
- blob, err := json.Marshal(original)
- if err != nil {
- t.Errorf("test %q: failed to marshal transaction: %v", name, err)
- continue
- }
- var proced *Transaction
- if err := json.Unmarshal(blob, &proced); err != nil {
- t.Errorf("Test %q: failed to unmarshal marhsalled transaction: %v", name, err)
- continue
- }
- proced.Hash() // hack private fields to pass deep equal
- if !reflect.DeepEqual(original, proced) {
- t.Errorf("test %q: transaction mismatch: have %+v, want %+v", name, proced, original)
- continue
- }
- }
-}
-
-var unmarshalReceiptTests = map[string]struct {
- input string
- wantError error
-}{
- "ok": {
- input: `{"blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","blockNumber":"0x1e773b","contractAddress":null,"cumulativeGasUsed":"0x10cea","from":"0xdf21fa922215b1a56f5a6d6294e6e36c85a0acfb","gasUsed":"0xbae2","logs":[{"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000df21fa922215b1a56f5a6d6294e6e36c85a0acfb","0x00000000000000000000000032be343b94f860124dc4fee278fdcbd38c102d88"],"data":"0x0000000000000000000000000000000000000000000000027cfefc4f3f392700","blockNumber":"0x1e773b","transactionIndex":"0x1","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","logIndex":"0x0"}],"logsBloom":"0x00000000000000020000000000020000000000000000000000000000000000000000000000000000000000000000000000040000000000000100000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000010000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000","root":"0x6e8a06b2dac39ac5c9d4db5fb2a2a94ef7a6e5ec1c554079112112caf162998a","to":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","transactionIndex":"0x1"}`,
- },
- "missing post state": {
- input: `{"blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","blockNumber":"0x1e773b","contractAddress":null,"cumulativeGasUsed":"0x10cea","from":"0xdf21fa922215b1a56f5a6d6294e6e36c85a0acfb","gasUsed":"0xbae2","logs":[{"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000df21fa922215b1a56f5a6d6294e6e36c85a0acfb","0x00000000000000000000000032be343b94f860124dc4fee278fdcbd38c102d88"],"data":"0x0000000000000000000000000000000000000000000000027cfefc4f3f392700","blockNumber":"0x1e773b","transactionIndex":"0x1","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","logIndex":"0x0"}],"logsBloom":"0x00000000000000020000000000020000000000000000000000000000000000000000000000000000000000000000000000040000000000000100000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000010000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000","to":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","transactionIndex":"0x1"}`,
- wantError: errMissingReceiptPostState,
- },
- "missing fields": {
- input: `{"blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","blockNumber":"0x1e773b","contractAddress":null,"cumulativeGasUsed":"0x10cea","from":"0xdf21fa922215b1a56f5a6d6294e6e36c85a0acfb","gasUsed":"0xbae2","logs":[{"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000df21fa922215b1a56f5a6d6294e6e36c85a0acfb","0x00000000000000000000000032be343b94f860124dc4fee278fdcbd38c102d88"],"data":"0x0000000000000000000000000000000000000000000000027cfefc4f3f392700","blockNumber":"0x1e773b","transactionIndex":"0x1","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","logIndex":"0x0"}],"logsBloom":"0x00000000000000020000000000020000000000000000000000000000000000000000000000000000000000000000000000040000000000000100000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000010000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000","root":"0x6e8a06b2dac39ac5c9d4db5fb2a2a94ef7a6e5ec1c554079112112caf162998a","to":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413"}`,
- wantError: errMissingReceiptFields,
- },
-}
-
-func TestUnmarshalReceipt(t *testing.T) {
- for name, test := range unmarshalReceiptTests {
- var r *Receipt
- err := json.Unmarshal([]byte(test.input), &r)
- checkError(t, name, err, test.wantError)
- }
-}
-
-func TestMarshalReceipt(t *testing.T) {
- for name, test := range unmarshalReceiptTests {
- if test.wantError != nil {
- continue
- }
- var original *Receipt
- json.Unmarshal([]byte(test.input), &original)
-
- blob, err := json.Marshal(original)
- if err != nil {
- t.Errorf("test %q: failed to marshal receipt: %v", name, err)
- continue
- }
- var proced *Receipt
- if err := json.Unmarshal(blob, &proced); err != nil {
- t.Errorf("Test %q: failed to unmarshal marhsalled receipt: %v", name, err)
- continue
- }
- if !reflect.DeepEqual(original, proced) {
- t.Errorf("test %q: receipt mismatch: have %+v, want %+v", name, proced, original)
- continue
- }
- }
-}
-
-func checkError(t *testing.T, testname string, got, want error) bool {
- if got == nil {
- if want != nil {
- t.Errorf("test %q: got no error, want %q", testname, want)
- return false
- }
- return true
- }
- if want == nil {
- t.Errorf("test %q: unexpected error %q", testname, got)
- } else if got.Error() != want.Error() {
- t.Errorf("test %q: got error %q, want %q", testname, got, want)
- }
- return false
-}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index b00fdabff..70c10d422 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -24,6 +24,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -49,12 +50,12 @@ type Receipt struct {
type jsonReceipt struct {
PostState *common.Hash `json:"root"`
- CumulativeGasUsed *hexBig `json:"cumulativeGasUsed"`
+ CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
Bloom *Bloom `json:"logsBloom"`
Logs *vm.Logs `json:"logs"`
TxHash *common.Hash `json:"transactionHash"`
ContractAddress *common.Address `json:"contractAddress"`
- GasUsed *hexBig `json:"gasUsed"`
+ GasUsed *hexutil.Big `json:"gasUsed"`
}
// NewReceipt creates a barebone transaction receipt, copying the init fields.
@@ -90,12 +91,12 @@ func (r *Receipt) MarshalJSON() ([]byte, error) {
return json.Marshal(&jsonReceipt{
PostState: &root,
- CumulativeGasUsed: (*hexBig)(r.CumulativeGasUsed),
+ CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed),
Bloom: &r.Bloom,
Logs: &r.Logs,
TxHash: &r.TxHash,
ContractAddress: &r.ContractAddress,
- GasUsed: (*hexBig)(r.GasUsed),
+ GasUsed: (*hexutil.Big)(r.GasUsed),
})
}
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 323bfaee6..1d2b1b561 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -27,6 +27,7 @@ import (
"sync/atomic"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
@@ -69,15 +70,15 @@ type txdata struct {
type jsonTransaction struct {
Hash *common.Hash `json:"hash"`
- AccountNonce *hexUint64 `json:"nonce"`
- Price *hexBig `json:"gasPrice"`
- GasLimit *hexBig `json:"gas"`
+ AccountNonce *hexutil.Uint64 `json:"nonce"`
+ Price *hexutil.Big `json:"gasPrice"`
+ GasLimit *hexutil.Big `json:"gas"`
Recipient *common.Address `json:"to"`
- Amount *hexBig `json:"value"`
- Payload *hexBytes `json:"input"`
- V *hexBig `json:"v"`
- R *hexBig `json:"r"`
- S *hexBig `json:"s"`
+ Amount *hexutil.Big `json:"value"`
+ Payload *hexutil.Bytes `json:"input"`
+ V *hexutil.Big `json:"v"`
+ R *hexutil.Big `json:"r"`
+ S *hexutil.Big `json:"s"`
}
func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
@@ -170,15 +171,15 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
return json.Marshal(&jsonTransaction{
Hash: &hash,
- AccountNonce: (*hexUint64)(&tx.data.AccountNonce),
- Price: (*hexBig)(tx.data.Price),
- GasLimit: (*hexBig)(tx.data.GasLimit),
+ AccountNonce: (*hexutil.Uint64)(&tx.data.AccountNonce),
+ Price: (*hexutil.Big)(tx.data.Price),
+ GasLimit: (*hexutil.Big)(tx.data.GasLimit),
Recipient: tx.data.Recipient,
- Amount: (*hexBig)(tx.data.Amount),
- Payload: (*hexBytes)(&tx.data.Payload),
- V: (*hexBig)(tx.data.V),
- R: (*hexBig)(tx.data.R),
- S: (*hexBig)(tx.data.S),
+ Amount: (*hexutil.Big)(tx.data.Amount),
+ Payload: (*hexutil.Bytes)(&tx.data.Payload),
+ V: (*hexutil.Big)(tx.data.V),
+ R: (*hexutil.Big)(tx.data.R),
+ S: (*hexutil.Big)(tx.data.S),
})
}
diff --git a/core/vm/log.go b/core/vm/log.go
index b292f5f43..06f941703 100644
--- a/core/vm/log.go
+++ b/core/vm/log.go
@@ -23,6 +23,7 @@ import (
"io"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -47,12 +48,12 @@ type Log struct {
type jsonLog struct {
Address *common.Address `json:"address"`
Topics *[]common.Hash `json:"topics"`
- Data string `json:"data"`
- BlockNumber string `json:"blockNumber"`
- TxIndex string `json:"transactionIndex"`
+ Data *hexutil.Bytes `json:"data"`
+ BlockNumber *hexutil.Uint64 `json:"blockNumber"`
+ TxIndex *hexutil.Uint `json:"transactionIndex"`
TxHash *common.Hash `json:"transactionHash"`
BlockHash *common.Hash `json:"blockHash"`
- Index string `json:"logIndex"`
+ Index *hexutil.Uint `json:"logIndex"`
}
func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log {
@@ -85,12 +86,12 @@ func (r *Log) MarshalJSON() ([]byte, error) {
return json.Marshal(&jsonLog{
Address: &r.Address,
Topics: &r.Topics,
- Data: fmt.Sprintf("0x%x", r.Data),
- BlockNumber: fmt.Sprintf("0x%x", r.BlockNumber),
- TxIndex: fmt.Sprintf("0x%x", r.TxIndex),
+ Data: (*hexutil.Bytes)(&r.Data),
+ BlockNumber: (*hexutil.Uint64)(&r.BlockNumber),
+ TxIndex: (*hexutil.Uint)(&r.TxIndex),
TxHash: &r.TxHash,
BlockHash: &r.BlockHash,
- Index: fmt.Sprintf("0x%x", r.Index),
+ Index: (*hexutil.Uint)(&r.Index),
})
}
@@ -100,29 +101,20 @@ func (r *Log) UnmarshalJSON(input []byte) error {
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
- if dec.Address == nil || dec.Topics == nil || dec.Data == "" || dec.BlockNumber == "" ||
- dec.TxIndex == "" || dec.TxHash == nil || dec.BlockHash == nil || dec.Index == "" {
+ if dec.Address == nil || dec.Topics == nil || dec.Data == nil || dec.BlockNumber == nil ||
+ dec.TxIndex == nil || dec.TxHash == nil || dec.BlockHash == nil || dec.Index == nil {
return errMissingLogFields
}
- declog := Log{
- Address: *dec.Address,
- Topics: *dec.Topics,
- TxHash: *dec.TxHash,
- BlockHash: *dec.BlockHash,
+ *r = Log{
+ Address: *dec.Address,
+ Topics: *dec.Topics,
+ Data: *dec.Data,
+ BlockNumber: uint64(*dec.BlockNumber),
+ TxHash: *dec.TxHash,
+ TxIndex: uint(*dec.TxIndex),
+ BlockHash: *dec.BlockHash,
+ Index: uint(*dec.Index),
}
- if _, err := fmt.Sscanf(dec.Data, "0x%x", &declog.Data); err != nil {
- return fmt.Errorf("invalid hex log data")
- }
- if _, err := fmt.Sscanf(dec.BlockNumber, "0x%x", &declog.BlockNumber); err != nil {
- return fmt.Errorf("invalid hex log block number")
- }
- if _, err := fmt.Sscanf(dec.TxIndex, "0x%x", &declog.TxIndex); err != nil {
- return fmt.Errorf("invalid hex log tx index")
- }
- if _, err := fmt.Sscanf(dec.Index, "0x%x", &declog.Index); err != nil {
- return fmt.Errorf("invalid hex log index")
- }
- *r = declog
return nil
}
diff --git a/core/vm/log_test.go b/core/vm/log_test.go
index 775016f9c..4d3189558 100644
--- a/core/vm/log_test.go
+++ b/core/vm/log_test.go
@@ -28,6 +28,9 @@ var unmarshalLogTests = map[string]struct {
"ok": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
},
+ "empty data": {
+ input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
+ },
"missing data": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
wantError: errMissingLogFields,
diff --git a/eth/filters/api.go b/eth/filters/api.go
index 834513262..584f55afd 100644
--- a/eth/filters/api.go
+++ b/eth/filters/api.go
@@ -17,7 +17,6 @@
package filters
import (
- "encoding/hex"
"encoding/json"
"errors"
"fmt"
@@ -28,6 +27,7 @@ import (
"golang.org/x/net/context"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
@@ -459,52 +459,28 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
if raw.Addresses != nil {
// raw.Address can contain a single address or an array of addresses
- var addresses []common.Address
- if strAddrs, ok := raw.Addresses.([]interface{}); ok {
- for i, addr := range strAddrs {
+ switch rawAddr := raw.Addresses.(type) {
+ case []interface{}:
+ for i, addr := range rawAddr {
if strAddr, ok := addr.(string); ok {
- if len(strAddr) >= 2 && strAddr[0] == '0' && (strAddr[1] == 'x' || strAddr[1] == 'X') {
- strAddr = strAddr[2:]
- }
- if decAddr, err := hex.DecodeString(strAddr); err == nil {
- addresses = append(addresses, common.BytesToAddress(decAddr))
- } else {
- return fmt.Errorf("invalid address given")
+ addr, err := decodeAddress(strAddr)
+ if err != nil {
+ return fmt.Errorf("invalid address at index %d: %v", i, err)
}
+ args.Addresses = append(args.Addresses, addr)
} else {
- return fmt.Errorf("invalid address on index %d", i)
+ return fmt.Errorf("non-string address at index %d", i)
}
}
- } else if singleAddr, ok := raw.Addresses.(string); ok {
- if len(singleAddr) >= 2 && singleAddr[0] == '0' && (singleAddr[1] == 'x' || singleAddr[1] == 'X') {
- singleAddr = singleAddr[2:]
- }
- if decAddr, err := hex.DecodeString(singleAddr); err == nil {
- addresses = append(addresses, common.BytesToAddress(decAddr))
- } else {
- return fmt.Errorf("invalid address given")
+ case string:
+ addr, err := decodeAddress(rawAddr)
+ if err != nil {
+ return fmt.Errorf("invalid address: %v", err)
}
- } else {
- return errors.New("invalid address(es) given")
- }
- args.Addresses = addresses
- }
-
- // helper function which parses a string to a topic hash
- topicConverter := func(raw string) (common.Hash, error) {
- if len(raw) == 0 {
- return common.Hash{}, nil
- }
- if len(raw) >= 2 && raw[0] == '0' && (raw[1] == 'x' || raw[1] == 'X') {
- raw = raw[2:]
- }
- if len(raw) != 2*common.HashLength {
- return common.Hash{}, errors.New("invalid topic(s)")
- }
- if decAddr, err := hex.DecodeString(raw); err == nil {
- return common.BytesToHash(decAddr), nil
+ args.Addresses = []common.Address{addr}
+ default:
+ return errors.New("invalid addresses in query")
}
- return common.Hash{}, errors.New("invalid topic(s)")
}
// topics is an array consisting of strings and/or arrays of strings.
@@ -512,20 +488,25 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
if len(raw.Topics) > 0 {
args.Topics = make([][]common.Hash, len(raw.Topics))
for i, t := range raw.Topics {
- if t == nil { // ignore topic when matching logs
+ switch topic := t.(type) {
+ case nil:
+ // ignore topic when matching logs
args.Topics[i] = []common.Hash{common.Hash{}}
- } else if topic, ok := t.(string); ok { // match specific topic
- top, err := topicConverter(topic)
+
+ case string:
+ // match specific topic
+ top, err := decodeTopic(topic)
if err != nil {
return err
}
args.Topics[i] = []common.Hash{top}
- } else if topics, ok := t.([]interface{}); ok { // or case e.g. [null, "topic0", "topic1"]
- for _, rawTopic := range topics {
+ case []interface{}:
+ // or case e.g. [null, "topic0", "topic1"]
+ for _, rawTopic := range topic {
if rawTopic == nil {
args.Topics[i] = append(args.Topics[i], common.Hash{})
} else if topic, ok := rawTopic.(string); ok {
- parsed, err := topicConverter(topic)
+ parsed, err := decodeTopic(topic)
if err != nil {
return err
}
@@ -534,7 +515,7 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
return fmt.Errorf("invalid topic(s)")
}
}
- } else {
+ default:
return fmt.Errorf("invalid topic(s)")
}
}
@@ -542,3 +523,19 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
return nil
}
+
+func decodeAddress(s string) (common.Address, error) {
+ b, err := hexutil.Decode(s)
+ if err == nil && len(b) != common.AddressLength {
+ err = fmt.Errorf("hex has invalid length %d after decoding", len(b))
+ }
+ return common.BytesToAddress(b), err
+}
+
+func decodeTopic(s string) (common.Hash, error) {
+ b, err := hexutil.Decode(s)
+ if err == nil && len(b) != common.HashLength {
+ err = fmt.Errorf("hex has invalid length %d after decoding", len(b))
+ }
+ return common.BytesToHash(b), err
+}
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index a095aa076..00edd90e1 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/rlp"
@@ -156,9 +157,9 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*typ
// TransactionCount returns the total number of transactions in the given block.
func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
- var num rpc.HexNumber
+ var num hexutil.Uint
err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash)
- return num.Uint(), err
+ return uint(num), err
}
// TransactionInBlock returns a single transaction at index in the given block.
@@ -196,11 +197,11 @@ func toBlockNumArg(number *big.Int) string {
}
type rpcProgress struct {
- StartingBlock rpc.HexNumber
- CurrentBlock rpc.HexNumber
- HighestBlock rpc.HexNumber
- PulledStates rpc.HexNumber
- KnownStates rpc.HexNumber
+ StartingBlock hexutil.Uint64
+ CurrentBlock hexutil.Uint64
+ HighestBlock hexutil.Uint64
+ PulledStates hexutil.Uint64
+ KnownStates hexutil.Uint64
}
// SyncProgress retrieves the current progress of the sync algorithm. If there's
@@ -220,11 +221,11 @@ func (ec *Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, err
return nil, err
}
return &ethereum.SyncProgress{
- StartingBlock: progress.StartingBlock.Uint64(),
- CurrentBlock: progress.CurrentBlock.Uint64(),
- HighestBlock: progress.HighestBlock.Uint64(),
- PulledStates: progress.PulledStates.Uint64(),
- KnownStates: progress.KnownStates.Uint64(),
+ StartingBlock: uint64(progress.StartingBlock),
+ CurrentBlock: uint64(progress.CurrentBlock),
+ HighestBlock: uint64(progress.HighestBlock),
+ PulledStates: uint64(progress.PulledStates),
+ KnownStates: uint64(progress.KnownStates),
}, nil
}
@@ -239,7 +240,7 @@ func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header)
// BalanceAt returns the wei balance of the given account.
// The block number can be nil, in which case the balance is taken from the latest known block.
func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
- var result rpc.HexNumber
+ var result hexutil.Big
err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber))
return (*big.Int)(&result), err
}
@@ -247,7 +248,7 @@ func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNu
// StorageAt returns the value of key in the contract storage of the given account.
// The block number can be nil, in which case the value is taken from the latest known block.
func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
- var result rpc.HexBytes
+ var result hexutil.Bytes
err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, toBlockNumArg(blockNumber))
return result, err
}
@@ -255,7 +256,7 @@ func (ec *Client) StorageAt(ctx context.Context, account common.Address, key com
// CodeAt returns the contract code of the given account.
// The block number can be nil, in which case the code is taken from the latest known block.
func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) {
- var result rpc.HexBytes
+ var result hexutil.Bytes
err := ec.c.CallContext(ctx, &result, "eth_getCode", account, toBlockNumArg(blockNumber))
return result, err
}
@@ -263,9 +264,9 @@ func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumbe
// NonceAt returns the account nonce of the given account.
// The block number can be nil, in which case the nonce is taken from the latest known block.
func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) {
- var result rpc.HexNumber
+ var result hexutil.Uint64
err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, toBlockNumArg(blockNumber))
- return result.Uint64(), err
+ return uint64(result), err
}
// Filters
@@ -286,7 +287,7 @@ func toFilterArg(q ethereum.FilterQuery) interface{} {
arg := map[string]interface{}{
"fromBlock": toBlockNumArg(q.FromBlock),
"toBlock": toBlockNumArg(q.ToBlock),
- "addresses": q.Addresses,
+ "address": q.Addresses,
"topics": q.Topics,
}
if q.FromBlock == nil {
@@ -299,21 +300,21 @@ func toFilterArg(q ethereum.FilterQuery) interface{} {
// PendingBalanceAt returns the wei balance of the given account in the pending state.
func (ec *Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) {
- var result rpc.HexNumber
+ var result hexutil.Big
err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, "pending")
return (*big.Int)(&result), err
}
// PendingStorageAt returns the value of key in the contract storage of the given account in the pending state.
func (ec *Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) {
- var result rpc.HexBytes
+ var result hexutil.Bytes
err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, "pending")
return result, err
}
// PendingCodeAt returns the contract code of the given account in the pending state.
func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
- var result rpc.HexBytes
+ var result hexutil.Bytes
err := ec.c.CallContext(ctx, &result, "eth_getCode", account, "pending")
return result, err
}
@@ -321,16 +322,16 @@ func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]
// PendingNonceAt returns the account nonce of the given account in the pending state.
// This is the nonce that should be used for the next transaction.
func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
- var result rpc.HexNumber
+ var result hexutil.Uint64
err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, "pending")
- return result.Uint64(), err
+ return uint64(result), err
}
// PendingTransactionCount returns the total number of transactions in the pending state.
func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) {
- var num rpc.HexNumber
+ var num hexutil.Uint
err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", "pending")
- return num.Uint(), err
+ return uint(num), err
}
// TODO: SubscribePendingTransactions (needs server side)
@@ -344,29 +345,29 @@ func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) {
// case the code is taken from the latest known block. Note that state from very old
// blocks might not be available.
func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
- var hex string
+ var hex hexutil.Bytes
err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), toBlockNumArg(blockNumber))
if err != nil {
return nil, err
}
- return common.FromHex(hex), nil
+ return hex, nil
}
// PendingCallContract executes a message call transaction using the EVM.
// The state seen by the contract call is the pending state.
func (ec *Client) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) {
- var hex string
+ var hex hexutil.Bytes
err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), "pending")
if err != nil {
return nil, err
}
- return common.FromHex(hex), nil
+ return hex, nil
}
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction.
func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
- var hex rpc.HexNumber
+ var hex hexutil.Big
if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil {
return nil, err
}
@@ -378,7 +379,7 @@ func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
// the true gas limit requirement as other transactions may be added or removed by miners,
// but it should provide a basis for setting a reasonable default.
func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) {
- var hex rpc.HexNumber
+ var hex hexutil.Big
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg))
if err != nil {
return nil, err
@@ -404,16 +405,16 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
"to": msg.To,
}
if len(msg.Data) > 0 {
- arg["data"] = fmt.Sprintf("%#x", msg.Data)
+ arg["data"] = hexutil.Bytes(msg.Data)
}
if msg.Value != nil {
- arg["value"] = fmt.Sprintf("%#x", msg.Value)
+ arg["value"] = (*hexutil.Big)(msg.Value)
}
if msg.Gas != nil {
- arg["gas"] = fmt.Sprintf("%#x", msg.Gas)
+ arg["gas"] = (*hexutil.Big)(msg.Gas)
}
if msg.GasPrice != nil {
- arg["gasPrice"] = fmt.Sprintf("%#x", msg.GasPrice)
+ arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
}
return arg
}