Skip to content

Commit da58afc

Browse files
dshulyakfjl
authored andcommitted
accounts/abi: update array length after parsing array (ethereum#15618)
Fixes ethereum#15617
1 parent ce823c9 commit da58afc

File tree

4 files changed

+78
-26
lines changed

4 files changed

+78
-26
lines changed

accounts/abi/event.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,16 @@ func (e Event) tupleUnpack(v interface{}, output []byte) error {
7171
if input.Indexed {
7272
// can't read, continue
7373
continue
74-
} else if input.Type.T == ArrayTy {
75-
// need to move this up because they read sequentially
76-
j += input.Type.Size
7774
}
7875
marshalledValue, err := toGoType((i+j)*32, input.Type, output)
7976
if err != nil {
8077
return err
8178
}
79+
if input.Type.T == ArrayTy {
80+
// combined index ('i' + 'j') need to be adjusted only by size of array, thus
81+
// we need to decrement 'j' because 'i' was incremented
82+
j += input.Type.Size - 1
83+
}
8284
reflectValue := reflect.ValueOf(marshalledValue)
8385

8486
switch value.Kind() {

accounts/abi/event_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@
1717
package abi
1818

1919
import (
20+
"bytes"
21+
"reflect"
2022
"strings"
2123
"testing"
2224

2325
"github.com/ethereum/go-ethereum/common"
2426
"github.com/ethereum/go-ethereum/crypto"
27+
"github.com/stretchr/testify/require"
2528
)
2629

2730
func TestEventId(t *testing.T) {
@@ -54,3 +57,23 @@ func TestEventId(t *testing.T) {
5457
}
5558
}
5659
}
60+
61+
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
62+
func TestEventMultiValueWithArrayUnpack(t *testing.T) {
63+
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
64+
type testStruct struct {
65+
Value1 [2]uint8
66+
Value2 uint8
67+
}
68+
abi, err := JSON(strings.NewReader(definition))
69+
require.NoError(t, err)
70+
var b bytes.Buffer
71+
var i uint8 = 1
72+
for ; i <= 3; i++ {
73+
b.Write(packNum(reflect.ValueOf(i)))
74+
}
75+
var rst testStruct
76+
require.NoError(t, abi.Unpack(&rst, "test", b.Bytes()))
77+
require.Equal(t, [2]uint8{1, 2}, rst.Value1)
78+
require.Equal(t, uint8(3), rst.Value2)
79+
}

accounts/abi/method.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,15 @@ func (method Method) tupleUnpack(v interface{}, output []byte) error {
9595
j := 0
9696
for i := 0; i < len(method.Outputs); i++ {
9797
toUnpack := method.Outputs[i]
98-
if toUnpack.Type.T == ArrayTy {
99-
// need to move this up because they read sequentially
100-
j += toUnpack.Type.Size
101-
}
10298
marshalledValue, err := toGoType((i+j)*32, toUnpack.Type, output)
10399
if err != nil {
104100
return err
105101
}
102+
if toUnpack.Type.T == ArrayTy {
103+
// combined index ('i' + 'j') need to be adjusted only by size of array, thus
104+
// we need to decrement 'j' because 'i' was incremented
105+
j += toUnpack.Type.Size - 1
106+
}
106107
reflectValue := reflect.ValueOf(marshalledValue)
107108

108109
switch value.Kind() {

accounts/abi/unpack_test.go

+45-19
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"math/big"
2424
"reflect"
25+
"strconv"
2526
"strings"
2627
"testing"
2728

@@ -261,25 +262,27 @@ var unpackTests = []unpackTest{
261262

262263
func TestUnpack(t *testing.T) {
263264
for i, test := range unpackTests {
264-
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
265-
abi, err := JSON(strings.NewReader(def))
266-
if err != nil {
267-
t.Fatalf("invalid ABI definition %s: %v", def, err)
268-
}
269-
encb, err := hex.DecodeString(test.enc)
270-
if err != nil {
271-
t.Fatalf("invalid hex: %s" + test.enc)
272-
}
273-
outptr := reflect.New(reflect.TypeOf(test.want))
274-
err = abi.Unpack(outptr.Interface(), "method", encb)
275-
if err := test.checkError(err); err != nil {
276-
t.Errorf("test %d (%v) failed: %v", i, test.def, err)
277-
continue
278-
}
279-
out := outptr.Elem().Interface()
280-
if !reflect.DeepEqual(test.want, out) {
281-
t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.want, out)
282-
}
265+
t.Run(strconv.Itoa(i), func(t *testing.T) {
266+
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
267+
abi, err := JSON(strings.NewReader(def))
268+
if err != nil {
269+
t.Fatalf("invalid ABI definition %s: %v", def, err)
270+
}
271+
encb, err := hex.DecodeString(test.enc)
272+
if err != nil {
273+
t.Fatalf("invalid hex: %s" + test.enc)
274+
}
275+
outptr := reflect.New(reflect.TypeOf(test.want))
276+
err = abi.Unpack(outptr.Interface(), "method", encb)
277+
if err := test.checkError(err); err != nil {
278+
t.Errorf("test %d (%v) failed: %v", i, test.def, err)
279+
return
280+
}
281+
out := outptr.Elem().Interface()
282+
if !reflect.DeepEqual(test.want, out) {
283+
t.Errorf("test %d (%v) failed: expected %v, got %v", i, test.def, test.want, out)
284+
}
285+
})
283286
}
284287
}
285288

@@ -336,6 +339,29 @@ func TestMultiReturnWithStruct(t *testing.T) {
336339
}
337340
}
338341

342+
func TestMultiReturnWithArray(t *testing.T) {
343+
const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
344+
abi, err := JSON(strings.NewReader(definition))
345+
if err != nil {
346+
t.Fatal(err)
347+
}
348+
buff := new(bytes.Buffer)
349+
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000009"))
350+
buff.Write(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000008"))
351+
352+
ret1, ret1Exp := new([3]uint64), [3]uint64{9, 9, 9}
353+
ret2, ret2Exp := new(uint64), uint64(8)
354+
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
355+
t.Fatal(err)
356+
}
357+
if !reflect.DeepEqual(*ret1, ret1Exp) {
358+
t.Error("array result", *ret1, "!= Expected", ret1Exp)
359+
}
360+
if *ret2 != ret2Exp {
361+
t.Error("int result", *ret2, "!= Expected", ret2Exp)
362+
}
363+
}
364+
339365
func TestUnmarshal(t *testing.T) {
340366
const definition = `[
341367
{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },

0 commit comments

Comments
 (0)