aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/abi/abi.go
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/abi/abi.go')
-rw-r--r--accounts/abi/abi.go59
1 files changed, 29 insertions, 30 deletions
diff --git a/accounts/abi/abi.go b/accounts/abi/abi.go
index 32df6f19d..1b07b2f68 100644
--- a/accounts/abi/abi.go
+++ b/accounts/abi/abi.go
@@ -238,8 +238,16 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) error {
return fmt.Errorf("abi: unmarshalling empty output")
}
- value := reflect.ValueOf(v).Elem()
- typ := value.Type()
+ // make sure the passed value is a pointer
+ valueOf := reflect.ValueOf(v)
+ if reflect.Ptr != valueOf.Kind() {
+ return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
+ }
+
+ var (
+ value = valueOf.Elem()
+ typ = value.Type()
+ )
if len(method.Outputs) > 1 {
switch value.Kind() {
@@ -268,6 +276,25 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) error {
return fmt.Errorf("abi: cannot marshal tuple in to slice %T (only []interface{} is supported)", v)
}
+ // if the slice already contains values, set those instead of the interface slice itself.
+ if value.Len() > 0 {
+ if len(method.Outputs) > value.Len() {
+ return fmt.Errorf("abi: cannot marshal in to slices of unequal size (require: %v, got: %v)", len(method.Outputs), value.Len())
+ }
+
+ for i := 0; i < len(method.Outputs); i++ {
+ marshalledValue, err := toGoType(i, method.Outputs[i], output)
+ if err != nil {
+ return err
+ }
+ reflectValue := reflect.ValueOf(marshalledValue)
+ if err := set(value.Index(i).Elem(), reflectValue, method.Outputs[i]); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
// create a new slice and start appending the unmarshalled
// values to the new interface slice.
z := reflect.MakeSlice(typ, 0, len(method.Outputs))
@@ -296,34 +323,6 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) error {
return nil
}
-// set attempts to assign src to dst by either setting, copying or otherwise.
-//
-// set is a bit more lenient when it comes to assignment and doesn't force an as
-// strict ruleset as bare `reflect` does.
-func set(dst, src reflect.Value, output Argument) error {
- dstType := dst.Type()
- srcType := src.Type()
-
- switch {
- case dstType.AssignableTo(src.Type()):
- dst.Set(src)
- case dstType.Kind() == reflect.Array && srcType.Kind() == reflect.Slice:
- if !dstType.Elem().AssignableTo(r_byte) {
- return fmt.Errorf("abi: cannot unmarshal %v in to array of elem %v", src.Type(), dstType.Elem())
- }
-
- if dst.Len() < output.Type.SliceSize {
- return fmt.Errorf("abi: cannot unmarshal src (len=%d) in to dst (len=%d)", output.Type.SliceSize, dst.Len())
- }
- reflect.Copy(dst, src)
- case dstType.Kind() == reflect.Interface:
- dst.Set(src)
- default:
- return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type())
- }
- return nil
-}
-
func (abi *ABI) UnmarshalJSON(data []byte) error {
var fields []struct {
Type string