From 41168fc6810984a56866380545e4fb7dbf93710e Mon Sep 17 00:00:00 2001 From: weimumu <934657014@qq.com> Date: Fri, 28 Dec 2018 18:21:04 +0800 Subject: [PATCH] add function to unpack dynamic data in slice or array --- accounts/abi/argument.go | 2 +- accounts/abi/type.go | 4 ++++ accounts/abi/unpack.go | 4 ++-- accounts/abi/unpack_test.go | 18 ++++++++++++++---- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 90fd9d05fc..212c5a6859 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -202,7 +202,7 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) { virtualArgs := 0 for index, arg := range arguments.NonIndexed() { marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data) - if arg.Type.T == ArrayTy && (*arg.Type.Elem).T != StringTy { + if arg.Type.T == ArrayTy && !(*arg.Type.Elem).isDynamicType() { // If we have a static array, like [3]uint256, these are coded as // just like uint256,uint256,uint256. // This means that we need to add two 'virtual' arguments when diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 6bfaabf5a5..a926921f18 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -234,6 +234,10 @@ func isDynamicType(t Type) bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) } +func (t Type) isDynamicType() bool { + return isDynamicType(t) +} + // getDynamicTypeOffset returns the offset for the type. // See `isDynamicType` to know which types are considered dynamic. // If the type t is an array and element type is not a dynamic type, then we consider it a static type and diff --git a/accounts/abi/unpack.go b/accounts/abi/unpack.go index 04716f7a2a..a7d147031a 100644 --- a/accounts/abi/unpack.go +++ b/accounts/abi/unpack.go @@ -195,12 +195,12 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) { switch t.T { case SliceTy: - if (*t.Elem).T == StringTy { + if (*t.Elem).isDynamicType() { return forEachUnpack(t, output[begin:], 0, end) } return forEachUnpack(t, output, begin, end) case ArrayTy: - if (*t.Elem).T == StringTy { + if (*t.Elem).isDynamicType() { offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:])) return forEachUnpack(t, output[offset:], 0, t.Size) } diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index defcddc486..14891ddbb4 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -173,8 +173,8 @@ var unpackTests = []unpackTest{ // multi dimensional, if these pass, all types that don't require length prefix should pass { def: `[{"type": "uint8[][]"}]`, - enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", - want: [][]uint8{{1, 2}, {1, 2}}, + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", + want: [][]uint8{{1, 2}, {1, 2, 3}}, }, { def: `[{"type": "uint8[2][2]"}]`, @@ -183,8 +183,8 @@ var unpackTests = []unpackTest{ }, { def: `[{"type": "uint8[][2]"}]`, - enc: "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001", - want: [2][]uint8{{1}, {1}}, + enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: [2][]uint8{{1, 2}, {2}}, }, { def: `[{"type": "uint8[2][]"}]`, @@ -251,6 +251,16 @@ var unpackTests = []unpackTest{ enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b676f2d657468657265756d000000000000000000000000000000000000000000", want: []string{"Ethereum", "go-ethereum"}, }, + { + def: `[{"type": "bytes[]"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003f0f0f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003f0f0f00000000000000000000000000000000000000000000000000000000000", + want: [][]byte{{0xf0, 0xf0, 0xf0}, {0xf0, 0xf0, 0xf0}}, + }, + { + def: `[{"type": "uint256[2][][]"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000003e8", + want: [][][2]*big.Int{{{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}, {{big.NewInt(1), big.NewInt(200)}, {big.NewInt(1), big.NewInt(1000)}}}, + }, { def: `[{"type": "int8[]"}]`, enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",