From ded4e8a290ac97b10b1aad6476f64c1edcd2b14a Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Tue, 6 Nov 2018 17:34:40 +0100 Subject: [PATCH 1/9] added tests for new abi encoding features (#4) * added tests from bytes32[][] and string[] * added offset to other types * formatting --- accounts/abi/pack_test.go | 69 +++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 58a5b7a581e2..5f802fce07a5 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -42,7 +42,7 @@ func TestPack(t *testing.T) { { "uint8[]", []uint8{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint16", @@ -52,7 +52,7 @@ func TestPack(t *testing.T) { { "uint16[]", []uint16{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint32", @@ -62,7 +62,7 @@ func TestPack(t *testing.T) { { "uint32[]", []uint32{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint64", @@ -72,7 +72,7 @@ func TestPack(t *testing.T) { { "uint64[]", []uint64{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint256", @@ -82,7 +82,7 @@ func TestPack(t *testing.T) { { "uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int8", @@ -92,7 +92,7 @@ func TestPack(t *testing.T) { { "int8[]", []int8{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int16", @@ -102,7 +102,7 @@ func TestPack(t *testing.T) { { "int16[]", []int16{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int32", @@ -112,7 +112,7 @@ func TestPack(t *testing.T) { { "int32[]", []int32{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int64", @@ -122,7 +122,7 @@ func TestPack(t *testing.T) { { "int64[]", []int64{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int256", @@ -132,7 +132,7 @@ func TestPack(t *testing.T) { { "int256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "bytes1", @@ -305,14 +305,21 @@ func TestPack(t *testing.T) { common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"), }, { + //web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']); "address[]", []common.Address{{1}, {2}}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000100000000000000000000000000000000000000" + + "0000000000000000000000000200000000000000000000000000000000000000"), }, { "bytes32[]", []common.Hash{{1}, {2}}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + //offset: 32 + "0000000000000000000000000000000000000000000000000000000000000002" + //len: 2 + "0100000000000000000000000000000000000000000000000000000000000000" + // 1 + "0200000000000000000000000000000000000000000000000000000000000000"), // 2 }, { "function", @@ -322,7 +329,41 @@ func TestPack(t *testing.T) { { "string", "foobar", - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset: 32 + "0000000000000000000000000000000000000000000000000000000000000006" + // len: 6 + "666f6f6261720000000000000000000000000000000000000000000000000000"), // "foobar" + }, + { + "string[]", + []string{"hello", "foobar"}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 + "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1 + "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 + "68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0] + "0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6 + "666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1] + }, + { + + //web3.eth.abi.encodeParameter('bytes32[][]', [['0x0100000000000000000000000000000000000000000000000000000000000000', + // '0x0200000000000000000000000000000000000000000000000000000000000000'],['0x0300000000000000000000000000000000000000000000000000000000000000', + // '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]); + "bytes32[][]", + [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 + "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 + "0100000000000000000000000000000000000000000000000000000000000000" + // array[0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3 + "0300000000000000000000000000000000000000000000000000000000000000" + // array[0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[2] + }, } { typ, err := NewType(test.typ) @@ -336,7 +377,7 @@ func TestPack(t *testing.T) { } if !bytes.Equal(output, test.output) { - t.Errorf("%d failed. Expected bytes: '%x' Got: '%x'", i, test.output, output) + t.Errorf("input %d for typ: %v failed. Expected bytes: '%x' Got: '%x'", i, typ.String(), test.output, output) } } } From dabca31d797623d43bd780721fc0ad461d24be53 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 7 Nov 2018 11:50:21 +0100 Subject: [PATCH 2/9] Abi/dynamic types (#5) --- accounts/abi/pack_test.go | 40 +++++++++++++-------------------- accounts/abi/type.go | 47 +++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 5f802fce07a5..0fb93856d90d 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -42,7 +42,7 @@ func TestPack(t *testing.T) { { "uint8[]", []uint8{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint16", @@ -52,7 +52,7 @@ func TestPack(t *testing.T) { { "uint16[]", []uint16{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint32", @@ -62,7 +62,7 @@ func TestPack(t *testing.T) { { "uint32[]", []uint32{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint64", @@ -72,7 +72,7 @@ func TestPack(t *testing.T) { { "uint64[]", []uint64{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint256", @@ -82,7 +82,7 @@ func TestPack(t *testing.T) { { "uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int8", @@ -92,7 +92,7 @@ func TestPack(t *testing.T) { { "int8[]", []int8{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int16", @@ -102,7 +102,7 @@ func TestPack(t *testing.T) { { "int16[]", []int16{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int32", @@ -112,7 +112,7 @@ func TestPack(t *testing.T) { { "int32[]", []int32{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int64", @@ -122,7 +122,7 @@ func TestPack(t *testing.T) { { "int64[]", []int64{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int256", @@ -132,7 +132,7 @@ func TestPack(t *testing.T) { { "int256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "bytes1", @@ -308,18 +308,12 @@ func TestPack(t *testing.T) { //web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']); "address[]", []common.Address{{1}, {2}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + - "0000000000000000000000000000000000000000000000000000000000000002" + - "0000000000000000000000000100000000000000000000000000000000000000" + - "0000000000000000000000000200000000000000000000000000000000000000"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"), }, { "bytes32[]", []common.Hash{{1}, {2}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + //offset: 32 - "0000000000000000000000000000000000000000000000000000000000000002" + //len: 2 - "0100000000000000000000000000000000000000000000000000000000000000" + // 1 - "0200000000000000000000000000000000000000000000000000000000000000"), // 2 + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"), }, { "function", @@ -329,15 +323,12 @@ func TestPack(t *testing.T) { { "string", "foobar", - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset: 32 - "0000000000000000000000000000000000000000000000000000000000000006" + // len: 6 - "666f6f6261720000000000000000000000000000000000000000000000000000"), // "foobar" + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"), }, { "string[]", []string{"hello", "foobar"}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 - "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1 "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 @@ -352,8 +343,7 @@ func TestPack(t *testing.T) { // '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]); "bytes32[][]", [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 - "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 diff --git a/accounts/abi/type.go b/accounts/abi/type.go index dce89d2b4ee4..eeb42e7d7c05 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -183,23 +183,43 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { return nil, err } - if t.T == SliceTy || t.T == ArrayTy { - var packed []byte + switch t.T { + case SliceTy, ArrayTy: + var ret []byte + if t.requiresLengthPrefix() { + // append length + ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) + } + + // calculate offset if any + offset := 0 + offsetReq := t.Elem.requiresLengthPrefix() + if offsetReq { + offset = getOffset(*t.Elem) * v.Len() + } + + var tail []byte for i := 0; i < v.Len(); i++ { val, err := t.Elem.pack(v.Index(i)) if err != nil { return nil, err } - packed = append(packed, val...) - } - if t.T == SliceTy { - return packBytesSlice(packed, v.Len()), nil - } else if t.T == ArrayTy { - return packed, nil + + if !offsetReq { + ret = append(ret, val...) + continue + } + + ret = append(ret, packNum(reflect.ValueOf(offset))...) + offset += len(val) + tail = append(tail, val...) } + + return append(ret, tail...), nil + default: + return packElement(t, v), nil } - return packElement(t, v), nil } // requireLengthPrefix returns whether the type requires any sort of length @@ -207,3 +227,12 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { func (t Type) requiresLengthPrefix() bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy } + +// getOffset returns the offset to be added for t +func getOffset(t Type) int { + if t.T == ArrayTy { + return 32 * t.Size + } + + return 32 +} From fc490afef77e3b7207b58259aaf7a3289aba9207 Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 7 Nov 2018 11:59:32 +0100 Subject: [PATCH 3/9] Revert "Abi/dynamic types (#5)" (#6) This reverts commit dabca31d797623d43bd780721fc0ad461d24be53. --- accounts/abi/pack_test.go | 40 ++++++++++++++++++++------------- accounts/abi/type.go | 47 ++++++++------------------------------- 2 files changed, 34 insertions(+), 53 deletions(-) diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 0fb93856d90d..5f802fce07a5 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -42,7 +42,7 @@ func TestPack(t *testing.T) { { "uint8[]", []uint8{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint16", @@ -52,7 +52,7 @@ func TestPack(t *testing.T) { { "uint16[]", []uint16{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint32", @@ -62,7 +62,7 @@ func TestPack(t *testing.T) { { "uint32[]", []uint32{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint64", @@ -72,7 +72,7 @@ func TestPack(t *testing.T) { { "uint64[]", []uint64{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint256", @@ -82,7 +82,7 @@ func TestPack(t *testing.T) { { "uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int8", @@ -92,7 +92,7 @@ func TestPack(t *testing.T) { { "int8[]", []int8{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int16", @@ -102,7 +102,7 @@ func TestPack(t *testing.T) { { "int16[]", []int16{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int32", @@ -112,7 +112,7 @@ func TestPack(t *testing.T) { { "int32[]", []int32{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int64", @@ -122,7 +122,7 @@ func TestPack(t *testing.T) { { "int64[]", []int64{1, 2}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int256", @@ -132,7 +132,7 @@ func TestPack(t *testing.T) { { "int256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "bytes1", @@ -308,12 +308,18 @@ func TestPack(t *testing.T) { //web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']); "address[]", []common.Address{{1}, {2}}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "0000000000000000000000000100000000000000000000000000000000000000" + + "0000000000000000000000000200000000000000000000000000000000000000"), }, { "bytes32[]", []common.Hash{{1}, {2}}, - common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + //offset: 32 + "0000000000000000000000000000000000000000000000000000000000000002" + //len: 2 + "0100000000000000000000000000000000000000000000000000000000000000" + // 1 + "0200000000000000000000000000000000000000000000000000000000000000"), // 2 }, { "function", @@ -323,12 +329,15 @@ func TestPack(t *testing.T) { { "string", "foobar", - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"), + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset: 32 + "0000000000000000000000000000000000000000000000000000000000000006" + // len: 6 + "666f6f6261720000000000000000000000000000000000000000000000000000"), // "foobar" }, { "string[]", []string{"hello", "foobar"}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1 "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 @@ -343,7 +352,8 @@ func TestPack(t *testing.T) { // '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]); "bytes32[][]", [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 diff --git a/accounts/abi/type.go b/accounts/abi/type.go index eeb42e7d7c05..dce89d2b4ee4 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -183,43 +183,23 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { return nil, err } - switch t.T { - case SliceTy, ArrayTy: - var ret []byte + if t.T == SliceTy || t.T == ArrayTy { + var packed []byte - if t.requiresLengthPrefix() { - // append length - ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) - } - - // calculate offset if any - offset := 0 - offsetReq := t.Elem.requiresLengthPrefix() - if offsetReq { - offset = getOffset(*t.Elem) * v.Len() - } - - var tail []byte for i := 0; i < v.Len(); i++ { val, err := t.Elem.pack(v.Index(i)) if err != nil { return nil, err } - - if !offsetReq { - ret = append(ret, val...) - continue - } - - ret = append(ret, packNum(reflect.ValueOf(offset))...) - offset += len(val) - tail = append(tail, val...) + packed = append(packed, val...) + } + if t.T == SliceTy { + return packBytesSlice(packed, v.Len()), nil + } else if t.T == ArrayTy { + return packed, nil } - - return append(ret, tail...), nil - default: - return packElement(t, v), nil } + return packElement(t, v), nil } // requireLengthPrefix returns whether the type requires any sort of length @@ -227,12 +207,3 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { func (t Type) requiresLengthPrefix() bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy } - -// getOffset returns the offset to be added for t -func getOffset(t Type) int { - if t.T == ArrayTy { - return 32 * t.Size - } - - return 32 -} From 758feaeb58512ea09ce9a60441c1a15639b47eeb Mon Sep 17 00:00:00 2001 From: Vedhavyas Singareddi Date: Wed, 7 Nov 2018 17:23:45 +0100 Subject: [PATCH 4/9] Abi/dynamic types (#7) --- accounts/abi/argument.go | 22 +++++------ accounts/abi/pack_test.go | 77 ++++++++++++++++++++++++++------------- accounts/abi/type.go | 60 +++++++++++++++++++++++++----- 3 files changed, 113 insertions(+), 46 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 93b513c346df..453af7441c43 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -243,12 +243,9 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { // input offset is the bytes offset for packed output inputOffset := 0 for _, abiArg := range abiArgs { - if abiArg.Type.T == ArrayTy { - inputOffset += 32 * abiArg.Type.Size - } else { - inputOffset += 32 - } + inputOffset += getOffset(abiArg.Type) } + var ret []byte for i, a := range args { input := abiArgs[i] @@ -257,14 +254,15 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { if err != nil { return nil, err } - // check for a slice type (string, bytes, slice) - if input.Type.requiresLengthPrefix() { - // calculate the offset - offset := inputOffset + len(variableInput) + // check for dynamic types)= + if offsetRequired(input.Type) { // set the offset - ret = append(ret, packNum(reflect.ValueOf(offset))...) - // Append the packed output to the variable input. The variable input - // will be appended at the end of the input. + ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) + + // calculate next offset + inputOffset += len(packed) + + // append to variable input variableInput = append(variableInput, packed...) } else { // append the packed value to the input diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 5f802fce07a5..4ccc9a304367 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -42,7 +42,7 @@ func TestPack(t *testing.T) { { "uint8[]", []uint8{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint16", @@ -52,7 +52,7 @@ func TestPack(t *testing.T) { { "uint16[]", []uint16{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint32", @@ -62,7 +62,7 @@ func TestPack(t *testing.T) { { "uint32[]", []uint32{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint64", @@ -72,7 +72,7 @@ func TestPack(t *testing.T) { { "uint64[]", []uint64{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "uint256", @@ -82,7 +82,7 @@ func TestPack(t *testing.T) { { "uint256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int8", @@ -92,7 +92,7 @@ func TestPack(t *testing.T) { { "int8[]", []int8{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int16", @@ -102,7 +102,7 @@ func TestPack(t *testing.T) { { "int16[]", []int16{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int32", @@ -112,7 +112,7 @@ func TestPack(t *testing.T) { { "int32[]", []int32{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int64", @@ -122,7 +122,7 @@ func TestPack(t *testing.T) { { "int64[]", []int64{1, 2}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "int256", @@ -132,7 +132,7 @@ func TestPack(t *testing.T) { { "int256[]", []*big.Int{big.NewInt(1), big.NewInt(2)}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"), }, { "bytes1", @@ -308,18 +308,12 @@ func TestPack(t *testing.T) { //web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']); "address[]", []common.Address{{1}, {2}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + - "0000000000000000000000000000000000000000000000000000000000000002" + - "0000000000000000000000000100000000000000000000000000000000000000" + - "0000000000000000000000000200000000000000000000000000000000000000"), + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"), }, { "bytes32[]", []common.Hash{{1}, {2}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + //offset: 32 - "0000000000000000000000000000000000000000000000000000000000000002" + //len: 2 - "0100000000000000000000000000000000000000000000000000000000000000" + // 1 - "0200000000000000000000000000000000000000000000000000000000000000"), // 2 + common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"), }, { "function", @@ -329,15 +323,12 @@ func TestPack(t *testing.T) { { "string", "foobar", - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset: 32 - "0000000000000000000000000000000000000000000000000000000000000006" + // len: 6 - "666f6f6261720000000000000000000000000000000000000000000000000000"), // "foobar" + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"), }, { "string[]", []string{"hello", "foobar"}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 - "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1 "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 @@ -345,6 +336,16 @@ func TestPack(t *testing.T) { "0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6 "666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1] }, + { + "string[2]", + []string{"hello", "foobar"}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset to hello + "0000000000000000000000000000000000000000000000000000000000000080" + // offset to foobar + "0000000000000000000000000000000000000000000000000000000000000005" + // length of hello + "68656c6c6f000000000000000000000000000000000000000000000000000000" + // encoded foobar + "0000000000000000000000000000000000000000000000000000000000000006" + // length of foobar + "666f6f6261720000000000000000000000000000000000000000000000000000"), // encoded foobar + }, { //web3.eth.abi.encodeParameter('bytes32[][]', [['0x0100000000000000000000000000000000000000000000000000000000000000', @@ -352,8 +353,7 @@ func TestPack(t *testing.T) { // '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]); "bytes32[][]", [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000020" + // offset array 32 - "0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 @@ -365,6 +365,33 @@ func TestPack(t *testing.T) { "0500000000000000000000000000000000000000000000000000000000000000"), // array[2] }, + + { + "bytes32[][2]", + [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 + "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 + "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 + "0100000000000000000000000000000000000000000000000000000000000000" + // array[0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3 + "0300000000000000000000000000000000000000000000000000000000000000" + // array[0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[2] + + }, + + { + "bytes32[3][2]", + [][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}}, + common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000" + // array[0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0300000000000000000000000000000000000000000000000000000000000000" + // array[2] + "0300000000000000000000000000000000000000000000000000000000000000" + // array[0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[2] + + }, } { typ, err := NewType(test.typ) if err != nil { diff --git a/accounts/abi/type.go b/accounts/abi/type.go index dce89d2b4ee4..ef775ce807dc 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -183,23 +183,43 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { return nil, err } - if t.T == SliceTy || t.T == ArrayTy { - var packed []byte + switch t.T { + case SliceTy, ArrayTy: + var ret []byte + if t.requiresLengthPrefix() { + // append length + ret = append(ret, packNum(reflect.ValueOf(v.Len()))...) + } + + // calculate offset if any + offset := 0 + offsetReq := offsetRequired(*t.Elem) + if offsetReq { + offset = getOffset(*t.Elem) * v.Len() + } + + var tail []byte for i := 0; i < v.Len(); i++ { val, err := t.Elem.pack(v.Index(i)) if err != nil { return nil, err } - packed = append(packed, val...) - } - if t.T == SliceTy { - return packBytesSlice(packed, v.Len()), nil - } else if t.T == ArrayTy { - return packed, nil + + if !offsetReq { + ret = append(ret, val...) + continue + } + + ret = append(ret, packNum(reflect.ValueOf(offset))...) + offset += len(val) + tail = append(tail, val...) } + + return append(ret, tail...), nil + default: + return packElement(t, v), nil } - return packElement(t, v), nil } // requireLengthPrefix returns whether the type requires any sort of length @@ -207,3 +227,25 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { func (t Type) requiresLengthPrefix() bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy } + +// offsetRequired returns true if the type is considered dynamic +func offsetRequired(t Type) bool { + // dynamic types + // array is also a dynamic type if the array type is dynamic + if t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && offsetRequired(*t.Elem)) { + return true + } + + return false +} + +// getOffset returns the offset to be added for t +func getOffset(t Type) int { + // if it is an array and there are no dynamic types + // then the array is static type + if t.T == ArrayTy && !offsetRequired(*t.Elem) { + return 32 * t.Size + } + + return 32 +} From e024c16f34c6028060b645efae1d6258e442442a Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Wed, 7 Nov 2018 17:26:37 +0100 Subject: [PATCH 5/9] some cleanup --- accounts/abi/pack_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 4ccc9a304367..8491e3fe7337 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -305,7 +305,6 @@ func TestPack(t *testing.T) { common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"), }, { - //web3.eth.abi.encodeParameter('address[]', ['0x0100000000000000000000000000000000000000','0x0200000000000000000000000000000000000000']); "address[]", []common.Address{{1}, {2}}, common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"), @@ -347,10 +346,6 @@ func TestPack(t *testing.T) { "666f6f6261720000000000000000000000000000000000000000000000000000"), // encoded foobar }, { - - //web3.eth.abi.encodeParameter('bytes32[][]', [['0x0100000000000000000000000000000000000000000000000000000000000000', - // '0x0200000000000000000000000000000000000000000000000000000000000000'],['0x0300000000000000000000000000000000000000000000000000000000000000', - // '0x0400000000000000000000000000000000000000000000000000000000000000','0x0500000000000000000000000000000000000000000000000000000000000000']]); "bytes32[][]", [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 From b65b3d25125b48af7e5f714b08c49611707be932 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Nov 2018 10:53:27 +0100 Subject: [PATCH 6/9] Apply suggestions from code review apply suggestions Co-Authored-By: vedhavyas --- accounts/abi/argument.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 453af7441c43..d91f32027858 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -254,7 +254,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { if err != nil { return nil, err } - // check for dynamic types)= + // check for dynamic types if offsetRequired(input.Type) { // set the offset ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) From 9810e35a66cf17e9f8f8fbe0fb6dded1db44cdb7 Mon Sep 17 00:00:00 2001 From: Manuel Polzhofer Date: Thu, 15 Nov 2018 17:38:19 +0100 Subject: [PATCH 7/9] added better formatting (#8) --- accounts/abi/argument.go | 3 -- accounts/abi/pack_test.go | 59 +++++++++++++++++++-------------------- accounts/abi/type.go | 11 +------- 3 files changed, 29 insertions(+), 44 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index d91f32027858..b5e6cd185883 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -245,7 +245,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { for _, abiArg := range abiArgs { inputOffset += getOffset(abiArg.Type) } - var ret []byte for i, a := range args { input := abiArgs[i] @@ -258,10 +257,8 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { if offsetRequired(input.Type) { // set the offset ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) - // calculate next offset inputOffset += len(packed) - // append to variable input variableInput = append(variableInput, packed...) } else { diff --git a/accounts/abi/pack_test.go b/accounts/abi/pack_test.go index 8491e3fe7337..ddd2b7362d5a 100644 --- a/accounts/abi/pack_test.go +++ b/accounts/abi/pack_test.go @@ -328,8 +328,8 @@ func TestPack(t *testing.T) { "string[]", []string{"hello", "foobar"}, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 - "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 - "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i=1 + "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0 + "0000000000000000000000000000000000000000000000000000000000000080" + // offset 128 to i = 1 "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 "68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0] "0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6 @@ -338,54 +338,51 @@ func TestPack(t *testing.T) { { "string[2]", []string{"hello", "foobar"}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset to hello - "0000000000000000000000000000000000000000000000000000000000000080" + // offset to foobar - "0000000000000000000000000000000000000000000000000000000000000005" + // length of hello - "68656c6c6f000000000000000000000000000000000000000000000000000000" + // encoded foobar - "0000000000000000000000000000000000000000000000000000000000000006" + // length of foobar - "666f6f6261720000000000000000000000000000000000000000000000000000"), // encoded foobar + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset to i = 0 + "0000000000000000000000000000000000000000000000000000000000000080" + // offset to i = 1 + "0000000000000000000000000000000000000000000000000000000000000005" + // len(str[0]) = 5 + "68656c6c6f000000000000000000000000000000000000000000000000000000" + // str[0] + "0000000000000000000000000000000000000000000000000000000000000006" + // len(str[1]) = 6 + "666f6f6261720000000000000000000000000000000000000000000000000000"), // str[1] }, { "bytes32[][]", [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000002" + // len(array) = 2 - "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 - "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 + "0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0 + "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1 "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 - "0100000000000000000000000000000000000000000000000000000000000000" + // array[0] - "0200000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1] "0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3 - "0300000000000000000000000000000000000000000000000000000000000000" + // array[0] - "0400000000000000000000000000000000000000000000000000000000000000" + // array[1] - "0500000000000000000000000000000000000000000000000000000000000000"), // array[2] - + "0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2] }, { "bytes32[][2]", [][]common.Hash{{{1}, {2}}, {{3}, {4}, {5}}}, - common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i=0 - "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i=1 + common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000040" + // offset 64 to i = 0 + "00000000000000000000000000000000000000000000000000000000000000a0" + // offset 160 to i = 1 "0000000000000000000000000000000000000000000000000000000000000002" + // len(array[0]) = 2 - "0100000000000000000000000000000000000000000000000000000000000000" + // array[0] - "0200000000000000000000000000000000000000000000000000000000000000" + // array[1] + "0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1] "0000000000000000000000000000000000000000000000000000000000000003" + // len(array[1]) = 3 - "0300000000000000000000000000000000000000000000000000000000000000" + // array[0] - "0400000000000000000000000000000000000000000000000000000000000000" + // array[1] - "0500000000000000000000000000000000000000000000000000000000000000"), // array[2] - + "0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2] }, { "bytes32[3][2]", [][]common.Hash{{{1}, {2}, {3}}, {{3}, {4}, {5}}}, - common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000" + // array[0] - "0200000000000000000000000000000000000000000000000000000000000000" + // array[1] - "0300000000000000000000000000000000000000000000000000000000000000" + // array[2] - "0300000000000000000000000000000000000000000000000000000000000000" + // array[0] - "0400000000000000000000000000000000000000000000000000000000000000" + // array[1] - "0500000000000000000000000000000000000000000000000000000000000000"), // array[2] - + common.Hex2Bytes("0100000000000000000000000000000000000000000000000000000000000000" + // array[0][0] + "0200000000000000000000000000000000000000000000000000000000000000" + // array[0][1] + "0300000000000000000000000000000000000000000000000000000000000000" + // array[0][2] + "0300000000000000000000000000000000000000000000000000000000000000" + // array[1][0] + "0400000000000000000000000000000000000000000000000000000000000000" + // array[1][1] + "0500000000000000000000000000000000000000000000000000000000000000"), // array[1][2] }, } { typ, err := NewType(test.typ) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index ef775ce807dc..1a3fd1fe1e28 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -198,24 +198,20 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { if offsetReq { offset = getOffset(*t.Elem) * v.Len() } - var tail []byte for i := 0; i < v.Len(); i++ { val, err := t.Elem.pack(v.Index(i)) if err != nil { return nil, err } - if !offsetReq { ret = append(ret, val...) continue } - ret = append(ret, packNum(reflect.ValueOf(offset))...) offset += len(val) tail = append(tail, val...) } - return append(ret, tail...), nil default: return packElement(t, v), nil @@ -232,11 +228,7 @@ func (t Type) requiresLengthPrefix() bool { func offsetRequired(t Type) bool { // dynamic types // array is also a dynamic type if the array type is dynamic - if t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && offsetRequired(*t.Elem)) { - return true - } - - return false + return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && offsetRequired(*t.Elem)) } // getOffset returns the offset to be added for t @@ -246,6 +238,5 @@ func getOffset(t Type) int { if t.T == ArrayTy && !offsetRequired(*t.Elem) { return 32 * t.Size } - return 32 } From da590e60ee3467f72a3b3c2983de9ea01134115d Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Mon, 26 Nov 2018 13:35:53 +0100 Subject: [PATCH 8/9] review chnages --- accounts/abi/argument.go | 2 +- accounts/abi/type.go | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index b5e6cd185883..c69516f128ae 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -243,7 +243,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { // input offset is the bytes offset for packed output inputOffset := 0 for _, abiArg := range abiArgs { - inputOffset += getOffset(abiArg.Type) + inputOffset += getDynamicTypeOffset(abiArg.Type) } var ret []byte for i, a := range args { diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 1a3fd1fe1e28..f4c528c3badd 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -196,7 +196,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { offset := 0 offsetReq := offsetRequired(*t.Elem) if offsetReq { - offset = getOffset(*t.Elem) * v.Len() + offset = getDynamicTypeOffset(*t.Elem) * v.Len() } var tail []byte for i := 0; i < v.Len(); i++ { @@ -231,8 +231,12 @@ func offsetRequired(t Type) bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && offsetRequired(*t.Elem)) } -// getOffset returns the offset to be added for t -func getOffset(t Type) int { +// getDynamicTypeOffset returns the offset for the type. +// See offsetRequired 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 +// return 32 * size of array since length prefix is not required. +// If t is a dynamic type or element type(for slices and arrays) is dynamic, then we simply return 32 as offset. +func getDynamicTypeOffset(t Type) int { // if it is an array and there are no dynamic types // then the array is static type if t.T == ArrayTy && !offsetRequired(*t.Elem) { From 0f9afde6d78965f3fa3c6e9feeaddde8b3576ac2 Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Mon, 26 Nov 2018 13:43:35 +0100 Subject: [PATCH 9/9] better comments --- accounts/abi/argument.go | 2 +- accounts/abi/type.go | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index c69516f128ae..f544c80dbb1c 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -254,7 +254,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { return nil, err } // check for dynamic types - if offsetRequired(input.Type) { + if isDynamicType(input.Type) { // set the offset ret = append(ret, packNum(reflect.ValueOf(inputOffset))...) // calculate next offset diff --git a/accounts/abi/type.go b/accounts/abi/type.go index f4c528c3badd..6bfaabf5a5b1 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -194,7 +194,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) { // calculate offset if any offset := 0 - offsetReq := offsetRequired(*t.Elem) + offsetReq := isDynamicType(*t.Elem) if offsetReq { offset = getDynamicTypeOffset(*t.Elem) * v.Len() } @@ -224,22 +224,25 @@ func (t Type) requiresLengthPrefix() bool { return t.T == StringTy || t.T == BytesTy || t.T == SliceTy } -// offsetRequired returns true if the type is considered dynamic -func offsetRequired(t Type) bool { +// isDynamicType returns true if the type is dynamic. +// StringTy, BytesTy, and SliceTy(irrespective of slice element type) are dynamic types +// ArrayTy is considered dynamic if and only if the Array element is a dynamic type. +// This function recursively checks the type for slice and array elements. +func isDynamicType(t Type) bool { // dynamic types // array is also a dynamic type if the array type is dynamic - return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && offsetRequired(*t.Elem)) + return t.T == StringTy || t.T == BytesTy || t.T == SliceTy || (t.T == ArrayTy && isDynamicType(*t.Elem)) } // getDynamicTypeOffset returns the offset for the type. -// See offsetRequired 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 +// 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 // return 32 * size of array since length prefix is not required. // If t is a dynamic type or element type(for slices and arrays) is dynamic, then we simply return 32 as offset. func getDynamicTypeOffset(t Type) int { // if it is an array and there are no dynamic types // then the array is static type - if t.T == ArrayTy && !offsetRequired(*t.Elem) { + if t.T == ArrayTy && !isDynamicType(*t.Elem) { return 32 * t.Size } return 32