diff options
Diffstat (limited to 'test/libsolidity/SolidityEndToEndTest.cpp')
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 562 |
1 files changed, 562 insertions, 0 deletions
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d8924250..ed95d687 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -7606,6 +7606,568 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call) BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7))); } +BOOST_AUTO_TEST_CASE(calling_uninitialized_function) +{ + char const* sourceCode = R"( + contract C { + function intern() returns (uint) { + function (uint) internal returns (uint) x; + x(2); + return 7; + } + function extern() returns (uint) { + function (uint) external returns (uint) x; + x(2); + return 7; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + // This should throw exceptions + BOOST_CHECK(callContractFunction("intern()") == encodeArgs()); + BOOST_CHECK(callContractFunction("extern()") == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(calling_uninitialized_function_in_detail) +{ + char const* sourceCode = R"( + contract C { + function() internal returns (uint) x; + int mutex; + function t() returns (uint) { + if (mutex > 0) + return 7; + mutex = 1; + // Avoid re-executing this function if we jump somewhere. + x(); + return 2; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(pass_function_types_internally) +{ + char const* sourceCode = R"( + contract C { + function f(uint x) returns (uint) { + return eval(g, x); + } + function eval(function(uint) returns (uint) x, uint a) internal returns (uint) { + return x(a); + } + function g(uint x) returns (uint) { return x + 1; } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8))); +} + +BOOST_AUTO_TEST_CASE(pass_function_types_externally) +{ + char const* sourceCode = R"( + contract C { + function f(uint x) returns (uint) { + return this.eval(this.g, x); + } + function f2(uint x) returns (uint) { + return eval(this.g, x); + } + function eval(function(uint) external returns (uint) x, uint a) returns (uint) { + return x(a); + } + function g(uint x) returns (uint) { return x + 1; } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8))); + BOOST_CHECK(callContractFunction("f2(uint256)", 7) == encodeArgs(u256(8))); +} + +BOOST_AUTO_TEST_CASE(receive_external_function_type) +{ + char const* sourceCode = R"( + contract C { + function g() returns (uint) { return 7; } + function f(function() external returns (uint) g) returns (uint) { + return g(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction( + "f(function)", + m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0) + ) == encodeArgs(u256(7))); +} + +BOOST_AUTO_TEST_CASE(return_external_function_type) +{ + char const* sourceCode = R"( + contract C { + function g() {} + function f() returns (function() external) { + return this.g; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK( + callContractFunction("f()") == + m_contractAddress.asBytes() + FixedHash<4>(dev::keccak256("g()")).asBytes() + bytes(32 - 4 - 20, 0) + ); +} + +BOOST_AUTO_TEST_CASE(store_function) +{ + char const* sourceCode = R"( + contract Other { + function addTwo(uint x) returns (uint) { return x + 2; } + } + contract C { + function (function (uint) external returns (uint)) returns (uint) ev; + function (uint) external returns (uint) x; + function store(function(uint) external returns (uint) y) { + x = y; + } + function eval(function(uint) external returns (uint) y) returns (uint) { + return y(7); + } + function t() returns (uint) { + ev = eval; + this.store((new Other()).addTwo); + return ev(x); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(9))); +} + +BOOST_AUTO_TEST_CASE(store_function_in_constructor) +{ + char const* sourceCode = R"( + contract C { + uint public result_in_constructor; + function (uint) internal returns (uint) x; + function C () { + x = double; + result_in_constructor = use(2); + } + function double(uint _arg) returns (uint _ret) { + _ret = _arg * 2; + } + function use(uint _arg) returns (uint) { + return x(_arg); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("use(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6))); + BOOST_CHECK(callContractFunction("result_in_constructor()") == encodeArgs(u256(4))); +} + +// TODO: store bound internal library functions + +BOOST_AUTO_TEST_CASE(store_internal_unused_function_in_constructor) +{ + char const* sourceCode = R"( + contract C { + function () internal returns (uint) x; + function C () { + x = unused; + } + function unused() internal returns (uint) { + return 7; + } + function t() returns (uint) { + return x(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7))); +} + +BOOST_AUTO_TEST_CASE(store_internal_unused_library_function_in_constructor) +{ + char const* sourceCode = R"( + library L { function x() internal returns (uint) { return 7; } } + contract C { + function () internal returns (uint) x; + function C () { + x = L.x; + } + function t() returns (uint) { + return x(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("t()") == encodeArgs(u256(7))); +} + +BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime) +{ + char const* sourceCode = R"( + contract C { + uint public initial; + function C() { + initial = double(2); + } + function double(uint _arg) returns (uint _ret) { + _ret = _arg * 2; + } + function runtime(uint _arg) returns (uint) { + return double(_arg); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("runtime(uint256)", encodeArgs(u256(3))) == encodeArgs(u256(6))); + BOOST_CHECK(callContractFunction("initial()") == encodeArgs(u256(4))); +} + +BOOST_AUTO_TEST_CASE(same_function_in_construction_and_runtime_equality_check) +{ + char const* sourceCode = R"( + contract C { + function (uint) internal returns (uint) x; + function C() { + x = double; + } + function test() returns (bool) { + return x == double; + } + function double(uint _arg) returns (uint _ret) { + _ret = _arg * 2; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(true)); +} + +BOOST_AUTO_TEST_CASE(function_type_library_internal) +{ + char const* sourceCode = R"( + library Utils { + function reduce(uint[] memory array, function(uint, uint) returns (uint) f, uint init) internal returns (uint) { + for (uint i = 0; i < array.length; i++) { + init = f(array[i], init); + } + return init; + } + function sum(uint a, uint b) internal returns (uint) { + return a + b; + } + } + contract C { + function f(uint[] x) returns (uint) { + return Utils.reduce(x, Utils.sum, 0); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f(uint256[])", 0x20, 3, u256(1), u256(7), u256(3)) == encodeArgs(u256(11))); +} + + +BOOST_AUTO_TEST_CASE(call_function_returning_function) +{ + char const* sourceCode = R"( + contract test { + function f0() returns (uint) { + return 2; + } + function f1() internal returns (function() returns (uint)) { + return f0; + } + function f2() internal returns (function() returns (function () returns (uint))) { + return f1; + } + function f3() internal returns (function() returns (function () returns (function () returns (uint)))) + { + return f2; + } + function f() returns (uint) { + function() returns(function() returns(function() returns(function() returns(uint)))) x; + x = f3; + return x()()()(); + } + } + )"; + + compileAndRun(sourceCode, 0, "test"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2))); +} + +BOOST_AUTO_TEST_CASE(mapping_of_functions) +{ + char const* sourceCode = R"( + contract Flow { + bool public success; + + mapping (address => function () internal) stages; + + function stage0() internal { + stages[msg.sender] = stage1; + } + + function stage1() internal { + stages[msg.sender] = stage2; + } + + function stage2() internal { + success = true; + } + + function Flow() { + stages[msg.sender] = stage0; + } + + function f() returns (uint) { + stages[msg.sender](); + return 7; + } + } + )"; + + compileAndRun(sourceCode, 0, "Flow"); + BOOST_CHECK(callContractFunction("success()") == encodeArgs(false)); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("success()") == encodeArgs(false)); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("success()") == encodeArgs(true)); +} + +BOOST_AUTO_TEST_CASE(packed_functions) +{ + char const* sourceCode = R"( + contract C { + // these should take the same slot + function() returns (uint) a; + function() external returns (uint) b; + function() external returns (uint) c; + function() returns (uint) d; + uint8 public x; + + function set() { + x = 2; + d = g; + c = this.h; + b = this.h; + a = g; + } + function t1() returns (uint) { + return a(); + } + function t2() returns (uint) { + return b(); + } + function t3() returns (uint) { + return a(); + } + function t4() returns (uint) { + return b(); + } + function g() returns (uint) { + return 7; + } + function h() returns (uint) { + return 8; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("set()") == encodeArgs()); + BOOST_CHECK(callContractFunction("t1()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("t2()") == encodeArgs(u256(8))); + BOOST_CHECK(callContractFunction("t3()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("t4()") == encodeArgs(u256(8))); + BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(2))); +} + +BOOST_AUTO_TEST_CASE(function_memory_array) +{ + char const* sourceCode = R"( + contract C { + function a(uint x) returns (uint) { return x + 1; } + function b(uint x) returns (uint) { return x + 2; } + function c(uint x) returns (uint) { return x + 3; } + function d(uint x) returns (uint) { return x + 5; } + function e(uint x) returns (uint) { return x + 8; } + function test(uint x, uint i) returns (uint) { + function(uint) internal returns (uint)[] memory arr = + new function(uint) internal returns (uint)[](10); + arr[0] = a; + arr[1] = b; + arr[2] = c; + arr[3] = d; + arr[4] = e; + return arr[i](x); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(0)) == encodeArgs(u256(11))); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(1)) == encodeArgs(u256(12))); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(2)) == encodeArgs(u256(13))); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(3)) == encodeArgs(u256(15))); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(4)) == encodeArgs(u256(18))); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", u256(10), u256(5)) == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(function_delete_storage) +{ + char const* sourceCode = R"( + contract C { + function a() returns (uint) { return 7; } + function() internal returns (uint) y; + function set() returns (uint) { + y = a; + return y(); + } + function d() returns (uint) { + delete y; + return 1; + } + function ca() returns (uint) { + return y(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("set()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("ca()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("d()") == encodeArgs(u256(1))); + BOOST_CHECK(callContractFunction("ca()") == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(function_delete_stack) +{ + char const* sourceCode = R"( + contract C { + function a() returns (uint) { return 7; } + function test() returns (uint) { + var y = a; + delete y; + y(); + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(copy_function_storage_array) +{ + char const* sourceCode = R"( + contract C { + function() internal returns (uint)[] x; + function() internal returns (uint)[] y; + function test() returns (uint) { + x.length = 10; + x[9] = a; + y = x; + return y[9](); + } + function a() returns (uint) { + return 7; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(7))); +} + +BOOST_AUTO_TEST_CASE(function_array_cross_calls) +{ + char const* sourceCode = R"( + contract D { + function f(function() external returns (function() external returns (uint))[] x) + returns (function() external returns (uint)[3] r) + { + r[0] = x[0](); + r[1] = x[1](); + r[2] = x[2](); + } + } + contract C { + function test() returns (uint, uint, uint) { + function() external returns (function() external returns (uint))[] memory x = + new function() external returns (function() external returns (uint))[](10); + for (uint i = 0; i < x.length; i ++) + x[i] = this.h; + x[0] = this.htwo; + var y = (new D()).f(x); + return (y[0](), y[1](), y[2]()); + } + function e() returns (uint) { return 5; } + function f() returns (uint) { return 6; } + function g() returns (uint) { return 7; } + uint counter; + function h() returns (function() external returns (uint)) { + return counter++ == 0 ? this.f : this.g; + } + function htwo() returns (function() external returns (uint)) { + return this.e; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(5), u256(6), u256(7))); +} + +BOOST_AUTO_TEST_CASE(copy_internal_function_array_to_storage) +{ + char const* sourceCode = R"( + contract C { + function() internal returns (uint)[20] x; + int mutex; + function one() returns (uint) { + function() internal returns (uint)[20] xmem; + x = xmem; + return 3; + } + function two() returns (uint) { + if (mutex > 0) + return 7; + mutex = 1; + // If this test fails, it might re-execute this function. + x[0](); + return 2; + } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("one()") == encodeArgs(u256(3))); + BOOST_CHECK(callContractFunction("two()") == encodeArgs()); +} + BOOST_AUTO_TEST_CASE(shift_constant_left) { char const* sourceCode = R"( |