accounts/abi: added getType func to Type struct

This commit is contained in:
Marius van der Wijden 2020-05-01 17:32:59 +02:00
parent 5e45db7610
commit b7f9ce5e45
3 changed files with 68 additions and 24 deletions

View file

@ -23,6 +23,8 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/ethereum/go-ethereum/common"
) )
// Type enumerator // Type enumerator
@ -55,6 +57,7 @@ type Type struct {
TupleRawName string // Raw struct name defined in source code, may be empty. TupleRawName string // Raw struct name defined in source code, may be empty.
TupleElems []*Type // Type information of all tuple fields TupleElems []*Type // Type information of all tuple fields
TupleRawNames []string // Raw field name of all tuple fields TupleRawNames []string // Raw field name of all tuple fields
TupelType reflect.Type
} }
var ( var (
@ -180,7 +183,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
} }
fields = append(fields, reflect.StructField{ fields = append(fields, reflect.StructField{
Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field. Name: ToCamelCase(c.Name), // reflect.StructOf will panic for any exported field.
Type: cType.Type, Type: cType.getType(),
Tag: reflect.StructTag("json:\"" + c.Name + "\""), Tag: reflect.StructTag("json:\"" + c.Name + "\""),
}) })
elems = append(elems, &cType) elems = append(elems, &cType)
@ -191,6 +194,8 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
} }
} }
expression += ")" expression += ")"
typ.TupelType = reflect.StructOf(fields)
typ.Type = reflect.StructOf(fields) typ.Type = reflect.StructOf(fields)
typ.TupleElems = elems typ.TupleElems = elems
typ.TupleRawNames = names typ.TupleRawNames = names
@ -218,6 +223,41 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
return 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 // String implements Stringer
func (t Type) String() (out string) { func (t Type) String() (out string) {
return t.stringKind return t.stringKind

View file

@ -34,32 +34,36 @@ var (
// ReadInteger reads the integer based on its kind and returns the appropriate value // ReadInteger reads the integer based on its kind and returns the appropriate value
func ReadInteger(typ Type, b []byte) interface{} { func ReadInteger(typ Type, b []byte) interface{} {
switch typ.Type { if typ.T == UintTy {
case uint8T: switch typ.Size {
return b[len(b)-1] case 8:
case uint16T: return b[len(b)-1]
return binary.BigEndian.Uint16(b[len(b)-2:]) case 16:
case uint32T: return binary.BigEndian.Uint16(b[len(b)-2:])
return binary.BigEndian.Uint32(b[len(b)-4:]) case 32:
case uint64T: return binary.BigEndian.Uint32(b[len(b)-4:])
return binary.BigEndian.Uint64(b[len(b)-8:]) case 64:
case int8T: 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]) return int8(b[len(b)-1])
case int16T: case 16:
return int16(binary.BigEndian.Uint16(b[len(b)-2:])) return int16(binary.BigEndian.Uint16(b[len(b)-2:]))
case int32T: case 32:
return int32(binary.BigEndian.Uint32(b[len(b)-4:])) return int32(binary.BigEndian.Uint32(b[len(b)-4:]))
case int64T: case 64:
return int64(binary.BigEndian.Uint64(b[len(b)-8:])) return int64(binary.BigEndian.Uint64(b[len(b)-8:]))
default: default:
// the only case left for integer is int256/uint256. // the only case left for integer is int256
ret := new(big.Int).SetBytes(b)
if typ.T == UintTy {
return ret
}
// big.SetBytes can't tell if a number is negative or positive in itself. // 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. // On EVM, if the returned number > max int256, it is negative.
// A number is > max int256 if the bit at position 255 is set. // A number is > max int256 if the bit at position 255 is set.
ret := new(big.Int).SetBytes(b)
if ret.Bit(255) == 1 { if ret.Bit(255) == 1 {
ret.Add(MaxUint256, new(big.Int).Neg(ret)) ret.Add(MaxUint256, new(big.Int).Neg(ret))
ret.Add(ret, common.Big1) 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") return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
} }
// convert // 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])) reflect.Copy(array, reflect.ValueOf(word[0:t.Size]))
return array.Interface(), nil return array.Interface(), nil
@ -127,10 +131,10 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
if t.T == SliceTy { if t.T == SliceTy {
// declare our slice // declare our slice
refSlice = reflect.MakeSlice(t.Type, size, size) refSlice = reflect.MakeSlice(t.getType(), size, size)
} else if t.T == ArrayTy { } else if t.T == ArrayTy {
// declare our array // declare our array
refSlice = reflect.New(t.Type).Elem() refSlice = reflect.New(t.getType()).Elem()
} else { } else {
return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") 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) { func forTupleUnpack(t Type, output []byte) (interface{}, error) {
retval := reflect.New(t.Type).Elem() retval := reflect.New(t.getType())
virtualArgs := 0 virtualArgs := 0
for index, elem := range t.TupleElems { for index, elem := range t.TupleElems {
marshalledValue, err := ToGoType((index+virtualArgs)*32, *elem, output) marshalledValue, err := ToGoType((index+virtualArgs)*32, *elem, output)

View file

@ -33,7 +33,7 @@ import (
// TestUnpack tests the general pack/unpack tests in packing_test.go // TestUnpack tests the general pack/unpack tests in packing_test.go
func TestUnpack(t *testing.T) { func TestUnpack(t *testing.T) {
for i, test := range packUnpackTests { 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 //Unpack
def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def) def := fmt.Sprintf(`[{ "name" : "method", "type": "function", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(def)) abi, err := JSON(strings.NewReader(def))