Skip to content

Commit 7353434

Browse files
weimumugballet
authored andcommitted
fix string array unpack bug in accounts/abi (#18364)
1 parent 9e9fc87 commit 7353434

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

accounts/abi/argument.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
202202
virtualArgs := 0
203203
for index, arg := range arguments.NonIndexed() {
204204
marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data)
205-
if arg.Type.T == ArrayTy {
205+
if arg.Type.T == ArrayTy && (*arg.Type.Elem).T != StringTy {
206206
// If we have a static array, like [3]uint256, these are coded as
207207
// just like uint256,uint256,uint256.
208208
// This means that we need to add two 'virtual' arguments when

accounts/abi/unpack.go

+7
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,15 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
195195

196196
switch t.T {
197197
case SliceTy:
198+
if (*t.Elem).T == StringTy {
199+
return forEachUnpack(t, output[begin:], 0, end)
200+
}
198201
return forEachUnpack(t, output, begin, end)
199202
case ArrayTy:
203+
if (*t.Elem).T == StringTy {
204+
offset := int64(binary.BigEndian.Uint64(returnOutput[len(returnOutput)-8:]))
205+
return forEachUnpack(t, output[offset:], 0, t.Size)
206+
}
200207
return forEachUnpack(t, output, index, t.Size)
201208
case StringTy: // variable arrays are written at the end of the return bytes
202209
return string(output[begin : begin+end]), nil

accounts/abi/unpack_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,16 @@ var unpackTests = []unpackTest{
241241
enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
242242
want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
243243
},
244+
{
245+
def: `[{"type": "string[4]"}]`,
246+
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b476f2d657468657265756d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000",
247+
want: [4]string{"Hello", "World", "Go-ethereum", "Ethereum"},
248+
},
249+
{
250+
def: `[{"type": "string[]"}]`,
251+
enc: "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b676f2d657468657265756d000000000000000000000000000000000000000000",
252+
want: []string{"Ethereum", "go-ethereum"},
253+
},
244254
{
245255
def: `[{"type": "int8[]"}]`,
246256
enc: "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
@@ -516,6 +526,57 @@ func TestMultiReturnWithArray(t *testing.T) {
516526
}
517527
}
518528

529+
func TestMultiReturnWithStringArray(t *testing.T) {
530+
const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]`
531+
abi, err := JSON(strings.NewReader(definition))
532+
if err != nil {
533+
t.Fatal(err)
534+
}
535+
buff := new(bytes.Buffer)
536+
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000005c1b78ea0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000001a055690d9db80000000000000000000000000000ab1257528b3782fb40d7ed5f72e624b744dffb2f00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008457468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001048656c6c6f2c20457468657265756d2100000000000000000000000000000000"))
537+
temp, _ := big.NewInt(0).SetString("30000000000000000000", 10)
538+
ret1, ret1Exp := new([3]*big.Int), [3]*big.Int{big.NewInt(1545304298), big.NewInt(6), temp}
539+
ret2, ret2Exp := new(common.Address), common.HexToAddress("ab1257528b3782fb40d7ed5f72e624b744dffb2f")
540+
ret3, ret3Exp := new([2]string), [2]string{"Ethereum", "Hello, Ethereum!"}
541+
ret4, ret4Exp := new(bool), false
542+
if err := abi.Unpack(&[]interface{}{ret1, ret2, ret3, ret4}, "multi", buff.Bytes()); err != nil {
543+
t.Fatal(err)
544+
}
545+
if !reflect.DeepEqual(*ret1, ret1Exp) {
546+
t.Error("big.Int array result", *ret1, "!= Expected", ret1Exp)
547+
}
548+
if !reflect.DeepEqual(*ret2, ret2Exp) {
549+
t.Error("address result", *ret2, "!= Expected", ret2Exp)
550+
}
551+
if !reflect.DeepEqual(*ret3, ret3Exp) {
552+
t.Error("string array result", *ret3, "!= Expected", ret3Exp)
553+
}
554+
if !reflect.DeepEqual(*ret4, ret4Exp) {
555+
t.Error("bool result", *ret4, "!= Expected", ret4Exp)
556+
}
557+
}
558+
559+
func TestMultiReturnWithStringSlice(t *testing.T) {
560+
const definition = `[{"name" : "multi", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]`
561+
abi, err := JSON(strings.NewReader(definition))
562+
if err != nil {
563+
t.Fatal(err)
564+
}
565+
buff := new(bytes.Buffer)
566+
buff.Write(common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008657468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b676f2d657468657265756d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000065"))
567+
ret1, ret1Exp := new([]string), []string{"ethereum", "go-ethereum"}
568+
ret2, ret2Exp := new([]*big.Int), []*big.Int{big.NewInt(100), big.NewInt(101)}
569+
if err := abi.Unpack(&[]interface{}{ret1, ret2}, "multi", buff.Bytes()); err != nil {
570+
t.Fatal(err)
571+
}
572+
if !reflect.DeepEqual(*ret1, ret1Exp) {
573+
t.Error("string slice result", *ret1, "!= Expected", ret1Exp)
574+
}
575+
if !reflect.DeepEqual(*ret2, ret2Exp) {
576+
t.Error("uint256 slice result", *ret2, "!= Expected", ret2Exp)
577+
}
578+
}
579+
519580
func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
520581
// Similar to TestMultiReturnWithArray, but with a special case in mind:
521582
// values of nested static arrays count towards the size as well, and any element following

0 commit comments

Comments
 (0)