aboutsummaryrefslogtreecommitdiffstats
path: root/test/libsolidity/ABIDecoderTests.cpp
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2017-09-13 23:16:45 +0800
committerchriseth <chris@ethereum.org>2017-11-30 00:08:44 +0800
commit98c38108e8ce01888ee4dbf98a332aa5ba41f722 (patch)
treef358ce8456893ae0b26b9e048c3657641e0a25c7 /test/libsolidity/ABIDecoderTests.cpp
parentbdc1ff8ec71bdf96e0706c951dd92def3aee4aa2 (diff)
downloaddexon-solidity-98c38108e8ce01888ee4dbf98a332aa5ba41f722.tar.gz
dexon-solidity-98c38108e8ce01888ee4dbf98a332aa5ba41f722.tar.zst
dexon-solidity-98c38108e8ce01888ee4dbf98a332aa5ba41f722.zip
Decoder tests.
Diffstat (limited to 'test/libsolidity/ABIDecoderTests.cpp')
-rw-r--r--test/libsolidity/ABIDecoderTests.cpp790
1 files changed, 790 insertions, 0 deletions
diff --git a/test/libsolidity/ABIDecoderTests.cpp b/test/libsolidity/ABIDecoderTests.cpp
new file mode 100644
index 00000000..6a4b5723
--- /dev/null
+++ b/test/libsolidity/ABIDecoderTests.cpp
@@ -0,0 +1,790 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Unit tests for Solidity's ABI decoder.
+ */
+
+#include <functional>
+#include <string>
+#include <tuple>
+#include <boost/test/unit_test.hpp>
+#include <libsolidity/interface/Exceptions.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
+
+#include <test/libsolidity/ABITestsCommon.h>
+
+using namespace std;
+using namespace std::placeholders;
+using namespace dev::test;
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+BOOST_FIXTURE_TEST_SUITE(ABIDecoderTest, SolidityExecutionFramework)
+
+BOOST_AUTO_TEST_CASE(BOTH_ENCODERS_macro)
+{
+ // This tests that the "both decoders macro" at least runs twice and
+ // modifies the source.
+ string sourceCode;
+ int runs = 0;
+ BOTH_ENCODERS(runs++;)
+ BOOST_CHECK(sourceCode == NewEncoderPragma);
+ BOOST_CHECK_EQUAL(runs, 2);
+}
+
+BOOST_AUTO_TEST_CASE(value_types)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint16 b, uint24 c, int24 d, bytes3 x, bool e, C g) public returns (uint) {
+ if (a != 1) return 1;
+ if (b != 2) return 2;
+ if (c != 3) return 3;
+ if (d != 4) return 4;
+ if (x != "abc") return 5;
+ if (e != true) return 6;
+ if (g != this) return 7;
+ return 20;
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction(
+ "f(uint256,uint16,uint24,int24,bytes3,bool,address)",
+ 1, 2, 3, 4, string("abc"), true, u160(m_contractAddress)
+ ), encodeArgs(u256(20)));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(enums)
+{
+ string sourceCode = R"(
+ contract C {
+ enum E { A, B }
+ function f(E e) public pure returns (uint x) {
+ assembly { x := e }
+ }
+ }
+ )";
+ bool newDecoder = false;
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f(uint8)", 0), encodeArgs(u256(0)));
+ ABI_CHECK(callContractFunction("f(uint8)", 1), encodeArgs(u256(1)));
+ // The old decoder was not as strict about enums
+ ABI_CHECK(callContractFunction("f(uint8)", 2), (newDecoder ? encodeArgs() : encodeArgs(2)));
+ ABI_CHECK(callContractFunction("f(uint8)", u256(-1)), (newDecoder? encodeArgs() : encodeArgs(u256(0xff))));
+ newDecoder = true;
+ )
+}
+
+BOOST_AUTO_TEST_CASE(cleanup)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint16 a, int16 b, address c, bytes3 d, bool e)
+ public pure returns (uint v, uint w, uint x, uint y, uint z) {
+ assembly { v := a w := b x := c y := d z := e}
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ ABI_CHECK(
+ callContractFunction("f(uint16,int16,address,bytes3,bool)", 1, 2, 3, "a", true),
+ encodeArgs(u256(1), u256(2), u256(3), string("a"), true)
+ );
+ ABI_CHECK(
+ callContractFunction(
+ "f(uint16,int16,address,bytes3,bool)",
+ u256(0xffffff), u256(0x1ffff), u256(-1), string("abcd"), u256(4)
+ ),
+ encodeArgs(u256(0xffff), u256(-1), (u256(1) << 160) - 1, string("abc"), true)
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(fixed_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint16[3] a, uint16[2][3] b, uint i, uint j, uint k)
+ public pure returns (uint, uint) {
+ return (a[i], b[j][k]);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 1, 2, 3,
+ 11, 12,
+ 21, 22,
+ 31, 32,
+ 1, 2, 1
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint16[3],uint16[2][3],uint256,uint256,uint256)", args),
+ encodeArgs(u256(2), u256(32))
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(dynamic_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint16[] b, uint c)
+ public pure returns (uint, uint, uint) {
+ return (b.length, b[a], c);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 6, 0x60, 9,
+ 7,
+ 11, 12, 13, 14, 15, 16, 17
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint256,uint16[],uint256)", args),
+ encodeArgs(u256(7), u256(17), u256(9))
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(dynamic_nested_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint16[][] b, uint[2][][3] c, uint d)
+ public pure returns (uint, uint, uint, uint, uint, uint, uint) {
+ return (a, b.length, b[1].length, b[1][1], c[1].length, c[1][1][1], d);
+ }
+ function test() view returns (uint, uint, uint, uint, uint, uint, uint) {
+ uint16[][] memory b = new uint16[][](3);
+ b[0] = new uint16[](2);
+ b[0][0] = 0x55;
+ b[0][1] = 0x56;
+ b[1] = new uint16[](4);
+ b[1][0] = 0x65;
+ b[1][1] = 0x66;
+ b[1][2] = 0x67;
+ b[1][3] = 0x68;
+
+ uint[2][][3] memory c;
+ c[0] = new uint[2][](1);
+ c[0][0][1] = 0x75;
+ c[1] = new uint[2][](5);
+ c[1][1][1] = 0x85;
+
+ return this.f(0x12, b, c, 0x13);
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 0x12, 4 * 0x20, 17 * 0x20, 0x13,
+ // b
+ 3, 3 * 0x20, 6 * 0x20, 11 * 0x20,
+ 2, 85, 86,
+ 4, 101, 102, 103, 104,
+ 0,
+ // c
+ 3 * 0x20, 6 * 0x20, 17 * 0x20,
+ 1, 0, 117,
+ 5, 0, 0, 0, 133, 0, 0, 0, 0, 0, 0,
+ 0
+ );
+
+ bytes expectation = encodeArgs(0x12, 3, 4, 0x66, 5, 0x85, 0x13);
+ ABI_CHECK(callContractFunction("test()"), expectation);
+ ABI_CHECK(callContractFunction("f(uint256,uint16[][],uint256[2][][3],uint256)", args), expectation);
+ )
+}
+
+BOOST_AUTO_TEST_CASE(byte_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, bytes b, uint c)
+ public pure returns (uint, uint, byte, uint) {
+ return (a, b.length, b[3], c);
+ }
+
+ function f_external(uint a, bytes b, uint c)
+ external pure returns (uint, uint, byte, uint) {
+ return (a, b.length, b[3], c);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 6, 0x60, 9,
+ 7, "abcdefg"
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint256,bytes,uint256)", args),
+ encodeArgs(u256(6), u256(7), "d", 9)
+ );
+ ABI_CHECK(
+ callContractFunction("f_external(uint256,bytes,uint256)", args),
+ encodeArgs(u256(6), u256(7), "d", 9)
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(calldata_arrays_too_large)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint[] b, uint c) external pure returns (uint) {
+ return 7;
+ }
+ }
+ )";
+ bool newEncoder = false;
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode);
+ bytes args = encodeArgs(
+ 6, 0x60, 9,
+ (u256(1) << 255) + 2, 1, 2
+ );
+ ABI_CHECK(
+ callContractFunction("f(uint256,uint256[],uint256)", args),
+ newEncoder ? encodeArgs() : encodeArgs(7)
+ );
+ newEncoder = true;
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_from_memory_simple)
+{
+ string sourceCode = R"(
+ contract C {
+ uint public _a;
+ uint[] public _b;
+ function C(uint a, uint[] b) {
+ _a = a;
+ _b = b;
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "C", encodeArgs(
+ 7, 0x40,
+ // b
+ 3, 0x21, 0x22, 0x23
+ ));
+ ABI_CHECK(callContractFunction("_a()"), encodeArgs(7));
+ ABI_CHECK(callContractFunction("_b(uint256)", 0), encodeArgs(0x21));
+ ABI_CHECK(callContractFunction("_b(uint256)", 1), encodeArgs(0x22));
+ ABI_CHECK(callContractFunction("_b(uint256)", 2), encodeArgs(0x23));
+ ABI_CHECK(callContractFunction("_b(uint256)", 3), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_function_type)
+{
+ string sourceCode = R"(
+ contract D {
+ function () external returns (uint) public _a;
+ function D(function () external returns (uint) a) {
+ _a = a;
+ }
+ }
+ contract C {
+ function f() returns (uint) {
+ return 3;
+ }
+ function g(function () external returns (uint) _f) returns (uint) {
+ return _f();
+ }
+ // uses "decode from memory"
+ function test1() returns (uint) {
+ D d = new D(this.f);
+ return d._a()();
+ }
+ // uses "decode from calldata"
+ function test2() returns (uint) {
+ return this.g(this.f);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("test1()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("test2()"), encodeArgs(3));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_function_type_array)
+{
+ string sourceCode = R"(
+ contract D {
+ function () external returns (uint)[] public _a;
+ function D(function () external returns (uint)[] a) {
+ _a = a;
+ }
+ }
+ contract E {
+ function () external returns (uint)[3] public _a;
+ function E(function () external returns (uint)[3] a) {
+ _a = a;
+ }
+ }
+ contract C {
+ function f1() public returns (uint) {
+ return 1;
+ }
+ function f2() public returns (uint) {
+ return 2;
+ }
+ function f3() public returns (uint) {
+ return 3;
+ }
+ function g(function () external returns (uint)[] _f, uint i) public returns (uint) {
+ return _f[i]();
+ }
+ function h(function () external returns (uint)[3] _f, uint i) public returns (uint) {
+ return _f[i]();
+ }
+ // uses "decode from memory"
+ function test1_dynamic() public returns (uint) {
+ var x = new function() external returns (uint)[](3);
+ x[0] = this.f1;
+ x[1] = this.f2;
+ x[2] = this.f3;
+ D d = new D(x);
+ return d._a(2)();
+ }
+ function test1_static() public returns (uint) {
+ E e = new E([this.f1, this.f2, this.f3]);
+ return e._a(2)();
+ }
+ // uses "decode from calldata"
+ function test2_dynamic() public returns (uint) {
+ var x = new function() external returns (uint)[](3);
+ x[0] = this.f1;
+ x[1] = this.f2;
+ x[2] = this.f3;
+ return this.g(x, 0);
+ }
+ function test2_static() public returns (uint) {
+ return this.h([this.f1, this.f2, this.f3], 0);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("test1_static()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("test1_dynamic()"), encodeArgs(3));
+ ABI_CHECK(callContractFunction("test2_static()"), encodeArgs(1));
+ ABI_CHECK(callContractFunction("test2_dynamic()"), encodeArgs(1));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(decode_from_memory_complex)
+{
+ string sourceCode = R"(
+ contract C {
+ uint public _a;
+ uint[] public _b;
+ bytes[2] public _c;
+ function C(uint a, uint[] b, bytes[2] c) {
+ _a = a;
+ _b = b;
+ _c = c;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C", encodeArgs(
+ 7, 0x60, 7 * 0x20,
+ // b
+ 3, 0x21, 0x22, 0x23,
+ // c
+ 0x40, 0x80,
+ 8, string("abcdefgh"),
+ 52, string("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ")
+ ));
+ ABI_CHECK(callContractFunction("_a()"), encodeArgs(7));
+ ABI_CHECK(callContractFunction("_b(uint256)", 0), encodeArgs(0x21));
+ ABI_CHECK(callContractFunction("_b(uint256)", 1), encodeArgs(0x22));
+ ABI_CHECK(callContractFunction("_b(uint256)", 2), encodeArgs(0x23));
+ ABI_CHECK(callContractFunction("_b(uint256)", 3), encodeArgs());
+ ABI_CHECK(callContractFunction("_c(uint256)", 0), encodeArgs(0x20, 8, string("abcdefgh")));
+ ABI_CHECK(callContractFunction("_c(uint256)", 1), encodeArgs(0x20, 52, string("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ")));
+ ABI_CHECK(callContractFunction("_c(uint256)", 2), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_input_value_type)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint a, uint b) public pure returns (uint) { return a; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f(uint256,uint256)", 1, 2), encodeArgs(1));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256,uint256)", bytes(64, 0)), encodeArgs(0));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256,uint256)", bytes(63, 0)), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_input_array)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(uint[] a) public pure returns (uint) { return 7; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1) + bytes(31, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 1) + bytes(32, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(uint256[])", encodeArgs(0x20, 2, 5, 6)), encodeArgs(7));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_dynamic_input_array)
+{
+ string sourceCode = R"(
+ contract C {
+ function f(bytes[1] a) public pure returns (uint) { return 7; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[1])", encodeArgs(0x20)), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(short_input_bytes)
+{
+ string sourceCode = R"(
+ contract C {
+ function e(bytes a) public pure returns (uint) { return 7; }
+ function f(bytes[] a) public pure returns (uint) { return 7; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(5, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(6, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(7, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("e(bytes)", encodeArgs(0x20, 7) + bytes(8, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(5, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(6, 0)), encodeArgs());
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(7, 0)), encodeArgs(7));
+ ABI_CHECK(callContractFunctionNoEncoding("f(bytes[])", encodeArgs(0x20, 1, 0x20, 7) + bytes(8, 0)), encodeArgs(7));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(cleanup_int_inside_arrays)
+{
+ string sourceCode = R"(
+ contract C {
+ enum E { A, B }
+ function f(uint16[] a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
+ function g(int16[] a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
+ function h(E[] a) public pure returns (uint r) { assembly { r := mload(add(a, 0x20)) } }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, 7), encodeArgs(7));
+ ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, 7), encodeArgs(7));
+ ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0xffff")), encodeArgs(u256("0xffff")));
+ ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0xffff")), encodeArgs(u256(-1)));
+ ABI_CHECK(callContractFunction("f(uint16[])", 0x20, 1, u256("0x1ffff")), encodeArgs(u256("0xffff")));
+ ABI_CHECK(callContractFunction("g(int16[])", 0x20, 1, u256("0x10fff")), encodeArgs(u256("0x0fff")));
+ ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 0), encodeArgs(u256(0)));
+ ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 1), encodeArgs(u256(1)));
+ ABI_CHECK(callContractFunction("h(uint8[])", 0x20, 1, 2), encodeArgs());
+ )
+}
+
+BOOST_AUTO_TEST_CASE(storage_ptr)
+{
+ string sourceCode = R"(
+ library L {
+ struct S { uint x; uint y; }
+ function f(uint[] storage r, S storage s) public returns (uint, uint, uint, uint) {
+ r[2] = 8;
+ s.x = 7;
+ return (r[0], r[1], s.x, s.y);
+ }
+ }
+ contract C {
+ uint8 x = 3;
+ L.S s;
+ uint[] r;
+ function f() public returns (uint, uint, uint, uint, uint, uint) {
+ r.length = 6;
+ r[0] = 1;
+ r[1] = 2;
+ r[2] = 3;
+ s.x = 11;
+ s.y = 12;
+ var (a, b, c, d) = L.f(r, s);
+ return (r[2], s.x, a, b, c, d);
+ }
+ }
+ )";
+ BOTH_ENCODERS(
+ compileAndRun(sourceCode, 0, "L");
+ compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}});
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(8, 7, 1, 2, 7, 12));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_simple)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { uint a; uint8 b; uint8 c; bytes2 d; }
+ function f(S s) public pure returns (uint a, uint b, uint c, uint d) {
+ a = s.a;
+ b = s.b;
+ c = s.c;
+ d = uint(s.d);
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("f((uint256,uint8,uint8,bytes2))", 1, 2, 3, "ab"), encodeArgs(1, 2, 3, 'a' * 0x100 + 'b'));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_cleanup)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { int16 a; uint8 b; bytes2 c; }
+ function f(S s) public pure returns (uint a, uint b, uint c) {
+ assembly {
+ a := mload(s)
+ b := mload(add(s, 0x20))
+ c := mload(add(s, 0x40))
+ }
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(
+ callContractFunction("f((int16,uint8,bytes2))", 0xff010, 0xff0002, "abcd"),
+ encodeArgs(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010"), 2, "ab")
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_short)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { int a; uint b; bytes16 c; }
+ function f(S s) public pure returns (S q) {
+ q = s;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(
+ callContractFunction("f((int256,uint256,bytes16))", 0xff010, 0xff0002, "abcd"),
+ encodeArgs(0xff010, 0xff0002, "abcd")
+ );
+ ABI_CHECK(
+ callContractFunctionNoEncoding("f((int256,uint256,bytes16))", encodeArgs(0xff010, 0xff0002) + bytes(32, 0)),
+ encodeArgs(0xff010, 0xff0002, 0)
+ );
+ ABI_CHECK(
+ callContractFunctionNoEncoding("f((int256,uint256,bytes16))", encodeArgs(0xff010, 0xff0002) + bytes(31, 0)),
+ encodeArgs()
+ );
+ )
+}
+
+BOOST_AUTO_TEST_CASE(struct_function)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { function () external returns (uint) f; uint b; }
+ function f(S s) public returns (uint, uint) {
+ return (s.f(), s.b);
+ }
+ function test() public returns (uint, uint) {
+ return this.f(S(this.g, 3));
+ }
+ function g() public returns (uint) { return 7; }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("test()"), encodeArgs(7, 3));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(empty_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { }
+ function f(uint a, S s, uint b) public pure returns (uint x, uint y) {
+ assembly { x := a y := b }
+ }
+ function g() public returns (uint, uint) {
+ return this.f(7, S(), 8);
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("f(uint256,(),uint256)", 7, 8), encodeArgs(7, 8));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(7, 8));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(mediocre_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { C c; }
+ function f(uint a, S[2] s1, uint b) public returns (uint r1, C r2, uint r3) {
+ r1 = a;
+ r2 = s1[0].c;
+ r3 = b;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ string sig = "f(uint256,(address)[2],uint256)";
+ ABI_CHECK(callContractFunction(sig,
+ 7, u256(u160(m_contractAddress)), 0, 8
+ ), encodeArgs(7, u256(u160(m_contractAddress)), 8));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(mediocre2_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { C c; uint[] x; }
+ function f(uint a, S[2] s1, uint b) public returns (uint r1, C r2, uint r3) {
+ r1 = a;
+ r2 = s1[0].c;
+ r3 = b;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ string sig = "f(uint256,(address,uint256[])[2],uint256)";
+ ABI_CHECK(callContractFunction(sig,
+ 7, 0x60, 8,
+ 0x40, 7 * 0x20,
+ u256(u160(m_contractAddress)), 0x40,
+ 2, 0x11, 0x12,
+ 0x99, 0x40,
+ 4, 0x31, 0x32, 0x34, 0x35
+ ), encodeArgs(7, u256(u160(m_contractAddress)), 8));
+ )
+}
+
+BOOST_AUTO_TEST_CASE(complex_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ enum E {A, B, C}
+ struct T { uint x; E e; uint8 y; }
+ struct S { C c; T[] t;}
+ function f(uint a, S[2] s1, S[] s2, uint b) public returns
+ (uint r1, C r2, uint r3, uint r4, C r5, uint r6, E r7, uint8 r8) {
+ r1 = a;
+ r2 = s1[0].c;
+ r3 = b;
+ r4 = s2.length;
+ r5 = s2[1].c;
+ r6 = s2[1].t.length;
+ r7 = s2[1].t[1].e;
+ r8 = s2[1].t[1].y;
+ }
+ }
+ )";
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ string sig = "f(uint256,(address,(uint256,uint8,uint8)[])[2],(address,(uint256,uint8,uint8)[])[],uint256)";
+ bytes args = encodeArgs(
+ 7, 0x80, 0x1e0, 8,
+ // S[2] s1
+ 0x40,
+ 0x100,
+ // S s1[0]
+ u256(u160(m_contractAddress)),
+ 0x40,
+ // T s1[0].t
+ 1, // length
+ // s1[0].t[0]
+ 0x11, 1, 0x12,
+ // S s1[1]
+ 0, 0x40,
+ // T s1[1].t
+ 0,
+ // S[] s2 (0x1e0)
+ 2, // length
+ 0x40, 0xa0,
+ // S s2[0]
+ 0, 0x40, 0,
+ // S s2[1]
+ 0x1234, 0x40,
+ // s2[1].t
+ 3, // length
+ 0, 0, 0,
+ 0x21, 2, 0x22,
+ 0, 0, 0
+ );
+ ABI_CHECK(callContractFunction(sig, args), encodeArgs(7, u256(u160(m_contractAddress)), 8, 2, 0x1234, 3, 2, 0x22));
+ // invalid enum value
+ args.data()[0x20 * 28] = 3;
+ ABI_CHECK(callContractFunction(sig, args), encodeArgs());
+ )
+}
+
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+} // end namespaces