From 60a999f238fca7c83b26ecf94257ee648afe4df9 Mon Sep 17 00:00:00 2001 From: Javier Peletier Date: Mon, 5 Mar 2018 16:01:40 +0100 Subject: accounts/abi: Modified unpackAtomic to accept struct lvalues --- accounts/abi/abi.go | 2 +- accounts/abi/argument.go | 50 +++++++++++++++++++++++++++++++----------------- accounts/abi/reflect.go | 16 ++++++++++++++++ 3 files changed, 49 insertions(+), 19 deletions(-) (limited to 'accounts/abi') diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go index da2ef9178..254b1f7fb 100644 --- a/accounts/abi/abi.go +++ b/accounts/abi/abi.go @@ -86,7 +86,7 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { } return method.Outputs.Unpack(v, output) } else if event, ok := abi.Events[name]; ok { - return event.Inputs.unpackTuple(v, output) + return event.Inputs.Unpack(v, output) } return fmt.Errorf("abi: could not locate named method or event") } diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 1b480da60..512d8fdfa 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -113,16 +113,8 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa } // If the output interface is a struct, make sure names don't collide if kind == reflect.Struct { - exists := make(map[string]bool) - for _, arg := range arguments { - field := capitalise(arg.Name) - if field == "" { - return fmt.Errorf("abi: purely underscored output cannot unpack to struct") - } - if exists[field] { - return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) - } - exists[field] = true + if err := requireUniqueStructFieldNames(arguments); err != nil { + return err } } for i, arg := range arguments.NonIndexed() { @@ -131,14 +123,9 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa switch kind { case reflect.Struct: - name := capitalise(arg.Name) - for j := 0; j < typ.NumField(); j++ { - // TODO read tags: `abi:"fieldName"` - if typ.Field(j).Name == name { - if err := set(value.Field(j), reflectValue, arg); err != nil { - return err - } - } + err := unpackStruct(value, reflectValue, arg) + if err != nil { + return err } case reflect.Slice, reflect.Array: if value.Len() < i { @@ -165,8 +152,20 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interf return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) } elem := reflect.ValueOf(v).Elem() + kind := elem.Kind() reflectValue := reflect.ValueOf(marshalledValues[0]) + + if kind == reflect.Struct { + //make sure names don't collide + if err := requireUniqueStructFieldNames(arguments); err != nil { + return err + } + + return unpackStruct(elem, reflectValue, arguments[0]) + } + return set(elem, reflectValue, arguments.NonIndexed()[0]) + } // Computes the full size of an array; @@ -278,3 +277,18 @@ func capitalise(input string) string { } return strings.ToUpper(input[:1]) + input[1:] } + +//unpackStruct extracts each argument into its corresponding struct field +func unpackStruct(value, reflectValue reflect.Value, arg Argument) error { + name := capitalise(arg.Name) + typ := value.Type() + for j := 0; j < typ.NumField(); j++ { + // TODO read tags: `abi:"fieldName"` + if typ.Field(j).Name == name { + if err := set(value.Field(j), reflectValue, arg); err != nil { + return err + } + } + } + return nil +} diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 7a9cdacd5..2e6bf7098 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -110,3 +110,19 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, } return nil } + +// requireUniqueStructFieldNames makes sure field names don't collide +func requireUniqueStructFieldNames(args Arguments) error { + exists := make(map[string]bool) + for _, arg := range args { + field := capitalise(arg.Name) + if field == "" { + return fmt.Errorf("abi: purely underscored output cannot unpack to struct") + } + if exists[field] { + return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) + } + exists[field] = true + } + return nil +} -- cgit v1.2.3