diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 26699b9699..5bad029223 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -217,54 +217,41 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues interfac // unpackTuple unpacks ( hexdata -> go ) a batch of values. func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error { var ( - value = reflect.ValueOf(v).Elem() - typ = value.Type() - kind = value.Kind() - nonIndexedArgs = arguments.NonIndexed() + value = reflect.ValueOf(v).Elem() + typ = value.Type() + kind = value.Kind() ) - if err := requireUnpackKind(value, len(nonIndexedArgs), arguments); err != nil { - return err - } - // If the interface is a struct, get of abi->struct_field mapping - var abi2struct map[string]string - if kind == reflect.Struct { - argNames := make([]string, len(nonIndexedArgs)) - for i, arg := range nonIndexedArgs { - argNames[i] = arg.Name - } - 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) + switch kind { + case reflect.Struct: + k := 0 + for i := 0; i < len(arguments); i++ { + // Skip indexed fields + if arguments[i].Indexed { + continue } - 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 } - case reflect.Slice, reflect.Array: - 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) + k++ } + 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 - } // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, diff --git a/accounts/abi/event_test.go b/accounts/abi/event_test.go index 28da4c5024..cf35e40123 100644 --- a/accounts/abi/event_test.go +++ b/accounts/abi/event_test.go @@ -167,6 +167,8 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) { func TestEventTupleUnpack(t *testing.T) { type EventTransfer struct { + From common.Address + To common.Address Value *big.Int } diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 0c839ba996..48914b2b90 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -91,7 +91,7 @@ func set(dst, src reflect.Value) error { dst.Set(src) case dstType.Kind() == reflect.Slice && srcType.Kind() == reflect.Slice && dst.CanSet(): return setSlice(dst, src) - case dstType.Kind() == reflect.Array: + case dstType.Kind() == reflect.Array && dst.CanSet(): return setArray(dst, src) case dstType.Kind() == reflect.Struct: return setStruct(dst, src)