From dca13033973c4346326cd23c71a02c8ea12b0e50 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 25 Feb 2015 20:27:55 +0100 Subject: [PATCH 01/10] Shortening of dynamic arrays. --- SolidityEndToEndTest.cpp | 90 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/SolidityEndToEndTest.cpp b/SolidityEndToEndTest.cpp index f52b52d1c..5b99f72e0 100644 --- a/SolidityEndToEndTest.cpp +++ b/SolidityEndToEndTest.cpp @@ -2768,6 +2768,96 @@ BOOST_AUTO_TEST_CASE(dynamic_out_of_bounds_array_access) BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); } +BOOST_AUTO_TEST_CASE(fixed_array_cleanup) +{ + char const* sourceCode = R"( + contract c { + uint spacer1; + uint spacer2; + uint[20] data; + function fill() { + for (uint i = 0; i < data.length; ++i) data[i] = i+1; + } + function clear() { delete data; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("fill()") == bytes()); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("clear()") == bytes()); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + +BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup) +{ + char const* sourceCode = R"( + contract c { + uint spacer1; + uint spacer2; + uint[3] data; + function fill() { + for (uint i = 0; i < data.length; ++i) data[i] = i+1; + } + function clear() { delete data; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("fill()") == bytes()); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("clear()") == bytes()); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + +BOOST_AUTO_TEST_CASE(dynamic_array_cleanup) +{ + char const* sourceCode = R"( + contract c { + uint[20] spacer; + uint[] dynamic; + function fill() { + dynamic.length = 21; + for (uint i = 0; i < dynamic.length; ++i) dynamic[i] = i+1; + } + function halfClear() { dynamic.length = 5; } + function fullClear() { delete dynamic; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("fill()") == bytes()); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("halfClear()") == bytes()); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("fullClear()") == bytes()); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + +BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup) +{ + char const* sourceCode = R"( + contract c { + struct s { uint[][] d; } + s[] data; + function fill() returns (uint) { + data.length = 3; + data[2].d.length = 4; + data[2].d[3].length = 5; + data[2].d[3][4] = 8; + return data[2].d[3][4]; + } + function clear() { delete data; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("fill()") == encodeArgs(8)); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("clear()") == bytes()); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + BOOST_AUTO_TEST_SUITE_END() } From e42183f2ff4e49bdba598651ab5f2c1d81042a57 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 27 Feb 2015 14:50:06 +0100 Subject: [PATCH 02/10] Type checks for array assignment. --- SolidityNameAndTypeResolution.cpp | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/SolidityNameAndTypeResolution.cpp b/SolidityNameAndTypeResolution.cpp index 4809aac1e..ff9fa1655 100644 --- a/SolidityNameAndTypeResolution.cpp +++ b/SolidityNameAndTypeResolution.cpp @@ -1185,6 +1185,61 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(array_copy_with_different_types1) +{ + char const* text = R"( + contract c { + bytes a; + uint[] b; + function f() { b = a; } + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(array_copy_with_different_types2) +{ + char const* text = R"( + contract c { + uint32[] a; + uint8[] b; + function f() { b = a; } + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(array_copy_with_different_types_conversion_possible) +{ + char const* text = R"( + contract c { + uint32[] a; + uint8[] b; + function f() { a = b; } + })"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic) +{ + char const* text = R"( + contract c { + uint32[] a; + uint8[80] b; + function f() { a = b; } + })"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static) +{ + char const* text = R"( + contract c { + uint[] a; + uint[80] b; + function f() { b = a; } + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From e7c4d73cc6f43c9a9e35c792c1908973aeff55d6 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 27 Feb 2015 22:52:02 +0100 Subject: [PATCH 03/10] Array copy storage to storage. --- SolidityEndToEndTest.cpp | 88 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/SolidityEndToEndTest.cpp b/SolidityEndToEndTest.cpp index 5b99f72e0..f305e81e3 100644 --- a/SolidityEndToEndTest.cpp +++ b/SolidityEndToEndTest.cpp @@ -2858,6 +2858,94 @@ BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup) BOOST_CHECK(m_state.storage(m_contractAddress).empty()); } +BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn) +{ + char const* sourceCode = R"( + contract c { + uint[] data1; + uint[] data2; + function setData1(uint length, uint index, uint value) { + data1.length = length; if (index < length) data1[index] = value; + } + function copyStorageStorage() { data2 = data1; } + function getData2(uint index) returns (uint len, uint val) { + len = data2.length; if (index < len) val = data2[index]; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 10, 5, 4) == bytes()); + BOOST_CHECK(callContractFunction("copyStorageStorage()") == bytes()); + BOOST_CHECK(callContractFunction("getData2(uint256)", 5) == encodeArgs(10, 4)); + BOOST_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 0, 0, 0) == bytes()); + BOOST_CHECK(callContractFunction("copyStorageStorage()") == bytes()); + BOOST_CHECK(callContractFunction("getData2(uint256)", 0) == encodeArgs(0, 0)); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + +BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_static) +{ + char const* sourceCode = R"( + contract c { + uint[40] data1; + uint[20] data2; + function test() returns (uint x, uint y){ + data1[30] = 4; + data1[2] = 7; + data1[3] = 9; + data2[3] = 8; + data1 = data2; + x = data1[3]; + y = data1[30]; // should be cleared + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(8, 0)); +} + +BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_dynamic) +{ + char const* sourceCode = R"( + contract c { + uint[9] data1; + uint[] data2; + function test() returns (uint x, uint y){ + data1[8] = 4; + data2 = data1; + x = data2.length; + y = data2[8]; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(9, 4)); +} + +BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct) +{ + char const* sourceCode = R"( + contract c { + struct Data { uint x; uint y; } + Data[] data1; + Data[] data2; + function test() returns (uint x, uint y) { + data1.length = 9; + data1[8].x = 4; + data1[8].y = 5; + data2 = data1; + x = data2[8].x; + y = data2[8].y; + data1.length = 0; + data2 = data1; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(4, 5)); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + BOOST_AUTO_TEST_SUITE_END() } From 41f9399a32a200d8e133fac9c39d85cb7b62108c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 25 Feb 2015 16:32:04 +0100 Subject: [PATCH 04/10] Adding test for base class statevar accessors --- SolidityNameAndTypeResolution.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/SolidityNameAndTypeResolution.cpp b/SolidityNameAndTypeResolution.cpp index 4809aac1e..e4764c5ef 100644 --- a/SolidityNameAndTypeResolution.cpp +++ b/SolidityNameAndTypeResolution.cpp @@ -720,6 +720,18 @@ BOOST_AUTO_TEST_CASE(private_state_variable) BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist"); } +BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor) +{ + // test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126 + char const* text = "contract Parent {\n" + " uint256 public m_aMember;\n" + "}\n" + "contract Child {\n" + " function foo() returns (uint256) { return Parent.m_aMember(); }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); +} + BOOST_AUTO_TEST_CASE(fallback_function) { char const* text = R"( From 285a376248018de08883c396b43f2cea90e9e53b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 26 Feb 2015 12:11:54 +0100 Subject: [PATCH 05/10] Add structs to inheritable members --- SolidityNameAndTypeResolution.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SolidityNameAndTypeResolution.cpp b/SolidityNameAndTypeResolution.cpp index e4764c5ef..9db45b911 100644 --- a/SolidityNameAndTypeResolution.cpp +++ b/SolidityNameAndTypeResolution.cpp @@ -726,8 +726,8 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor) char const* text = "contract Parent {\n" " uint256 public m_aMember;\n" "}\n" - "contract Child {\n" - " function foo() returns (uint256) { return Parent.m_aMember(); }\n" + "contract Child is Parent{\n" + " function foo() returns (uint256) { return Parent.m_aMember; }\n" "}\n"; BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); } From 03bc87031e0f4836a51dba1a8f4c101c903824f9 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 27 Feb 2015 10:08:14 +0100 Subject: [PATCH 06/10] VisibleInDerivedContracts() is now virtual() - Plus an extra test for internal visibility in a base class variable --- SolidityNameAndTypeResolution.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/SolidityNameAndTypeResolution.cpp b/SolidityNameAndTypeResolution.cpp index 9db45b911..58cebaebb 100644 --- a/SolidityNameAndTypeResolution.cpp +++ b/SolidityNameAndTypeResolution.cpp @@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(inheritance_diamond_basic) function g() { f(); rootFunction(); } } )"; - BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); } BOOST_AUTO_TEST_CASE(cyclic_inheritance) @@ -732,6 +732,17 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor) BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); } +BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member) +{ + char const* text = "contract Parent {\n" + " uint256 internal m_aMember;\n" + "}\n" + "contract Child is Parent{\n" + " function foo() returns (uint256) { return Parent.m_aMember; }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); +} + BOOST_AUTO_TEST_CASE(fallback_function) { char const* text = R"( From 447320a91d266c4d5bd3c249081e52c8c1533df5 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 28 Feb 2015 18:30:33 +0100 Subject: [PATCH 07/10] getInheritableMembers() does not look at BaseContracts - Also adding tests for improper accessing members of other contracts. --- SolidityNameAndTypeResolution.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/SolidityNameAndTypeResolution.cpp b/SolidityNameAndTypeResolution.cpp index 58cebaebb..81d58d0dd 100644 --- a/SolidityNameAndTypeResolution.cpp +++ b/SolidityNameAndTypeResolution.cpp @@ -743,6 +743,35 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member) BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); } +BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1) +{ + char const* text = "contract Parent1 {\n" + " uint256 internal m_aMember1;\n" + "}\n" + "contract Parent2 is Parent1{\n" + " uint256 internal m_aMember2;\n" + "}\n" + "contract Child is Parent2{\n" + " function foo() returns (uint256) { return Parent2.m_aMember1; }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class2) +{ + char const* text = "contract Parent1 {\n" + " uint256 internal m_aMember1;\n" + "}\n" + "contract Parent2 is Parent1{\n" + " uint256 internal m_aMember2;\n" + "}\n" + "contract Child is Parent2{\n" + " function foo() returns (uint256) { return Child.m_aMember2; }\n" + " uint256 public m_aMember3;\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_CASE(fallback_function) { char const* text = R"( From 88ecc27c2b4fd88edbf3bfb283219052cf9b66da Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 27 Feb 2015 17:41:22 +0100 Subject: [PATCH 08/10] Implemented passing arguments to the base constructor. --- SolidityEndToEndTest.cpp | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/SolidityEndToEndTest.cpp b/SolidityEndToEndTest.cpp index f305e81e3..87a8eb79f 100644 --- a/SolidityEndToEndTest.cpp +++ b/SolidityEndToEndTest.cpp @@ -2946,6 +2946,70 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct) BOOST_CHECK(m_state.storage(m_contractAddress).empty()); } +BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base) +{ + char const* sourceCode = R"( + contract Base { + function Base(uint i) + { + m_i = i; + } + uint public m_i; + } + contract Derived is Base(2) { + function Derived(uint i) Base(i) + {} + } + contract Final is Derived(4) { + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4)); +} + +BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base) +{ + char const* sourceCode = R"( + contract Base { + function Base(uint j) + { + m_i = j; + } + uint public m_i; + } + contract Base1 is Base(3) { + function Base1(uint k) Base(k*k) {} + } + contract Derived is Base(3), Base1(2) { + function Derived(uint i) Base(i) Base1(i) + {} + } + contract Final is Derived(4) { + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4)); +} + +BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base_with_gap) +{ + char const* sourceCode = R"( + contract Base { + function Base(uint i) + { + m_i = i; + } + uint public m_i; + } + contract Base1 is Base(3) {} + contract Derived is Base(2), Base1 { + function Derived(uint i) Base(i) {} + } + contract Final is Derived(4) { + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4)); +} + + BOOST_AUTO_TEST_SUITE_END() } From 66d2ec1d15c890ad58302c69068da4d5d1879c92 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 3 Mar 2015 11:36:54 +0100 Subject: [PATCH 09/10] Fix test after change in call failure semantics. --- SolidityEndToEndTest.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SolidityEndToEndTest.cpp b/SolidityEndToEndTest.cpp index 87a8eb79f..9587a3488 100644 --- a/SolidityEndToEndTest.cpp +++ b/SolidityEndToEndTest.cpp @@ -1619,9 +1619,11 @@ BOOST_AUTO_TEST_CASE(gas_and_value_basic) function sendAmount(uint amount) returns (uint256 bal) { return h.getBalance.value(amount)(); } - function outOfGas() returns (bool flagBefore, bool flagAfter, uint myBal) { - flagBefore = h.getFlag(); - h.setFlag.gas(2)(); // should fail due to OOG, return value can be garbage + function outOfGas() returns (bool ret) { + h.setFlag.gas(2)(); // should fail due to OOG + return true; + } + function checkState() returns (bool flagAfter, uint myBal) { flagAfter = h.getFlag(); myBal = this.balance; } @@ -1630,7 +1632,8 @@ BOOST_AUTO_TEST_CASE(gas_and_value_basic) compileAndRun(sourceCode, 20); BOOST_REQUIRE(callContractFunction("sendAmount(uint256)", 5) == encodeArgs(5)); // call to helper should not succeed but amount should be transferred anyway - BOOST_REQUIRE(callContractFunction("outOfGas()", 5) == encodeArgs(false, false, 20 - 5)); + BOOST_REQUIRE(callContractFunction("outOfGas()", 5) == bytes()); + BOOST_REQUIRE(callContractFunction("checkState()", 5) == encodeArgs(false, 20 - 5)); } BOOST_AUTO_TEST_CASE(value_complex) From 99263f0e3e7a58464e211479430c4a21dd6eb5a9 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 3 Mar 2015 11:28:56 +0100 Subject: [PATCH 10/10] Fixed arrays in ABI. --- SolidityEndToEndTest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SolidityEndToEndTest.cpp b/SolidityEndToEndTest.cpp index 87a8eb79f..bc0be186f 100644 --- a/SolidityEndToEndTest.cpp +++ b/SolidityEndToEndTest.cpp @@ -2504,11 +2504,11 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) compileAndRun(sourceCode); string data = "123456789012345678901234567890123"; BOOST_CHECK(m_state.storage(m_contractAddress).empty()); - BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true)); + BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true)); BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true)); BOOST_CHECK(m_state.storage(m_contractAddress).empty()); - BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true)); + BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true)); BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); BOOST_CHECK(callContractFunction("del()") == encodeArgs(true)); BOOST_CHECK(m_state.storage(m_contractAddress).empty()); @@ -2661,8 +2661,8 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13); string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); bytes calldata = encodeArgs( - u256(innercalldata1.length()), u256(innercalldata2.length()), - 12, innercalldata1, innercalldata2, 13); + 12, u256(innercalldata1.length()), u256(innercalldata2.length()), 13, + innercalldata1, innercalldata2); BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata) == encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))); }