accounts/abi: simplified reflection logic

This commit is contained in:
Marius van der Wijden 2020-05-07 17:02:35 +02:00
parent a10793e412
commit d0a25e1967
3 changed files with 30 additions and 41 deletions

View file

@ -217,54 +217,41 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interfac
// unpackTuple unpacks ( hexdata -> go ) a batch of values. // unpackTuple unpacks ( hexdata -> go ) a batch of values.
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
var ( var (
value = reflect.ValueOf(v).Elem() value = reflect.ValueOf(v).Elem()
typ = value.Type() typ = value.Type()
kind = value.Kind() kind = value.Kind()
nonIndexedArgs = arguments.NonIndexed()
) )
if err := requireUnpackKind(value, len(nonIndexedArgs), arguments); err != nil {
return err
}
// If the interface is a struct, get of abi->struct_field mapping switch kind {
var abi2struct map[string]string case reflect.Struct:
if kind == reflect.Struct { k := 0
argNames := make([]string, len(nonIndexedArgs)) for i := 0; i < len(arguments); i++ {
for i, arg := range nonIndexedArgs { // Skip indexed fields
argNames[i] = arg.Name if arguments[i].Indexed {
} continue
var err error
if abi2struct, err = mapArgNamesToStructFields(argNames, value); err != nil {
return err
}
}
for i, arg := range nonIndexedArgs {
switch kind {
case reflect.Struct:
field := value.FieldByName(abi2struct[arg.Name])
if !field.IsValid() {
return fmt.Errorf("abi: field %s can't be found in the given value", arg.Name)
} }
if err := unpack(&arg.Type, field.Addr().Interface(), marshalledValues[i]); err != nil { if i >= value.NumField() {
return fmt.Errorf("Invalid field length while unpacking: %v", i)
}
if err := set(value.Field(i), reflect.ValueOf(marshalledValues[k])); err != nil {
return err return err
} }
case reflect.Slice, reflect.Array: k++
if value.Len() < i {
return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len())
}
v := value.Index(i)
if err := requireAssignable(v, reflect.ValueOf(marshalledValues[i])); err != nil {
return err
}
if err := unpack(&arg.Type, v.Addr().Interface(), marshalledValues[i]); err != nil {
return err
}
default:
return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ)
} }
case reflect.Slice, reflect.Array:
for i := 0; i < value.Len(); i++ {
// Skip indexed fields
if arguments[i].Indexed {
continue
}
if err := set(value.Index(i), reflect.ValueOf(marshalledValues[i])); err != nil {
return err
}
}
default:
return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ)
} }
return nil return nil
} }
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,

View file

@ -167,6 +167,8 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) {
func TestEventTupleUnpack(t *testing.T) { func TestEventTupleUnpack(t *testing.T) {
type EventTransfer struct { type EventTransfer struct {
From common.Address
To common.Address
Value *big.Int Value *big.Int
} }

View file

@ -91,7 +91,7 @@ func set(dst, src reflect.Value) error {
dst.Set(src) dst.Set(src)
case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice && dst.CanSet(): case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice && dst.CanSet():
return setSlice(dst, src) return setSlice(dst, src)
case dstType.Kind() == reflect.Array: case dstType.Kind() == reflect.Array && dst.CanSet():
return setArray(dst, src) return setArray(dst, src)
case dstType.Kind() == reflect.Struct: case dstType.Kind() == reflect.Struct:
return setStruct(dst, src) return setStruct(dst, src)