Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GC] uint256 rather than big.Int in Transaction #614

Merged
merged 11 commits into from
Jun 4, 2020
Next Next commit
uint256 in rlp
  • Loading branch information
yperbasis committed May 31, 2020
commit 067a2eae415f8c13618cc47070f11b9cc9bccdde
32 changes: 32 additions & 0 deletions rlp/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
"reflect"
"strings"
"sync"

"github.com/holiman/uint256"
)

//lint:ignore ST1012 EOL is not an error.
Expand Down Expand Up @@ -146,6 +148,7 @@ func addErrorContext(err error, ctx string) error {
var (
decoderInterface = reflect.TypeOf(new(Decoder)).Elem()
bigInt = reflect.TypeOf(big.Int{})
uint256Int = reflect.TypeOf(uint256.Int{})
)

func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
Expand All @@ -157,6 +160,10 @@ func makeDecoder(typ reflect.Type, tags tags) (dec decoder, err error) {
return decodeBigInt, nil
case typ.AssignableTo(bigInt):
return decodeBigIntNoPtr, nil
case typ.AssignableTo(reflect.PtrTo(uint256Int)):
return decodeUint256, nil
case typ.AssignableTo(uint256Int):
return decodeUint256NoPtr, nil
case kind == reflect.Ptr:
return makePtrDecoder(typ, tags)
case reflect.PtrTo(typ).Implements(decoderInterface):
Expand Down Expand Up @@ -237,6 +244,31 @@ func decodeBigInt(s *Stream, val reflect.Value) error {
return nil
}

func decodeUint256NoPtr(s *Stream, val reflect.Value) error {
return decodeUint256(s, val.Addr())
}

func decodeUint256(s *Stream, val reflect.Value) error {
b, err := s.Bytes()
if err != nil {
return wrapStreamError(err, val.Type())
}
if len(b) > 32 {
return wrapStreamError(errUintOverflow, val.Type())
}
i := val.Interface().(*uint256.Int)
if i == nil {
i = new(uint256.Int)
val.Set(reflect.ValueOf(i))
}
// Reject leading zero bytes
if len(b) > 0 && b[0] == 0 {
return wrapStreamError(ErrCanonInt, val.Type())
}
i.SetBytes(b)
return nil
}

func makeListDecoder(typ reflect.Type, tag tags) (decoder, error) {
etype := typ.Elem()
if etype.Kind() == reflect.Uint8 && !reflect.PtrTo(etype).Implements(decoderInterface) {
Expand Down
21 changes: 17 additions & 4 deletions rlp/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"reflect"
"strings"
"testing"

"github.com/holiman/uint256"
)

func TestStreamKind(t *testing.T) {
Expand Down Expand Up @@ -370,10 +372,11 @@ type intField struct {
}

var (
veryBigInt = big.NewInt(0).Add(
big.NewInt(0).Lsh(big.NewInt(0xFFFFFFFFFFFFFF), 16),
big.NewInt(0xFFFF),
veryBigInt = uint256.NewInt().Add(
uint256.NewInt().Lsh(uint256.NewInt().SetUint64(0xFFFFFFFFFFFFFF), 16),
uint256.NewInt().SetUint64(0xFFFF),
)
realBigInt = big.NewInt(0).SetBytes(unhex("010000000000000000000000000000000000000000000000000000000000000000"))
)

type hasIgnoredField struct {
Expand Down Expand Up @@ -451,12 +454,22 @@ var decodeTests = []decodeTest{

// big ints
{input: "01", ptr: new(*big.Int), value: big.NewInt(1)},
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt},
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*big.Int), value: veryBigInt.ToBig()},
{input: "A1010000000000000000000000000000000000000000000000000000000000000000", ptr: new(*big.Int), value: realBigInt},
{input: "10", ptr: new(big.Int), value: *big.NewInt(16)}, // non-pointer also works
{input: "C0", ptr: new(*big.Int), error: "rlp: expected input string or byte for *big.Int"},
{input: "820001", ptr: new(big.Int), error: "rlp: non-canonical integer (leading zero bytes) for *big.Int"},
{input: "8105", ptr: new(big.Int), error: "rlp: non-canonical size information for *big.Int"},

// uint256
{input: "01", ptr: new(*uint256.Int), value: uint256.NewInt().SetUint64(1)},
{input: "89FFFFFFFFFFFFFFFFFF", ptr: new(*uint256.Int), value: veryBigInt},
{input: "A1010000000000000000000000000000000000000000000000000000000000000000", ptr: new(*uint256.Int), error: "rlp: input string too long for *uint256.Int"},
{input: "10", ptr: new(uint256.Int), value: *uint256.NewInt().SetUint64(16)}, // non-pointer also works
{input: "C0", ptr: new(*uint256.Int), error: "rlp: expected input string or byte for *uint256.Int"},
{input: "820001", ptr: new(uint256.Int), error: "rlp: non-canonical integer (leading zero bytes) for *uint256.Int"},
{input: "8105", ptr: new(uint256.Int), error: "rlp: non-canonical size information for *uint256.Int"},

// structs
{
input: "C50583343434",
Expand Down
29 changes: 29 additions & 0 deletions rlp/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
"math/big"
"reflect"
"sync"

"github.com/holiman/uint256"
)

// https://github.com/ethereum/wiki/wiki/RLP
Expand Down Expand Up @@ -344,6 +346,10 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
return writeBigIntPtr, nil
case typ.AssignableTo(bigInt):
return writeBigIntNoPtr, nil
case typ.AssignableTo(reflect.PtrTo(uint256Int)):
return writeUint256Ptr, nil
case typ.AssignableTo(uint256Int):
return writeUint256NoPtr, nil
case kind == reflect.Ptr:
return makePtrWriter(typ, ts)
case reflect.PtrTo(typ).Implements(encoderInterface):
Expand Down Expand Up @@ -428,6 +434,29 @@ func writeBigInt(i *big.Int, w *encbuf) error {
return nil
}

func writeUint256Ptr(val reflect.Value, w *encbuf) error {
ptr := val.Interface().(*uint256.Int)
if ptr == nil {
w.str = append(w.str, EmptyStringCode)
return nil
}
return writeUint256(ptr, w)
}

func writeUint256NoPtr(val reflect.Value, w *encbuf) error {
i := val.Interface().(uint256.Int)
return writeUint256(&i, w)
}

func writeUint256(i *uint256.Int, w *encbuf) error {
if i.IsZero() {
w.str = append(w.str, EmptyStringCode)
} else {
w.encodeString(i.Bytes())
}
return nil
}

func writeBytes(val reflect.Value, w *encbuf) error {
w.encodeString(val.Bytes())
return nil
Expand Down
28 changes: 28 additions & 0 deletions rlp/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"math/big"
"sync"
"testing"

"github.com/holiman/uint256"
)

type testEncoder struct {
Expand Down Expand Up @@ -137,6 +139,31 @@ var encTests = []encTest{
// negative ints are not supported
{val: big.NewInt(-1), error: "rlp: cannot encode negative *big.Int"},

// uint256 integers (should match uint for small values)
{val: uint256.NewInt(), output: "80"},
{val: uint256.NewInt().SetUint64(1), output: "01"},
{val: uint256.NewInt().SetUint64(127), output: "7F"},
{val: uint256.NewInt().SetUint64(128), output: "8180"},
{val: uint256.NewInt().SetUint64(256), output: "820100"},
{val: uint256.NewInt().SetUint64(1024), output: "820400"},
{val: uint256.NewInt().SetUint64(0xFFFFFF), output: "83FFFFFF"},
{val: uint256.NewInt().SetUint64(0xFFFFFFFF), output: "84FFFFFFFF"},
{val: uint256.NewInt().SetUint64(0xFFFFFFFFFF), output: "85FFFFFFFFFF"},
{val: uint256.NewInt().SetUint64(0xFFFFFFFFFFFF), output: "86FFFFFFFFFFFF"},
{val: uint256.NewInt().SetUint64(0xFFFFFFFFFFFFFF), output: "87FFFFFFFFFFFFFF"},
{
val: uint256.NewInt().SetBytes(unhex("102030405060708090A0B0C0D0E0F2")),
output: "8F102030405060708090A0B0C0D0E0F2",
},
{
val: uint256.NewInt().SetBytes(unhex("0100020003000400050006000700080009000A000B000C000D000E01")),
output: "9C0100020003000400050006000700080009000A000B000C000D000E01",
},

// non-pointer uint256.Int
{val: *uint256.NewInt(), output: "80"},
{val: *uint256.NewInt().SetUint64(0xFFFFFF), output: "83FFFFFF"},

// byte slices, strings
{val: []byte{}, output: "80"},
{val: []byte{0x7E}, output: "7E"},
Expand Down Expand Up @@ -242,6 +269,7 @@ var encTests = []encTest{
{val: (*[]byte)(nil), output: "80"},
{val: (*[10]byte)(nil), output: "80"},
{val: (*big.Int)(nil), output: "80"},
{val: (*uint256.Int)(nil), output: "80"},
{val: (*[]string)(nil), output: "C0"},
{val: (*[10]string)(nil), output: "C0"},
{val: (*[]interface{})(nil), output: "C0"},
Expand Down