aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/abi
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/abi')
-rw-r--r--accounts/abi/abi.go2
-rw-r--r--accounts/abi/argument.go50
-rw-r--r--accounts/abi/reflect.go16
3 files changed, 49 insertions, 19 deletions
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
+}