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.
This commit is contained in:
protolambda 2017-12-29 00:34:33 +01:00 committed by Martin Holst Swende
parent 0e147cce0f
commit f428ef3e5d
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0

View file

@ -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 // this value will become our slice or our array, depending on the type
var refSlice reflect.Value var refSlice reflect.Value
slice := output[start : start+size*32]
if t.T == SliceTy { if t.T == SliceTy {
// declare our slice // 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") 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 { for i, j := start, 0; j < size; j++ {
// 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
}
inter, err := toGoType(i, *t.Elem, output) inter, err := toGoType(i, *t.Elem, output)
if err != nil { if err != nil {
return nil, err 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 // append the item to our reflect slice
refSlice.Index(j).Set(reflect.ValueOf(inter)) refSlice.Index(j).Set(reflectedInter)
} }
// return the interface // return the interface