Decoder tests.

This commit is contained in:
chriseth 2017-09-13 17:16:45 +02:00
parent bdc1ff8ec7
commit 98c38108e8
5 changed files with 866 additions and 34 deletions

View File

@ -84,12 +84,22 @@ public:
return callFallbackWithValue(0);
}
bytes const& callContractFunctionWithValueNoEncoding(std::string _sig, u256 const& _value, bytes const& _arguments)
{
FixedHash<4> hash(dev::keccak256(_sig));
sendMessage(hash.asBytes() + _arguments, false, _value);
return m_output;
}
bytes const& callContractFunctionNoEncoding(std::string _sig, bytes const& _arguments)
{
return callContractFunctionWithValueNoEncoding(_sig, 0, _arguments);
}
template <class... Args>
bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments)
{
FixedHash<4> hash(dev::keccak256(_sig));
sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value);
return m_output;
return callContractFunctionWithValueNoEncoding(_sig, _value, encodeArgs(_arguments...));
}
template <class... Args>

View File

@ -57,6 +57,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
if (dev::test::Options::get().disableIPC)
{
for (auto suite: {
"ABIDecoderTest",
"ABIEncoderTest",
"SolidityAuctionRegistrar",
"SolidityFixedFeeRegistrar",

View File

@ -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

View File

@ -25,6 +25,8 @@
#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;
@ -42,20 +44,6 @@ namespace test
BOOST_CHECK_EQUAL(toHex(m_logs[0].data), toHex(DATA)); \
} while (false)
static string const NewEncoderPragma = "pragma experimental ABIEncoderV2;\n";
#define NEW_ENCODER(CODE) \
{ \
sourceCode = NewEncoderPragma + sourceCode; \
{ CODE } \
}
#define BOTH_ENCODERS(CODE) \
{ \
{ CODE } \
NEW_ENCODER(CODE) \
}
BOOST_FIXTURE_TEST_SUITE(ABIEncoderTest, SolidityExecutionFramework)
BOOST_AUTO_TEST_CASE(both_encoders_macro)
@ -74,7 +62,7 @@ BOOST_AUTO_TEST_CASE(value_types)
string sourceCode = R"(
contract C {
event E(uint a, uint16 b, uint24 c, int24 d, bytes3 x, bool, C);
function f() {
function f() public {
bytes6 x = hex"1bababababa2";
bool b;
assembly { b := 7 }
@ -98,7 +86,7 @@ BOOST_AUTO_TEST_CASE(string_literal)
string sourceCode = R"(
contract C {
event E(string, bytes20, string);
function f() {
function f() public {
E("abcdef", "abcde", "abcdefabcdefgehabcabcasdfjklabcdefabcedefghabcabcasdfjklabcdefabcdefghabcabcasdfjklabcdeefabcdefghabcabcasdefjklabcdefabcdefghabcabcasdfjkl");
}
}
@ -120,7 +108,7 @@ BOOST_AUTO_TEST_CASE(enum_type_cleanup)
string sourceCode = R"(
contract C {
enum E { A, B }
function f(uint x) returns (E en) {
function f(uint x) public returns (E en) {
assembly { en := x }
}
}
@ -138,7 +126,7 @@ BOOST_AUTO_TEST_CASE(conversion)
string sourceCode = R"(
contract C {
event E(bytes4, bytes4, uint16, uint8, int16, int8);
function f() {
function f() public {
bytes2 x; assembly { x := 0xf1f2f3f400000000000000000000000000000000000000000000000000000000 }
uint8 a;
uint16 b = 0x1ff;
@ -164,7 +152,7 @@ BOOST_AUTO_TEST_CASE(memory_array_one_dim)
string sourceCode = R"(
contract C {
event E(uint a, int16[] b, uint c);
function f() {
function f() public {
int16[] memory x = new int16[](3);
assembly {
for { let i := 0 } lt(i, 3) { i := add(i, 1) } {
@ -191,7 +179,7 @@ BOOST_AUTO_TEST_CASE(memory_array_two_dim)
string sourceCode = R"(
contract C {
event E(uint a, int16[][2] b, uint c);
function f() {
function f() public {
int16[][2] memory x;
x[0] = new int16[](3);
x[1] = new int16[](2);
@ -216,7 +204,7 @@ BOOST_AUTO_TEST_CASE(memory_byte_array)
string sourceCode = R"(
contract C {
event E(uint a, bytes[] b, uint c);
function f() {
function f() public {
bytes[] memory x = new bytes[](2);
x[0] = "abcabcdefghjklmnopqrsuvwabcdefgijklmnopqrstuwabcdefgijklmnoprstuvw";
x[1] = "abcdefghijklmnopqrtuvwabcfghijklmnopqstuvwabcdeghijklmopqrstuvw";
@ -243,7 +231,7 @@ BOOST_AUTO_TEST_CASE(storage_byte_array)
bytes short;
bytes long;
event E(bytes s, bytes l);
function f() {
function f() public {
short = "123456789012345678901234567890a";
long = "ffff123456789012345678901234567890afffffffff123456789012345678901234567890a";
E(short, long);
@ -267,7 +255,7 @@ BOOST_AUTO_TEST_CASE(storage_array)
contract C {
address[3] addr;
event E(address[3] a);
function f() {
function f() public {
assembly {
sstore(0, sub(0, 1))
sstore(1, sub(0, 2))
@ -290,7 +278,7 @@ BOOST_AUTO_TEST_CASE(storage_array_dyn)
contract C {
address[] addr;
event E(address[] a);
function f() {
function f() public {
addr.push(1);
addr.push(2);
addr.push(3);
@ -311,7 +299,7 @@ BOOST_AUTO_TEST_CASE(storage_array_compact)
contract C {
int72[] x;
event E(int72[]);
function f() {
function f() public {
x.push(-1);
x.push(2);
x.push(-3);
@ -339,7 +327,7 @@ BOOST_AUTO_TEST_CASE(external_function)
contract C {
event E(function(uint) external returns (uint), function(uint) external returns (uint));
function(uint) external returns (uint) g;
function f(uint) returns (uint) {
function f(uint) public returns (uint) {
g = this.f;
E(this.f, g);
}
@ -347,7 +335,7 @@ BOOST_AUTO_TEST_CASE(external_function)
)";
BOTH_ENCODERS(
compileAndRun(sourceCode);
callContractFunction("f(uint256)");
callContractFunction("f(uint256)", u256(0));
string functionIdF = asString(m_contractAddress.ref()) + asString(FixedHash<4>(dev::keccak256("f(uint256)")).ref());
REQUIRE_LOG_DATA(encodeArgs(functionIdF, functionIdF));
)
@ -360,7 +348,7 @@ BOOST_AUTO_TEST_CASE(external_function_cleanup)
event E(function(uint) external returns (uint), function(uint) external returns (uint));
// This test relies on the fact that g is stored in slot zero.
function(uint) external returns (uint) g;
function f(uint) returns (uint) {
function f(uint) public returns (uint) {
function(uint) external returns (uint)[1] memory h;
assembly { sstore(0, sub(0, 1)) mstore(h, sub(0, 1)) }
E(h[0], g);
@ -369,7 +357,7 @@ BOOST_AUTO_TEST_CASE(external_function_cleanup)
)";
BOTH_ENCODERS(
compileAndRun(sourceCode);
callContractFunction("f(uint256)");
callContractFunction("f(uint256)", u256(0));
REQUIRE_LOG_DATA(encodeArgs(string(24, char(-1)), string(24, char(-1))));
)
}
@ -404,7 +392,7 @@ BOOST_AUTO_TEST_CASE(function_name_collision)
// and by the ABI encoder
string sourceCode = R"(
contract C {
function f(uint x) returns (uint) {
function f(uint x) public returns (uint) {
assembly {
function abi_encode_t_uint256_to_t_uint256() {
mstore(0, 7)
@ -432,7 +420,7 @@ BOOST_AUTO_TEST_CASE(structs)
struct T { uint64[2] x; }
S s;
event e(uint16, S);
function f() returns (uint, S) {
function f() public returns (uint, S) {
uint16 x = 7;
s.a = 8;
s.b = 9;

View File

@ -0,0 +1,43 @@
/*
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/>.
*/
#include <string>
namespace dev
{
namespace solidity
{
namespace test
{
static std::string const NewEncoderPragma = "pragma experimental ABIEncoderV2;\n";
#define NEW_ENCODER(CODE) \
{ \
sourceCode = NewEncoderPragma + sourceCode; \
{ CODE } \
}
#define BOTH_ENCODERS(CODE) \
{ \
{ CODE } \
NEW_ENCODER(CODE) \
}
}
}
} // end namespaces