diff options
author | Jeffrey Wilcke <geffobscura@gmail.com> | 2016-05-11 19:21:25 +0800 |
---|---|---|
committer | Jeffrey Wilcke <geffobscura@gmail.com> | 2016-05-11 19:36:27 +0800 |
commit | 91a7a4a7867718ccb6c9620120a1be5680ad0abd (patch) | |
tree | f8b6b278efe61a68c6a6c0bc88d0b7ca792ccd9d /accounts/abi/reflect.go | |
parent | 5782164a35ea8acdb09507a604c45941051fd5f3 (diff) | |
download | go-tangerine-91a7a4a7867718ccb6c9620120a1be5680ad0abd.tar go-tangerine-91a7a4a7867718ccb6c9620120a1be5680ad0abd.tar.gz go-tangerine-91a7a4a7867718ccb6c9620120a1be5680ad0abd.tar.bz2 go-tangerine-91a7a4a7867718ccb6c9620120a1be5680ad0abd.tar.lz go-tangerine-91a7a4a7867718ccb6c9620120a1be5680ad0abd.tar.xz go-tangerine-91a7a4a7867718ccb6c9620120a1be5680ad0abd.tar.zst go-tangerine-91a7a4a7867718ccb6c9620120a1be5680ad0abd.zip |
accounts/abi: fixed unpacking in to already slice interfaces
Previously it was assumed that wheneven type `[]interface{}` was given
that the interface was empty. The abigen rightfully assumed that
interface slices which already have pre-allocated variable sets to be
assigned.
This PR fixes that by checking that the given `[]interface{}` is larger
than zero and assigns each value using the generic `set` function (this
function has also been moved to abi/reflect.go) and checks whether the
assignment was possible.
The generic assignment function `set` now also deals with pointers
(useful for interface slice mentioned above) by dereferencing the
pointer until it finds a setable type.
Diffstat (limited to 'accounts/abi/reflect.go')
-rw-r--r-- | accounts/abi/reflect.go | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/accounts/abi/reflect.go b/accounts/abi/reflect.go index 780c64c66..ab5020200 100644 --- a/accounts/abi/reflect.go +++ b/accounts/abi/reflect.go @@ -16,7 +16,10 @@ package abi -import "reflect" +import ( + "fmt" + "reflect" +) // indirect recursively dereferences the value until it either gets the value // or finds a big.Int @@ -62,3 +65,33 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value { reflect.Copy(slice, value) return slice } + +// 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) + case dstType.Kind() == reflect.Ptr: + return set(dst.Elem(), src, output) + default: + return fmt.Errorf("abi: cannot unmarshal %v in to %v", src.Type(), dst.Type()) + } + return nil +} |