From ea24bca6612a0fd98763704479a2ae5d844e786c Mon Sep 17 00:00:00 2001 From: Enrique Lacal Date: Tue, 30 May 2023 13:50:48 +0100 Subject: [PATCH 1/3] fix: check dynamic type for tuple before decoding Signed-off-by: Enrique Lacal --- pkg/abi/abidecode.go | 14 +++++++++++--- pkg/abi/abidecode_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/pkg/abi/abidecode.go b/pkg/abi/abidecode.go index afa076d6..344cdce4 100644 --- a/pkg/abi/abidecode.go +++ b/pkg/abi/abidecode.go @@ -88,12 +88,18 @@ func decodeABIElement(ctx context.Context, breadcrumbs string, block []byte, hea } return 32, cv, err case TupleComponent: - headOffset, err := decodeABILength(ctx, breadcrumbs, block, headPosition) + dynamic, err := isDynamicType(ctx, component) if err != nil { return -1, nil, err } - headStart += headOffset - headPosition = headStart + if dynamic { + headOffset, err := decodeABILength(ctx, breadcrumbs, block, headPosition) + if err != nil { + return -1, nil, err + } + headStart += headOffset + headPosition = headStart + } _, cv, err := walkDynamicChildArrayABIBytes(ctx, "tup", breadcrumbs, block, headStart, headPosition, component, component.tupleChildren) return 32, cv, err default: @@ -150,6 +156,8 @@ func decodeABILength(ctx context.Context, desc string, block []byte, offset int) if offset+32 > len(block) { return -1, i18n.NewError(ctx, signermsgs.MsgNotEnoughBytesABIArrayCount, desc) } + newBlock := block[offset : offset+32] + fmt.Println(newBlock) i := new(big.Int).SetBytes(block[offset : offset+32]) if i.BitLen() > 32 { return -1, i18n.NewError(ctx, signermsgs.MsgABIArrayCountTooLarge, i.Text(10), desc) diff --git a/pkg/abi/abidecode_test.go b/pkg/abi/abidecode_test.go index befd8c27..f1897914 100644 --- a/pkg/abi/abidecode_test.go +++ b/pkg/abi/abidecode_test.go @@ -346,6 +346,35 @@ func TestExampleABIDecodeTuple(t *testing.T) { assert.Equal(t, big.NewInt(2414), cv.Children[0].Children[0].Children[3].Value) } +// TestExampleABIDecodeNonDynamicTuple is responsible for testing a duple that does +// not have any dynamic fields +func TestExampleABIDecodeNonDynamicTuple(t *testing.T) { + + f := &Entry{ + Name: "coupon", + Outputs: ParameterArray{ + { + Type: "tuple", + Name: "mystruct", + Components: ParameterArray{ + {Type: "address", Name: "account"}, + {Type: "uint256", Name: "value"}, + }, + }, + }, + } + + d, _ := hex.DecodeString("" + + "000000000000000000000000d2d8a61d774f552301d71aa99a78aff2e4765ca7" + + "000000000000000000000000000000000000000000000000000000000000007b") + + cv, err := f.Outputs.DecodeABIData(d, 0) + assert.NoError(t, err) + assert.Equal(t, big.NewInt(123), cv.Children[0].Children[1].Value) + address, _ := cv.Children[0].Children[0].JSON() + assert.Equal(t, "\"d2d8a61d774f552301d71aa99a78aff2e4765ca7\"", string(address)) +} + func TestExampleABIDecodeDoubleNestedTuple(t *testing.T) { f := &Entry{ From 24e96d74c9a576f0eba3ec516c5e73458511f7f3 Mon Sep 17 00:00:00 2001 From: Enrique Lacal Date: Tue, 30 May 2023 15:13:37 +0100 Subject: [PATCH 2/3] fix: nested static tuple encoding and decoding Signed-off-by: Enrique Lacal --- pkg/abi/abidecode.go | 9 ++- pkg/abi/abidecode_test.go | 121 +++++++++++++++++++++++++++++++++++++- pkg/abi/abiencode.go | 2 +- 3 files changed, 128 insertions(+), 4 deletions(-) diff --git a/pkg/abi/abidecode.go b/pkg/abi/abidecode.go index 344cdce4..d2362528 100644 --- a/pkg/abi/abidecode.go +++ b/pkg/abi/abidecode.go @@ -100,8 +100,13 @@ func decodeABIElement(ctx context.Context, breadcrumbs string, block []byte, hea headStart += headOffset headPosition = headStart } - _, cv, err := walkDynamicChildArrayABIBytes(ctx, "tup", breadcrumbs, block, headStart, headPosition, component, component.tupleChildren) - return 32, cv, err + + headBytesRead, cv, err := walkDynamicChildArrayABIBytes(ctx, "tup", breadcrumbs, block, headStart, headPosition, component, component.tupleChildren) + if dynamic { + // In the case where it's dynamic we only read one block + headBytesRead = 32 + } + return headBytesRead, cv, err default: return -1, nil, i18n.NewError(ctx, signermsgs.MsgBadABITypeComponent, component.cType) } diff --git a/pkg/abi/abidecode_test.go b/pkg/abi/abidecode_test.go index f1897914..1f419415 100644 --- a/pkg/abi/abidecode_test.go +++ b/pkg/abi/abidecode_test.go @@ -439,6 +439,112 @@ func TestExampleABIDecodeDoubleNestedTuple(t *testing.T) { assert.Equal(t, big.NewInt(66666), cv.Children[0].Children[0].Children[3].Value) } +func TestExampleABIDecodeStaticNestedTupleInDynamicTuple(t *testing.T) { + + f := &Entry{ + Name: "f", + Outputs: ParameterArray{ + { + Type: "tuple[]", + Name: "nested", + Components: ParameterArray{ + {Type: "uint256", Name: "a"}, + {Type: "string", Name: "b"}, + {Type: "tuple", Name: "c", Components: ParameterArray{ + {Type: "uint256", Name: "c1"}, + {Type: "uint256", Name: "c2"}, + }}, + {Type: "uint256", Name: "d"}, + }, + }, + }, + } + + b, err := f.Outputs.EncodeABIDataJSON([]byte(`{ + "nested": [{ + "a": 11111, + "b": "test22222", + "c": { + "c1": 33333, + "c2": 44444 + }, + "d": 55555 + }] + }`)) + assert.NoError(t, err) + + assert.Equal(t, + "0000000000000000000000000000000000000000000000000000000000000020"+ // 0 - 32 - offset for the start of the dynamic array + "0000000000000000000000000000000000000000000000000000000000000001"+ // 32 - 1 - number of tuples in the dynamic array + "0000000000000000000000000000000000000000000000000000000000000020"+ // 64 - 32 - offset of the data for the tuple at position 0 in the array + "0000000000000000000000000000000000000000000000000000000000002b67"+ // 96 - 11111 - value "a" + "00000000000000000000000000000000000000000000000000000000000000a0"+ // 128 - 160 - offset of the string data for "b", relative to 96 = 224 + "0000000000000000000000000000000000000000000000000000000000008235"+ // 160 - 33333 - value of "c1" + "000000000000000000000000000000000000000000000000000000000000ad9c"+ // 192 - 44444 - value of "c2" + "000000000000000000000000000000000000000000000000000000000000d903"+ // 224 - 55555 - value of "d" + "0000000000000000000000000000000000000000000000000000000000000009"+ // 256 - 9 - length of the string data for "b" + "7465737432323232320000000000000000000000000000000000000000000000", // 288 - "test22222" + hex.EncodeToString(b)) + + cv, err := f.Outputs.DecodeABIData(b, 0) + + assert.Equal(t, big.NewInt(11111), cv.Children[0].Children[0].Children[0].Value) + assert.Equal(t, "test22222", cv.Children[0].Children[0].Children[1].Value) + assert.Equal(t, big.NewInt(33333), cv.Children[0].Children[0].Children[2].Children[0].Value) + assert.Equal(t, big.NewInt(44444), cv.Children[0].Children[0].Children[2].Children[1].Value) + assert.Equal(t, big.NewInt(55555), cv.Children[0].Children[0].Children[3].Value) +} + +func TestExampleABIDecodeDoubleStaticNestedTuple(t *testing.T) { + + f := &Entry{ + Name: "f", + Outputs: ParameterArray{ + { + Type: "tuple[]", + Name: "nested", + Components: ParameterArray{ + {Type: "uint256", Name: "a"}, + {Type: "tuple", Name: "c", Components: ParameterArray{ + {Type: "uint256", Name: "c1"}, + {Type: "uint256", Name: "c2"}, + }}, + {Type: "uint256", Name: "d"}, + }, + }, + }, + } + + b, err := f.Outputs.EncodeABIDataJSON([]byte(`{ + "nested": [{ + "a": 11111, + "c": { + "c1": 22222, + "c2": 33333 + }, + "d": 44444 + }] + }`)) + assert.NoError(t, err) + + // The encoding looks right to me + assert.Equal(t, + "0000000000000000000000000000000000000000000000000000000000000020"+ // 0 - 32 - offset for the start of the dynamic array + "0000000000000000000000000000000000000000000000000000000000000001"+ // 32 - 1 - number of tuples in the dynamic array + "0000000000000000000000000000000000000000000000000000000000002b67"+ // 64 - 11111 - value of "a" + "00000000000000000000000000000000000000000000000000000000000056ce"+ // 96 - 22222 - value of "c1" + "0000000000000000000000000000000000000000000000000000000000008235"+ // 128 - 33333 - value of "c2" + "000000000000000000000000000000000000000000000000000000000000ad9c", // 160 - 44444 - value of "d" + hex.EncodeToString(b)) + + cv, err := f.Outputs.DecodeABIData(b, 0) + + assert.Equal(t, big.NewInt(11111), cv.Children[0].Children[0].Children[0].Value) + assert.Equal(t, big.NewInt(22222), cv.Children[0].Children[0].Children[1].Children[0].Value) + assert.Equal(t, big.NewInt(33333), cv.Children[0].Children[0].Children[1].Children[1].Value) + assert.Equal(t, big.NewInt(44444), cv.Children[0].Children[0].Children[2].Value) +} + func TestExampleABIDecodeTupleFixed(t *testing.T) { f := &Entry{ @@ -863,7 +969,6 @@ func TestIsDynamicTypeBadNestedTupleType(t *testing.T) { }) assert.Regexp(t, "FF22041", err) } - func TestDecodeABIElementBadDynamicTypeFixedArray(t *testing.T) { block, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000020") @@ -877,6 +982,20 @@ func TestDecodeABIElementBadDynamicTypeFixedArray(t *testing.T) { assert.Regexp(t, "FF22041", err) } +func TestDecodeABIElementBadDynamicTypeTuple(t *testing.T) { + + block, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000020") + assert.NoError(t, err) + + _, _, err = decodeABIElement(context.Background(), "", block, 0, 0, &typeComponent{ + cType: TupleComponent, + tupleChildren: []*typeComponent{ + {cType: 99}, + }, + }) + assert.Regexp(t, "FF22041", err) +} + func TestDecodeABIElementInsufficientDataFixedArrayDynamicType(t *testing.T) { p := &ParameterArray{ diff --git a/pkg/abi/abiencode.go b/pkg/abi/abiencode.go index 720e5b0e..f16f7dad 100644 --- a/pkg/abi/abiencode.go +++ b/pkg/abi/abiencode.go @@ -48,7 +48,7 @@ func (cv *ComponentValue) encodeABIData(ctx context.Context, desc string) ([]byt case DynamicArrayComponent: return cv.encodeABIChildren(ctx, desc, true /* always dynamic */, true /* need length */) case TupleComponent: - return cv.encodeABIChildren(ctx, desc, true /* always dynamic */, false /* no length */) + return cv.encodeABIChildren(ctx, desc, false /* only dynamic if the children are dynamic */, false /* no length */) default: return nil, false, i18n.NewError(ctx, signermsgs.MsgBadABITypeComponent, tc.cType) } From 9af5ad6b7afa126733d4ef093261fd990f89ab83 Mon Sep 17 00:00:00 2001 From: Enrique Lacal Date: Tue, 30 May 2023 18:26:41 +0100 Subject: [PATCH 3/3] fix: Remove fmt print Signed-off-by: Enrique Lacal --- pkg/abi/abidecode.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/abi/abidecode.go b/pkg/abi/abidecode.go index d2362528..12db5fbe 100644 --- a/pkg/abi/abidecode.go +++ b/pkg/abi/abidecode.go @@ -161,8 +161,6 @@ func decodeABILength(ctx context.Context, desc string, block []byte, offset int) if offset+32 > len(block) { return -1, i18n.NewError(ctx, signermsgs.MsgNotEnoughBytesABIArrayCount, desc) } - newBlock := block[offset : offset+32] - fmt.Println(newBlock) i := new(big.Int).SetBytes(block[offset : offset+32]) if i.BitLen() > 32 { return -1, i18n.NewError(ctx, signermsgs.MsgABIArrayCountTooLarge, i.Text(10), desc)