From b7f9ce5e45c59d936a2f9b64264bbdfc468d8ca7 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Fri, 1 May 2020 17:32:59 +0200 Subject: [PATCH] accounts/abi: added getType func to Type struct --- accounts/abi/type.go | 42 +++++++++++++++++++++++++++++++- accounts/abi/unpack.go | 48 ++++++++++++++++++++----------------- accounts/abi/unpack_test.go | 2 +- 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 6975dab14d..9401de1711 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -23,6 +23,8 @@ import ( "regexp" "strconv" "strings" + + "github.com/ethereum/go-ethereum/common" ) // Type enumerator @@ -55,6 +57,7 @@ type Type struct { TupleRawName string // Raw struct name defined in source code, may be empty. TupleElems []*Type // Type information of all tuple fields TupleRawNames []string // Raw field name of all tuple fields + TupelType reflect.Type } var ( @@ -180,7 +183,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty } fields = append(fields, reflect.StructField{ Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field. - Type: cType.Type, + Type: cType.getType(), Tag: reflect.StructTag("json:\"" + c.Name + "\""), }) elems = append(elems, &cType) @@ -191,6 +194,8 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty } } expression += ")" + + typ.TupelType = reflect.StructOf(fields) typ.Type = reflect.StructOf(fields) typ.TupleElems = elems typ.TupleRawNames = names @@ -218,6 +223,41 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty return } +func (t Type) getType() reflect.Type { + switch t.T { + case IntTy: + return reflectIntType(false, t.Size) + case UintTy: + return reflectIntType(true, t.Size) + case BoolTy: + return reflect.TypeOf(false) + case StringTy: + return reflect.TypeOf("") + case SliceTy: + return reflect.SliceOf(t.Elem.getType()) + case ArrayTy: + return reflect.ArrayOf(t.Size, t.Elem.getType()) + case TupleTy: + return t.TupelType + case AddressTy: + return reflect.TypeOf(common.Address{}) + case FixedBytesTy: + return reflect.ArrayOf(t.Size, reflect.TypeOf(byte(0))) + case BytesTy: + return reflect.SliceOf(reflect.TypeOf(byte(0))) + case HashTy: + // hashtype currently not used + return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) + case FixedPointTy: + // fixedpoint type currently not used + return reflect.ArrayOf(32, reflect.TypeOf(byte(0))) + case FunctionTy: + return reflect.ArrayOf(24, reflect.TypeOf(byte(0))) + default: + panic("Invalid type") + } +} + // String implements Stringer func (t Type) String() (out string) { return t.stringKind diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index dede1a5f7d..d492ffd171 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -34,32 +34,36 @@ var ( // ReadInteger reads the integer based on its kind and returns the appropriate value func ReadInteger(typ Type, b []byte) interface{} { - switch typ.Type { - case uint8T: - return b[len(b)-1] - case uint16T: - return binary.BigEndian.Uint16(b[len(b)-2:]) - case uint32T: - return binary.BigEndian.Uint32(b[len(b)-4:]) - case uint64T: - return binary.BigEndian.Uint64(b[len(b)-8:]) - case int8T: + if typ.T == UintTy { + switch typ.Size { + case 8: + return b[len(b)-1] + case 16: + return binary.BigEndian.Uint16(b[len(b)-2:]) + case 32: + return binary.BigEndian.Uint32(b[len(b)-4:]) + case 64: + return binary.BigEndian.Uint64(b[len(b)-8:]) + default: + // the only case left for unsigned integer is uint256. + return new(big.Int).SetBytes(b) + } + } + switch typ.Size { + case 8: return int8(b[len(b)-1]) - case int16T: + case 16: return int16(binary.BigEndian.Uint16(b[len(b)-2:])) - case int32T: + case 32: return int32(binary.BigEndian.Uint32(b[len(b)-4:])) - case int64T: + case 64: return int64(binary.BigEndian.Uint64(b[len(b)-8:])) default: - // the only case left for integer is int256/uint256. - ret := new(big.Int).SetBytes(b) - if typ.T == UintTy { - return ret - } + // the only case left for integer is int256 // big.SetBytes can't tell if a number is negative or positive in itself. // On EVM, if the returned number > max int256, it is negative. // A number is > max int256 if the bit at position 255 is set. + ret := new(big.Int).SetBytes(b) if ret.Bit(255) == 1 { ret.Add(MaxUint256, new(big.Int).Neg(ret)) ret.Add(ret, common.Big1) @@ -106,7 +110,7 @@ func ReadFixedBytes(t Type, word []byte) (interface{}, error) { return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") } // convert - array := reflect.New(t.Type).Elem() + array := reflect.New(reflect.ArrayOf(t.Size, reflect.TypeOf(byte(0)))).Elem() reflect.Copy(array, reflect.ValueOf(word[0:t.Size])) return array.Interface(), nil @@ -127,10 +131,10 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) if t.T == SliceTy { // declare our slice - refSlice = reflect.MakeSlice(t.Type, size, size) + refSlice = reflect.MakeSlice(t.getType(), size, size) } else if t.T == ArrayTy { // declare our array - refSlice = reflect.New(t.Type).Elem() + refSlice = reflect.New(t.getType()).Elem() } else { return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") } @@ -154,7 +158,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) } func forTupleUnpack(t Type, output []byte) (interface{}, error) { - retval := reflect.New(t.Type).Elem() + retval := reflect.New(t.getType()) virtualArgs := 0 for index, elem := range t.TupleElems { marshalledValue, err := ToGoType((index+virtualArgs)*32, *elem, output) diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 97a2723080..7a590b4b4b 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -33,7 +33,7 @@ import ( // TestUnpack tests the general pack/unpack tests in packing_test.go func TestUnpack(t *testing.T) { for i, test := range packUnpackTests { - t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Run(strconv.Itoa(i)+" "+test.def, func(t *testing.T) { //Unpack def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def) abi, err := JSON(strings.NewReader(def))