From f428ef3e5d009846f35ae1691a1de854f120aa93 Mon Sep 17 00:00:00 2001 From: protolambda Date: Fri, 29 Dec 2017 00:34:33 +0100 Subject: [PATCH] accounts/abi: bugfix for unpacking nested arrays The code previously assumed the arrays/slices were always 1 level deep. While the packing supports nested arrays (!!!). The current code for unpacking doesn't return the "consumed" length, so this fix had to work around that by calculating it (i.e. packing and getting resulting length) after the unpacking of the array element. It's far from ideal, but unpacking behaviour is fixed now. --- accounts/abi/unpack.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 761c80edfd..33b5b994c5 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -104,7 +104,6 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) // this value will become our slice or our array, depending on the type var refSlice reflect.Value - slice := output[start : start+size*32] if t.T == SliceTy { // declare our slice @@ -116,17 +115,25 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") } - for i, j := start, 0; j*32 < len(slice); i, j = i+32, j+1 { - // this corrects the arrangement so that we get all the underlying array values - if t.Elem.T == ArrayTy && j != 0 { - i = start + t.Elem.Size*32*j - } + for i, j := start, 0; j < size; j++ { inter, err := toGoType(i, *t.Elem, output) if err != nil { return nil, err } + + reflectedInter := reflect.ValueOf(inter) + + //Although we just did the reverse, pack it, to get the length of the actual element. + //Getting the length directly from the "toGoType" would be way better, + // but it requires some refactoring to get it return the *consumed* length. + interPacked, err := t.Elem.pack(reflectedInter) + if err != nil { + return nil, err + } + i += len(interPacked) + // append the item to our reflect slice - refSlice.Index(j).Set(reflect.ValueOf(inter)) + refSlice.Index(j).Set(reflectedInter) } // return the interface