diff options
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | TestHelper.cpp | 20 | ||||
-rw-r--r-- | TestHelper.h | 2 | ||||
-rw-r--r-- | libsolidity/SolidityEndToEndTest.cpp | 593 | ||||
-rw-r--r-- | libsolidity/SolidityNameAndTypeResolution.cpp | 110 | ||||
-rw-r--r-- | libsolidity/SolidityWallet.cpp | 31 | ||||
-rw-r--r-- | libsolidity/solidityExecutionFramework.h | 8 |
7 files changed, 751 insertions, 18 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d39a5cca..cbf18480 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,9 +72,12 @@ add_executable(testeth ${SRC_LIST} ${HEADERS}) target_link_libraries(testeth ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(testeth ${CURL_LIBRARIES}) +target_link_libraries(testeth ${CRYPTOPP_LIBRARIES}) target_link_libraries(testeth ethereum) target_link_libraries(testeth ethcore) -target_link_libraries(testeth secp256k1) +if (NOT WIN32) + target_link_libraries(testeth secp256k1) +endif() if (JSCONSOLE) target_link_libraries(testeth jsengine) diff --git a/TestHelper.cpp b/TestHelper.cpp index 698f3512..b3dee72e 100644 --- a/TestHelper.cpp +++ b/TestHelper.cpp @@ -235,7 +235,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) } void ImportTest::importTransaction(json_spirit::mObject& _o) -{ +{ if (_o.count("secretKey") > 0) { assert(_o.count("nonce") > 0); @@ -728,10 +728,20 @@ Options::Options() for (auto i = 0; i < argc; ++i) { auto arg = std::string{argv[i]}; - if (arg == "--jit") - eth::VMFactory::setKind(eth::VMKind::JIT); - else if (arg == "--vm=smart") - eth::VMFactory::setKind(eth::VMKind::Smart); + if (arg == "--vm" && i + 1 < argc) + { + string vmKind = argv[++i]; + if (vmKind == "interpreter") + VMFactory::setKind(VMKind::Interpreter); + else if (vmKind == "jit") + VMFactory::setKind(VMKind::JIT); + else if (vmKind == "smart") + VMFactory::setKind(VMKind::Smart); + else + cerr << "Unknown VM kind: " << vmKind << endl; + } + else if (arg == "--jit") // TODO: Remove deprecated option "--jit" + VMFactory::setKind(VMKind::JIT); else if (arg == "--vmtrace") vmtrace = true; else if (arg == "--filltests") diff --git a/TestHelper.h b/TestHelper.h index 73b560aa..1c1dfb5f 100644 --- a/TestHelper.h +++ b/TestHelper.h @@ -224,7 +224,7 @@ public: bool bigData = false; bool wallet = false; bool nonetwork = false; - bool nodag = false; + bool nodag = true; /// @} /// Get reference to options diff --git a/libsolidity/SolidityEndToEndTest.cpp b/libsolidity/SolidityEndToEndTest.cpp index a839aa02..3ddb0552 100644 --- a/libsolidity/SolidityEndToEndTest.cpp +++ b/libsolidity/SolidityEndToEndTest.cpp @@ -4355,6 +4355,306 @@ BOOST_AUTO_TEST_CASE(accessor_involving_strings) BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result); } +BOOST_AUTO_TEST_CASE(bytes_in_function_calls) +{ + char const* sourceCode = R"( + contract Main { + string public s1; + string public s2; + function set(string _s1, uint x, string _s2) returns (uint) { + s1 = _s1; + s2 = _s2; + return x; + } + function setIndirectFromMemory(string _s1, uint x, string _s2) returns (uint) { + return this.set(_s1, x, _s2); + } + function setIndirectFromCalldata(string _s1, uint x, string _s2) external returns (uint) { + return this.set(_s1, x, _s2); + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"); + vector<size_t> lengthes{0, 31, 64, 65}; + for (auto l1: lengthes) + for (auto l2: lengthes) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2)); + bytes args1 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2; + BOOST_REQUIRE( + callContractFunction("setIndirectFromMemory(string,uint256,string)", asString(args1)) == + encodeArgs(u256(l1)) + ); + BOOST_CHECK(callContractFunction("s1()") == encodeArgs(0x20) + dyn1); + BOOST_CHECK(callContractFunction("s2()") == encodeArgs(0x20) + dyn2); + // swapped + bytes args2 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn2.size())) + dyn2 + dyn1; + BOOST_REQUIRE( + callContractFunction("setIndirectFromCalldata(string,uint256,string)", asString(args2)) == + encodeArgs(u256(l1)) + ); + BOOST_CHECK(callContractFunction("s1()") == encodeArgs(0x20) + dyn2); + BOOST_CHECK(callContractFunction("s2()") == encodeArgs(0x20) + dyn1); + } +} + +BOOST_AUTO_TEST_CASE(return_bytes_internal) +{ + char const* sourceCode = R"( + contract Main { + bytes s1; + function doSet(bytes _s1) returns (bytes _r1) { + s1 = _s1; + _r1 = s1; + } + function set(bytes _s1) external returns (uint _r, bytes _r1) { + _r1 = doSet(_s1); + _r = _r1.length; + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + vector<size_t> lengthes{0, 31, 64, 65}; + for (auto l1: lengthes) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes args1 = encodeArgs(u256(0x20)) + dyn1; + BOOST_REQUIRE( + callContractFunction("set(bytes)", asString(args1)) == + encodeArgs(u256(l1), u256(0x40)) + dyn1 + ); + } +} + +BOOST_AUTO_TEST_CASE(bytes_index_access_memory) +{ + char const* sourceCode = R"( + contract Main { + function f(bytes _s1, uint i1, uint i2, uint i3) returns (byte c1, byte c2, byte c3) { + c1 = _s1[i1]; + c2 = intern(_s1, i2); + c3 = internIndirect(_s1)[i3]; + } + function intern(bytes _s1, uint i) returns (byte c) { + return _s1[i]; + } + function internIndirect(bytes _s1) returns (bytes) { + return _s1; + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + bytes args1 = encodeArgs(u256(0x80), u256(3), u256(4), u256(5)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(bytes,uint256,uint256,uint256)", asString(args1)) == + encodeArgs(string{s1[3]}, string{s1[4]}, string{s1[5]}) + ); +} + +BOOST_AUTO_TEST_CASE(bytes_in_constructors_unpacker) +{ + char const* sourceCode = R"( + contract Test { + uint public m_x; + bytes public m_s; + function Test(uint x, bytes s) { + m_x = x; + m_s = s; + } + } + )"; + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + compileAndRun(sourceCode, 0, "Test", args1); + BOOST_REQUIRE(callContractFunction("m_x()") == encodeArgs(x)); + BOOST_REQUIRE(callContractFunction("m_s()") == encodeArgs(u256(0x20)) + dyn1); +} + +BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer) +{ + char const* sourceCode = R"( + contract Base { + uint public m_x; + bytes m_s; + function Base(uint x, bytes s) { + m_x = x; + m_s = s; + } + function part(uint i) returns (byte) { + return m_s[i]; + } + } + contract Main is Base { + function Main(bytes s, uint x) Base(x, f(s)) {} + function f(bytes s) returns (bytes) { + return s; + } + } + contract Creator { + function f(uint x, bytes s) returns (uint r, byte ch) { + var c = new Main(s, x); + r = c.m_x(); + ch = c.part(x); + } + } + )"; + compileAndRun(sourceCode, 0, "Creator"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(uint256,bytes)", asString(args1)) == + encodeArgs(x, string{s1[unsigned(x)]}) + ); +} + +BOOST_AUTO_TEST_CASE(arrays_in_constructors) +{ + char const* sourceCode = R"( + contract Base { + uint public m_x; + address[] m_s; + function Base(uint x, address[] s) { + m_x = x; + m_s = s; + } + function part(uint i) returns (address) { + return m_s[i]; + } + } + contract Main is Base { + function Main(address[] s, uint x) Base(x, f(s)) {} + function f(address[] s) returns (address[]) { + return s; + } + } + contract Creator { + function f(uint x, address[] s) returns (uint r, address ch) { + var c = new Main(s, x); + r = c.m_x(); + ch = c.part(x); + } + } + )"; + compileAndRun(sourceCode, 0, "Creator"); + vector<u256> s1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + bytes dyn1 = encodeArgs(u256(s1.size()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(uint256,address[])", asString(args1)) == + encodeArgs(x, s1[unsigned(x)]) + ); +} + +BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage) +{ + char const* sourceCode = R"( + contract Test { + uint24[] public data; + function set(uint24[] _data) returns (uint) { + data = _data; + return data.length; + } + function get() returns (uint24[]) { + return data; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector<u256> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[])", u256(0x20), u256(data.size()), data) == + encodeArgs(u256(data.size())) + ); + BOOST_CHECK(callContractFunction("data(uint256)", u256(7)) == encodeArgs(u256(8))); + BOOST_CHECK(callContractFunction("data(uint256)", u256(15)) == encodeArgs(u256(16))); + BOOST_CHECK(callContractFunction("data(uint256)", u256(18)) == encodeArgs()); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0x20), u256(data.size()), data)); +} + +BOOST_AUTO_TEST_CASE(arrays_complex_from_and_to_storage) +{ + char const* sourceCode = R"( + contract Test { + uint24[3][] public data; + function set(uint24[3][] _data) returns (uint) { + data = _data; + return data.length; + } + function get() returns (uint24[3][]) { + return data; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector<u256> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[3][])", u256(0x20), u256(data.size() / 3), data) == + encodeArgs(u256(data.size() / 3)) + ); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(2), u256(2)) == encodeArgs(u256(9))); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(5), u256(1)) == encodeArgs(u256(17))); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(6), u256(0)) == encodeArgs()); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0x20), u256(data.size() / 3), data)); +} + +BOOST_AUTO_TEST_CASE(arrays_complex_memory_index_access) +{ + char const* sourceCode = R"( + contract Test { + function set(uint24[3][] _data, uint a, uint b) returns (uint l, uint e) { + l = _data.length; + e = _data[a][b]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector<u256> data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE(callContractFunction( + "set(uint24[3][],uint256,uint256)", + u256(0x60), + u256(3), + u256(2), + u256(data.size() / 3), + data + ) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2]))); +} + +BOOST_AUTO_TEST_CASE(bytes_memory_index_access) +{ + char const* sourceCode = R"( + contract Test { + function set(bytes _data, uint i) returns (uint l, byte c) { + l = _data.length; + c = _data[i]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + string data("abcdefgh"); + BOOST_REQUIRE(callContractFunction( + "set(bytes,uint256)", + u256(0x40), + u256(3), + u256(data.size()), + data + ) == encodeArgs(u256(data.size()), string("d"))); +} + BOOST_AUTO_TEST_CASE(storage_array_ref) { char const* sourceCode = R"( @@ -4408,6 +4708,299 @@ BOOST_AUTO_TEST_CASE(storage_array_ref) BOOST_CHECK(callContractFunction("find(uint256)", u256(400)) == encodeArgs(u256(-1))); } +BOOST_AUTO_TEST_CASE(memory_types_initialisation) +{ + char const* sourceCode = R"( + contract Test { + mapping(uint=>uint) data; + function stat() returns (uint[5]) + { + data[2] = 3; // make sure to use some memory + } + function dyn() returns (uint[]) { stat(); } + function nested() returns (uint[3][]) { stat(); } + function nestedStat() returns (uint[3][7]) { stat(); } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + BOOST_CHECK(callContractFunction("stat()") == encodeArgs(vector<u256>(5))); + BOOST_CHECK(callContractFunction("dyn()") == encodeArgs(u256(0x20), u256(0))); + BOOST_CHECK(callContractFunction("nested()") == encodeArgs(u256(0x20), u256(0))); + BOOST_CHECK(callContractFunction("nestedStat()") == encodeArgs(vector<u256>(3 * 7))); +} + +BOOST_AUTO_TEST_CASE(memory_arrays_delete) +{ + char const* sourceCode = R"( + contract Test { + function del() returns (uint24[3][4]) { + uint24[3][4] memory x; + for (uint24 i = 0; i < x.length; i ++) + for (uint24 j = 0; j < x[i].length; j ++) + x[i][j] = i * 0x10 + j; + delete x[1]; + delete x[3][2]; + return x; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector<u256> data(3 * 4); + for (unsigned i = 0; i < 4; i++) + for (unsigned j = 0; j < 3; j++) + { + u256 v = 0; + if (!(i == 1 || (i == 3 && j == 2))) + v = i * 0x10 + j; + data[i * 3 + j] = v; + } + BOOST_CHECK(callContractFunction("del()") == encodeArgs(data)); +} + +BOOST_AUTO_TEST_CASE(memory_arrays_index_access_write) +{ + char const* sourceCode = R"( + contract Test { + function set(uint24[3][4] x) { + x[2][2] = 1; + x[3][2] = 7; + } + function f() returns (uint24[3][4]){ + uint24[3][4] memory data; + set(data); + return data; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector<u256> data(3 * 4); + data[3 * 2 + 2] = 1; + data[3 * 3 + 2] = 7; + BOOST_CHECK(callContractFunction("f()") == encodeArgs(data)); +} + +BOOST_AUTO_TEST_CASE(memory_arrays_dynamic_index_access_write) +{ + char const* sourceCode = R"( + contract Test { + uint24[3][][4] data; + function set(uint24[3][][4] x) internal returns (uint24[3][][4]) { + x[1][2][2] = 1; + x[1][3][2] = 7; + return x; + } + function f() returns (uint24[3][]) { + data[1].length = 4; + return set(data)[1]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector<u256> data(3 * 4); + data[3 * 2 + 2] = 1; + data[3 * 3 + 2] = 7; + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0x20), u256(4), data)); +} + +BOOST_AUTO_TEST_CASE(memory_structs_read_write) +{ + char const* sourceCode = R"( + contract Test { + struct S { uint8 x; uint16 y; uint z; uint8[2] a; } + S[5] data; + function testInit() returns (uint8 x, uint16 y, uint z, uint8 a, bool flag) { + S[2] memory d; + x = d[0].x; + y = d[0].y; + z = d[0].z; + a = d[0].a[1]; + flag = true; + } + function testCopyRead() returns (uint8 x, uint16 y, uint z, uint8 a) { + data[2].x = 1; + data[2].y = 2; + data[2].z = 3; + data[2].a[1] = 4; + S memory s = data[2]; + x = s.x; + y = s.y; + z = s.z; + a = s.a[1]; + } + function testAssign() returns (uint8 x, uint16 y, uint z, uint8 a) { + S memory s; + s.x = 1; + s.y = 2; + s.z = 3; + s.a[1] = 4; + x = s.x; + y = s.y; + z = s.z; + a = s.a[1]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + BOOST_CHECK(callContractFunction("testInit()") == encodeArgs(u256(0), u256(0), u256(0), u256(0), true)); + BOOST_CHECK(callContractFunction("testCopyRead()") == encodeArgs(u256(1), u256(2), u256(3), u256(4))); + BOOST_CHECK(callContractFunction("testAssign()") == encodeArgs(u256(1), u256(2), u256(3), u256(4))); +} + +BOOST_AUTO_TEST_CASE(memory_structs_as_function_args) +{ + char const* sourceCode = R"( + contract Test { + struct S { uint8 x; uint16 y; uint z; } + function test() returns (uint x, uint y, uint z) { + S memory data = combine(1, 2, 3); + x = extract(data, 0); + y = extract(data, 1); + z = extract(data, 2); + } + function extract(S s, uint which) internal returns (uint x) { + if (which == 0) return s.x; + else if (which == 1) return s.y; + else return s.z; + } + function combine(uint8 x, uint16 y, uint z) internal returns (S s) { + s.x = x; + s.y = y; + s.z = z; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(1), u256(2), u256(3))); +} + +BOOST_AUTO_TEST_CASE(memory_structs_nested) +{ + char const* sourceCode = R"( + contract Test { + struct S { uint8 x; uint16 y; uint z; } + struct X { uint8 x; S s; } + function test() returns (uint a, uint x, uint y, uint z) { + X memory d = combine(1, 2, 3, 4); + a = extract(d, 0); + x = extract(d, 1); + y = extract(d, 2); + z = extract(d, 3); + } + function extract(X s, uint which) internal returns (uint x) { + if (which == 0) return s.x; + else if (which == 1) return s.s.x; + else if (which == 2) return s.s.y; + else return s.s.z; + } + function combine(uint8 a, uint8 x, uint16 y, uint z) internal returns (X s) { + s.x = a; + s.s.x = x; + s.s.y = y; + s.s.z = z; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(1), u256(2), u256(3), u256(4))); +} + +BOOST_AUTO_TEST_CASE(memory_structs_nested_load) +{ + char const* sourceCode = R"( + contract Test { + struct S { uint8 x; uint16 y; uint z; } + struct X { uint8 x; S s; uint8[2] a; } + X m_x; + function load() returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { + m_x.x = 1; + m_x.s.x = 2; + m_x.s.y = 3; + m_x.s.z = 4; + m_x.a[0] = 5; + m_x.a[1] = 6; + X memory d = m_x; + a = d.x; + x = d.s.x; + y = d.s.y; + z = d.s.z; + a1 = d.a[0]; + a2 = d.a[1]; + } + function store() returns (uint a, uint x, uint y, uint z, uint a1, uint a2) { + X memory d; + d.x = 1; + d.s.x = 2; + d.s.y = 3; + d.s.z = 4; + d.a[0] = 5; + d.a[1] = 6; + m_x = d; + a = m_x.x; + x = m_x.s.x; + y = m_x.s.y; + z = m_x.s.z; + a1 = m_x.a[0]; + a2 = m_x.a[1]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + auto out = encodeArgs(u256(1), u256(2), u256(3), u256(4), u256(5), u256(6)); + BOOST_CHECK(callContractFunction("load()") == out); + BOOST_CHECK(callContractFunction("store()") == out); +} + +BOOST_AUTO_TEST_CASE(struct_constructor_nested) +{ + char const* sourceCode = R"( + contract C { + struct X { uint x1; uint x2; } + struct S { uint s1; uint[3] s2; X s3; } + S s; + function C() { + uint[3] memory s2; + s2[1] = 9; + s = S(1, s2, X(4, 5)); + } + function get() returns (uint s1, uint[3] s2, uint x1, uint x2) + { + s1 = s.s1; + s2 = s.s2; + x1 = s.s3.x1; + x2 = s.s3.x2; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + + auto out = encodeArgs(u256(1), u256(0), u256(9), u256(0), u256(4), u256(5)); + BOOST_CHECK(callContractFunction("get()") == out); +} + +BOOST_AUTO_TEST_CASE(struct_named_constructor) +{ + char const* sourceCode = R"( + contract C { + struct S { uint a; bool x; } + S public s; + function C() { + s = S({a: 1, x: true}); + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + + BOOST_CHECK(callContractFunction("s()") == encodeArgs(u256(1), true)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/libsolidity/SolidityNameAndTypeResolution.cpp b/libsolidity/SolidityNameAndTypeResolution.cpp index afa8b727..50fcdbbe 100644 --- a/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/libsolidity/SolidityNameAndTypeResolution.cpp @@ -403,6 +403,23 @@ BOOST_AUTO_TEST_CASE(abstract_contract) BOOST_CHECK(derived->getDefinedFunctions()[0]->isFullyImplemented()); } +BOOST_AUTO_TEST_CASE(abstract_contract_with_overload) +{ + ASTPointer<SourceUnit> sourceUnit; + char const* text = R"( + contract base { function foo(bool); } + contract derived is base { function foo(uint) {} } + )"; + ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed"); + std::vector<ASTPointer<ASTNode>> nodes = sourceUnit->getNodes(); + ContractDefinition* base = dynamic_cast<ContractDefinition*>(nodes[0].get()); + ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[1].get()); + BOOST_REQUIRE(base); + BOOST_CHECK(!base->isFullyImplemented()); + BOOST_REQUIRE(derived); + BOOST_CHECK(!derived->isFullyImplemented()); +} + BOOST_AUTO_TEST_CASE(create_abstract_contract) { ASTPointer<SourceUnit> sourceUnit; @@ -1900,6 +1917,18 @@ BOOST_AUTO_TEST_CASE(storage_location_local_variables) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); } +BOOST_AUTO_TEST_CASE(no_mappings_in_memory_array) +{ + char const* sourceCode = R"( + contract C { + function f() { + mapping(uint=>uint)[] memory x; + } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_CASE(assignment_mem_to_local_storage_variable) { char const* sourceCode = R"( @@ -1931,6 +1960,20 @@ BOOST_AUTO_TEST_CASE(storage_assign_to_different_local_variable) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(no_delete_on_storage_pointers) +{ + char const* sourceCode = R"( + contract C { + uint[] data; + function f() { + var x = data; + delete x; + } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_CASE(assignment_mem_storage_variable_directly) { char const* sourceCode = R"( @@ -1987,6 +2030,73 @@ BOOST_AUTO_TEST_CASE(mem_array_assignment_changes_base_type) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible) +{ + char const* sourceCode = R"( + contract C { + function f(uint) returns (string); + function g() { + var x = this.f(2); + } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(memory_arrays_not_resizeable) +{ + char const* sourceCode = R"( + contract C { + function f() { + uint[] memory x; + x.length = 2; + } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(struct_constructor) +{ + char const* sourceCode = R"( + contract C { + struct S { uint a; bool x; } + function f() { + S memory s = S(1, true); + } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + +BOOST_AUTO_TEST_CASE(struct_constructor_nested) +{ + char const* sourceCode = R"( + contract C { + struct X { uint x1; uint x2; } + struct S { uint s1; uint[3] s2; X s3; } + function f() { + uint[3] memory s2; + S memory s = S(1, s2, X(4, 5)); + } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + +BOOST_AUTO_TEST_CASE(struct_named_constructor) +{ + char const* sourceCode = R"( + contract C { + struct S { uint a; bool x; } + function f() { + S memory s = S({a: 1, x: true}); + } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/libsolidity/SolidityWallet.cpp b/libsolidity/SolidityWallet.cpp index 09820b87..ba8f198f 100644 --- a/libsolidity/SolidityWallet.cpp +++ b/libsolidity/SolidityWallet.cpp @@ -200,17 +200,17 @@ contract multiowned { } // the number of owners that must confirm the same operation before it is run. - uint m_required; + uint public m_required; // pointer used to find a free slot in m_owners - uint m_numOwners; + uint public m_numOwners; // list of owners - uint[256] m_owners; + uint[256] public m_owners; uint constant c_maxOwners = 250; // index on the list of owners to allow reverse lookup - mapping(uint => uint) m_ownerIndex; + mapping(uint => uint) public m_ownerIndex; // the ongoing operations. - mapping(bytes32 => PendingState) m_pending; - bytes32[] m_pendingIndex; + mapping(bytes32 => PendingState) public m_pending; + bytes32[] public m_pendingIndex; } // inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable) @@ -251,9 +251,9 @@ contract daylimit is multiowned { } // determines today's index. function today() private constant returns (uint) { return now / 1 days; } - uint m_spentToday; - uint m_dailyLimit; - uint m_lastDay; + uint public m_spentToday; + uint public m_dailyLimit; + uint public m_lastDay; } // interface contract for multisig proxy contracts; see below for docs. contract multisig { @@ -275,11 +275,14 @@ contract Wallet is multisig, multiowned, daylimit { uint value; bytes data; } + /* // logged events: // Funds has arrived into the wallet (record how much). event Deposit(address from, uint value); // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). event SingleTransact(address owner, uint value, address to, bytes data); + // Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going). + event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data);*/ // constructor - just pass on the owner arra to the multiowned. event Created(); function Wallet() { @@ -299,7 +302,7 @@ contract Wallet is multisig, multiowned, daylimit { // If not, goes into multisig process. We provide a hash on return to allow the sender to provide // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value // and _data arguments). They still get the option of using them if they want, anyways. - function execute(address _to, uint _value, bytes _data) onlyowner external returns (bytes32 _r) { + function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 _r) { // first, take the opportunity to check that we're under the daily limit. if (underLimit(_value)) { SingleTransact(msg.sender, _value, _to, _data); @@ -332,8 +335,14 @@ contract Wallet is multisig, multiowned, daylimit { delete m_txs[m_pendingIndex[i]]; super.clearPending(); } + // // internally confirm transaction with all of the info. returns true iff confirmed good and executed. + // function confirmVerbose(bytes32 _h, address _to, uint _value, bytes _data) private onlymanyowners(_h) returns (bool) { + // _to.call.value(_value)(_data); + // MultiTransact("out", msg.sender, _h, _value, _to); + // return true; + // } // pending transactions we have at present. - mapping (bytes32 => Transaction) m_txs; + mapping (bytes32 => Transaction) public m_txs; } )DELIMITER"; diff --git a/libsolidity/solidityExecutionFramework.h b/libsolidity/solidityExecutionFramework.h index 0079d82b..200940a4 100644 --- a/libsolidity/solidityExecutionFramework.h +++ b/libsolidity/solidityExecutionFramework.h @@ -127,6 +127,14 @@ public: return _padLeft ? padding + _value : _value + padding; } static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + template <class _T> + static bytes encode(std::vector<_T> const& _value) + { + bytes ret; + for (auto const& v: _value) + ret += encode(v); + return ret; + } template <class FirstArg, class... Args> static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) |