diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index a9e0543cb..b65a94f52 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -27,6 +27,8 @@ #include +#include + #include #include @@ -34,6 +36,8 @@ #include #include +#include +#include #include @@ -41,6 +45,7 @@ using namespace std; using namespace solidity; using namespace solidity::util; using namespace solidity::test; +using namespace solidity::frontend::test; ExecutionFramework::ExecutionFramework(): ExecutionFramework(solidity::test::CommonOptions::get().evmVersion(), solidity::test::CommonOptions::get().vmPaths) @@ -282,3 +287,15 @@ bool ExecutionFramework::storageEmpty(h160 const& _addr) const } return true; } + +vector ExecutionFramework::recordedLogs() const +{ + vector logs; + for (evmc::MockedHost::log_record const& logRecord: m_evmcHost->recorded_logs) + logs.emplace_back( + EVMHost::convertFromEVMC(logRecord.creator), + bytes{logRecord.data.begin(), logRecord.data.end()}, + logRecord.topics | ranges::views::transform([](evmc::bytes32 _bytes) { return EVMHost::convertFromEVMC(_bytes); }) | ranges::to + ); + return logs; +} diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index de88679c7..d6912c5d0 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -39,6 +39,11 @@ #include +namespace solidity::frontend::test +{ +struct LogRecord; +} // namespace solidity::frontend::test + namespace solidity::test { using rational = boost::rational; @@ -247,6 +252,12 @@ public: return m_sender; } + size_t numLogs() const; + size_t numLogTopics(size_t _logIdx) const; + util::h256 logTopic(size_t _logIdx, size_t _topicIdx) const; + util::h160 logAddress(size_t _logIdx) const; + bytes logData(size_t _logIdx) const; + private: template auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) @@ -278,11 +289,7 @@ protected: bool storageEmpty(util::h160 const& _addr) const; bool addressHasCode(util::h160 const& _addr) const; - size_t numLogs() const; - size_t numLogTopics(size_t _logIdx) const; - util::h256 logTopic(size_t _logIdx, size_t _topicIdx) const; - util::h160 logAddress(size_t _logIdx) const; - bytes logData(size_t _logIdx) const; + std::vector recordedLogs() const; langutil::EVMVersion m_evmVersion; solidity::frontend::RevertStrings m_revertStrings = solidity::frontend::RevertStrings::Default; diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 1af3cac34..50d7dfcc0 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -178,9 +178,9 @@ map SemanticTest::makeBuiltins() }; } - vector SemanticTest::makeSideEffectHooks() const { + using namespace std::placeholders; return { [](FunctionCall const& _call) -> vector { @@ -192,7 +192,111 @@ vector SemanticTest::makeSideEffectHooks() const return result; } return {}; - }}; + }, + bind(&SemanticTest::eventSideEffectHook, this, _1) + }; +} + +string SemanticTest::formatEventParameter(optional _signature, bool _indexed, size_t _index, bytes const& _data) +{ + auto isPrintableASCII = [](bytes const& s) + { + bool zeroes = true; + for (auto c: s) + { + if (static_cast(c) != 0x00) + { + zeroes = false; + if (static_cast(c) <= 0x1f || static_cast(c) >= 0x7f) + return false; + } else + break; + } + return !zeroes; + }; + + ABIType abiType(ABIType::Type::Hex); + if (isPrintableASCII(_data)) + abiType = ABIType(ABIType::Type::String); + if (_signature.has_value()) + { + vector const& types = _indexed ? _signature->indexedTypes : _signature->nonIndexedTypes; + if (_index < types.size()) + { + if (types.at(_index) == "bool") + abiType = ABIType(ABIType::Type::Boolean); + } + } + return BytesUtils::formatBytes(_data, abiType); +} + +vector SemanticTest::eventSideEffectHook(FunctionCall const&) const +{ + vector sideEffects; + vector recordedLogs = ExecutionFramework::recordedLogs(); + for (LogRecord const& log: recordedLogs) + { + optional eventSignature; + if (!log.topics.empty()) + eventSignature = matchEvent(log.topics[0]); + stringstream sideEffect; + sideEffect << "emit "; + if (eventSignature.has_value()) + sideEffect << eventSignature.value().signature; + else + sideEffect << ""; + + if (m_contractAddress != log.creator) + sideEffect << " from 0x" << log.creator; + + vector eventStrings; + size_t index{0}; + for (h256 const& topic: log.topics) + { + if (!eventSignature.has_value() || index != 0) + eventStrings.push_back("#" + formatEventParameter(eventSignature, true, index, topic.asBytes())); + ++index; + } + + soltestAssert(log.data.size() % 32 == 0, ""); + for (size_t index = 0; index < log.data.size() / 32; ++index) + { + auto begin = log.data.begin() + static_cast(index * 32); + bytes const& data = bytes{begin, begin + 32}; + eventStrings.emplace_back(formatEventParameter(eventSignature, false, index, data)); + } + + if (!eventStrings.empty()) + sideEffect << ": "; + sideEffect << joinHumanReadable(eventStrings); + sideEffects.emplace_back(sideEffect.str()); + } + return sideEffects; +} + +optional SemanticTest::matchEvent(util::h256 const& hash) const +{ + optional result; + for (string& contractName: m_compiler.contractNames()) + { + ContractDefinition const& contract = m_compiler.contractDefinition(contractName); + for (EventDefinition const* event: contract.events()) + { + FunctionTypePointer eventFunctionType = event->functionType(true); + if (!event->isAnonymous() && keccak256(eventFunctionType->externalSignature()) == hash) + { + AnnotatedEventSignature eventInfo; + eventInfo.signature = eventFunctionType->externalSignature(); + for (auto const& param: event->parameters()) + if (param->isIndexed()) + eventInfo.indexedTypes.emplace_back(param->type()->toString(true)); + else + eventInfo.nonIndexedTypes.emplace_back(param->type()->toString(true)); + result = eventInfo; + } + } + } + return result; } TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index 97fdb2de6..b8093db22 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -30,6 +30,13 @@ namespace solidity::frontend::test { +struct AnnotatedEventSignature +{ + std::string signature; + std::vector indexedTypes; + std::vector nonIndexedTypes; +}; + /** * Class that represents a semantic test (or end-to-end test) and allows running it as part of the * boost unit test environment or isoltest. It reads the Solidity source and an additional comment @@ -82,6 +89,9 @@ private: bool checkGasCostExpectation(TestFunctionCall& io_test, bool _compileViaYul) const; std::map makeBuiltins(); std::vector makeSideEffectHooks() const; + std::vector eventSideEffectHook(FunctionCall const&) const; + std::optional matchEvent(util::h256 const& hash) const; + static std::string formatEventParameter(std::optional _signature, bool _indexed, size_t _index, bytes const& _data); SourceMap m_sources; std::size_t m_lineOffset; std::vector m_tests; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 032949cfa..e724f9998 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1416,686 +1416,6 @@ BOOST_AUTO_TEST_CASE(default_fallback_throws) } } -BOOST_AUTO_TEST_CASE(event) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address indexed _from, bytes32 indexed _id, uint _value); - function deposit(bytes32 _id, bool _manually) public payable { - if (_manually) { - bytes32 s = 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f; - uint value = msg.value; - address sender = msg.sender; - assembly { - mstore(0, value) - log3(0, 0x20, s, sender, _id) - } - } else { - emit Deposit(msg.sender, _id, msg.value); - } - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - for (bool manually: {true, false}) - { - callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)"))); - BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight)); - BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id)); - } - ) -} - -BOOST_AUTO_TEST_CASE(event_emit) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address indexed _from, bytes32 indexed _id, uint _value); - function deposit(bytes32 _id) public payable { - emit Deposit(msg.sender, _id, msg.value); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - callContractFunctionWithValue("deposit(bytes32)", value, id); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)"))); - BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight)); - BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id)); - ) -} - -BOOST_AUTO_TEST_CASE(event_constructor) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address indexed _from, bytes32 indexed _id, uint _value); - constructor() { - emit Deposit(msg.sender, bytes32("abc"), 7); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(7))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256)"))); - BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight)); - BOOST_CHECK_EQUAL(logTopic(0, 2), h256(string{"abc"}, h256::FromBinary, h256::AlignLeft)); - ) -} - - -BOOST_AUTO_TEST_CASE(event_no_arguments) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(); - function deposit() public { - emit Deposit(); - } - } - )"; - - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit) -{ - char const* sourceCode = R"( - contract A { - event x(); - } - contract B is A { - function f() public returns (uint) { - emit A.x(); - return 1; - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - callContractFunction("f()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("x()"))); - ); -} - -BOOST_AUTO_TEST_CASE(events_with_same_name) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(); - event Deposit(address _addr); - event Deposit(address _addr, uint _amount); - event Deposit(address _addr, bool _flag); - function deposit() public returns (uint) { - emit Deposit(); - return 1; - } - function deposit(address _addr) public returns (uint) { - emit Deposit(_addr); - return 2; - } - function deposit(address _addr, uint _amount) public returns (uint) { - emit Deposit(_addr, _amount); - return 3; - } - function deposit(address _addr, bool _flag) public returns (uint) { - emit Deposit(_addr, _flag); - return 4; - } - } - )"; - h160 const c_loggedAddress = m_contractAddress; - - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); - - ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(2))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)"))); - - ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(3))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)"))); - - ABI_CHECK(callContractFunction("deposit(address,bool)", c_loggedAddress, false), encodeArgs(u256(4))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, false)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bool)"))); - ) -} - -BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit) -{ - char const* sourceCode = R"( - contract A { - event Deposit(); - } - - contract B { - event Deposit(address _addr); - } - - contract ClientReceipt is A, B { - event Deposit(address _addr, uint _amount); - function deposit() public returns (uint) { - emit Deposit(); - return 1; - } - function deposit(address _addr) public returns (uint) { - emit Deposit(_addr); - return 1; - } - function deposit(address _addr, uint _amount) public returns (uint) { - emit Deposit(_addr, _amount); - return 1; - } - } - )"; - h160 const c_loggedAddress = m_contractAddress; - - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0).empty()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit()"))); - - ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(c_loggedAddress)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address)"))); - - ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(1))); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,uint256)"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_anonymous) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit() anonymous; - function deposit() public { - emit Deposit(); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 0); - ) -} - -BOOST_AUTO_TEST_CASE(event_anonymous_with_topics) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address indexed _from, bytes32 indexed _id, uint indexed _value, uint indexed _value2, bytes32 data) anonymous; - function deposit(bytes32 _id) public payable { - emit Deposit(msg.sender, _id, msg.value, 2, "abc"); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - callContractFunctionWithValue("deposit(bytes32)", value, id); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs("abc")); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 4); - BOOST_CHECK_EQUAL(logTopic(0, 0), h256(m_sender, h256::AlignRight)); - BOOST_CHECK_EQUAL(logTopic(0, 1), h256(id)); - BOOST_CHECK_EQUAL(logTopic(0, 2), h256(value)); - BOOST_CHECK_EQUAL(logTopic(0, 3), h256(2)); - ) -} - -BOOST_AUTO_TEST_CASE(event_lots_of_data) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(address _from, bytes32 _id, uint _value, bool _flag); - function deposit(bytes32 _id) public payable { - emit Deposit(msg.sender, _id, msg.value, true); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - u256 value(18); - u256 id(0x1234); - callContractFunctionWithValue("deposit(bytes32)", value, id); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(m_sender, id, value, true)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(address,bytes32,uint256,bool)"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_really_lots_of_data) -{ - char const* sourceCode = R"( - contract ClientReceipt { - event Deposit(uint fixeda, bytes dynx, uint fixedb); - function deposit() public { - emit Deposit(10, msg.data, 15); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 4, asString(FixedHash<4>(util::keccak256("deposit()")).asBytes())))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); -} - -BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) -{ - char const* sourceCode = R"( - contract ClientReceipt { - bytes x; - event Deposit(uint fixeda, bytes dynx, uint fixedb); - function deposit() public { - x.push("A"); - x.push("B"); - x.push("C"); - emit Deposit(10, x, 15); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 3, string("ABC")))); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); -} - -BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage) -{ - char const* sourceCode = R"( - contract ClientReceipt { - bytes x; - event Deposit(uint fixeda, bytes dynx, uint fixedb); - function deposit() public { - x = new bytes(31); - x[0] = "A"; - x[1] = "B"; - x[2] = "C"; - x[30] = "Z"; - emit Deposit(10, x, 15); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(10, 0x60, 15, 31, string("ABC") + string(27, 0) + "Z")); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Deposit(uint256,bytes,uint256)"))); -} - -BOOST_AUTO_TEST_CASE(event_struct_memory_v2) -{ - char const* sourceCode = R"( - pragma abicoder v2; - contract C { - struct S { uint a; } - event E(S); - function createEvent(uint x) public { - emit E(S(x)); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(x)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))"))); -} - -BOOST_AUTO_TEST_CASE(event_struct_storage_v2) -{ - char const* sourceCode = R"( - pragma abicoder v2; - contract C { - struct S { uint a; } - event E(S); - S s; - function createEvent(uint x) public { - s.a = x; - emit E(s); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(x)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint256))"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_memory) -{ - char const* sourceCode = R"( - contract C { - event E(uint[]); - function createEvent(uint x) public { - uint[] memory arr = new uint[](3); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2) -{ - char const* sourceCode = R"( - pragma abicoder v2; - contract C { - event E(uint[]); - function createEvent(uint x) public { - uint[] memory arr = new uint[](3); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2) -{ - char const* sourceCode = R"( - pragma abicoder v2; - contract C { - event E(uint[][]); - function createEvent(uint x) public { - uint[][] memory arr = new uint[][](2); - arr[0] = new uint[](2); - arr[1] = new uint[](2); - arr[0][0] = x; - arr[0][1] = x + 1; - arr[1][0] = x + 2; - arr[1][1] = x + 3; - emit E(arr); - } - } - )"; - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])"))); -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_storage) -{ - char const* sourceCode = R"( - contract C { - event E(uint[]); - uint[] arr; - function createEvent(uint x) public { - while (arr.length < 3) - arr.push(); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2) -{ - char const* sourceCode = R"( - pragma abicoder v2; - contract C { - event E(uint[]); - uint[] arr; - function createEvent(uint x) public { - while (arr.length < 3) - arr.push(); - arr[0] = x; - arr[1] = x + 1; - arr[2] = x + 2; - emit E(arr); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[])"))); - ) -} - -BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2) -{ - char const* sourceCode = R"( - pragma abicoder v2; - contract C { - event E(uint[][]); - uint[][] arr; - function createEvent(uint x) public { - arr.push(new uint[](2)); - arr.push(new uint[](2)); - arr[0][0] = x; - arr[0][1] = x + 1; - arr[1][0] = x + 2; - arr[1][1] = x + 3; - emit E(arr); - } - } - )"; - /// TODO enable again after push(..) via yul is implemented for nested arrays. - /// ALSO_VIA_YUL() - compileAndRun(sourceCode); - u256 x(42); - callContractFunction("createEvent(uint256)", x); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 1); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(uint256[][])"))); -} - -BOOST_AUTO_TEST_CASE(event_indexed_string) -{ - char const* sourceCode = R"( - contract C { - string x; - uint[4] y; - event E(string indexed r, uint[4] indexed t); - function deposit() public { - for (uint i = 0; i < 90; i++) - bytes(x).push(0); - for (uint8 i = 0; i < 90; i++) - bytes(x)[i] = bytes1(i); - y[0] = 4; - y[1] = 5; - y[2] = 6; - y[3] = 7; - emit E(x, y); - } - } - )"; - compileAndRun(sourceCode); - callContractFunction("deposit()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - string dynx(90, 0); - std::iota(dynx.begin(), dynx.end(), 0); - BOOST_CHECK(logData(0) == bytes()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 3); - BOOST_CHECK_EQUAL(logTopic(0, 1), util::keccak256(dynx)); - BOOST_CHECK_EQUAL(logTopic(0, 2), util::keccak256( - encodeArgs(u256(4), u256(5), u256(6), u256(7)) - )); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E(string,uint256[4])"))); -} - -BOOST_AUTO_TEST_CASE(event_indexed_function) -{ - char const* sourceCode = R"( - contract C { - event Test(function() external indexed); - function f() public { - emit Test(this.f); - } - } - )"; - - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - - compileAndRun(sourceCode); - callContractFunction("f()"); - BOOST_REQUIRE_EQUAL(numLogs(), 1); - BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); - BOOST_CHECK(logData(0) == bytes()); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 2); - - bytes functionHash = util::keccak256("f()").asBytes(); - bytes address = m_contractAddress.asBytes(); - bytes selector = bytes(functionHash.cbegin(), functionHash.cbegin() + 4); - bytes padding = bytes(8, 0); - bytes functionABI = address + selector + padding; - - BOOST_CHECK_EQUAL(logTopic(0, 1).hex(), util::toHex(functionABI)); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("Test(function)"))); - ) -} - BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) { char const* sourceCode = R"( @@ -5292,37 +4612,6 @@ BOOST_AUTO_TEST_CASE(abi_encodePackedV2_arrayOfStrings) ) } -BOOST_AUTO_TEST_CASE(event_signature_in_library) -{ - // This tests a bug that was present where the "internal signature" - // for structs was also used for events. - char const* sourceCode = R"( - pragma abicoder v2; - library L { - struct S { - uint8 a; - int16 b; - } - event E(S indexed, S); - function f() internal { - S memory s; - emit E(s, s); - } - } - contract C { - constructor() { - L.f(); - } - } - )"; - ALSO_VIA_YUL( - DISABLE_EWASM_TESTRUN() - compileAndRun(sourceCode, 0, "C"); - BOOST_REQUIRE_EQUAL(numLogTopics(0), 2); - BOOST_CHECK_EQUAL(logTopic(0, 0), util::keccak256(string("E((uint8,int16),(uint8,int16))"))); - ) -} - BOOST_AUTO_TEST_CASE(code_access) { char const* sourceCode = R"( diff --git a/test/libsolidity/semanticTests/events/event.sol b/test/libsolidity/semanticTests/events/event.sol new file mode 100644 index 000000000..0143b8835 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event.sol @@ -0,0 +1,23 @@ +contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint _value); + function deposit(bytes32 _id, bool _manually) public payable { + if (_manually) { + bytes32 s = 0x19dacbf83c5de6658e14cbf7bcae5c15eca2eedecf1c66fbca928e4d351bea0f; + uint value = msg.value; + address sender = msg.sender; + assembly { + mstore(0, value) + log3(0, 0x20, s, sender, _id) + } + } else { + emit Deposit(msg.sender, _id, msg.value); + } + } +} +// ==== +// compileViaYul: also +// ---- +// deposit(bytes32,bool), 18 wei: 0x1234, true -> +// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #0x1234, 0x12 +// deposit(bytes32,bool), 18 wei: 0x1234, false -> +// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #0x1234, 0x12 diff --git a/test/libsolidity/semanticTests/events/event_access_through_base_name_emit.sol b/test/libsolidity/semanticTests/events/event_access_through_base_name_emit.sol new file mode 100644 index 000000000..2e55940de --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_access_through_base_name_emit.sol @@ -0,0 +1,14 @@ +contract A { + event x(); +} +contract B is A { + function f() public returns (uint) { + emit A.x(); + return 1; + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 1 +// ~ emit x() diff --git a/test/libsolidity/semanticTests/events/event_anonymous.sol b/test/libsolidity/semanticTests/events/event_anonymous.sol new file mode 100644 index 000000000..e890fc1cb --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_anonymous.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit() anonymous; + function deposit() public { + emit Deposit(); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> +// ~ emit diff --git a/test/libsolidity/semanticTests/events/event_anonymous_with_signature_collision.sol b/test/libsolidity/semanticTests/events/event_anonymous_with_signature_collision.sol new file mode 100644 index 000000000..96b06cc12 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_anonymous_with_signature_collision.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit(uint256 indexed _from, bytes32 indexed _id, uint _value) anonymous; + function deposit(bytes32 _id) public payable { + emit Deposit(0x2012159ca6b6372f102c535a4814d13a00bfc5568ddfd72151364061b00355d1, _id, msg.value); // 0x2012159c -> 'Deposit(uint256,bytes32,uint256)' + } +} +// ==== +// compileViaYul: also +// ---- +// deposit(bytes32), 18 wei: 0x1234 -> +// ~ emit : #0x2012159ca6b6372f102c535a4814d13a00bfc5568ddfd72151364061b00355d1, #0x1234, 0x12 diff --git a/test/libsolidity/semanticTests/events/event_anonymous_with_signature_collision2.sol b/test/libsolidity/semanticTests/events/event_anonymous_with_signature_collision2.sol new file mode 100644 index 000000000..1ddaa8d7b --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_anonymous_with_signature_collision2.sol @@ -0,0 +1,12 @@ +contract ClientReceipt { + event Withdraw(uint _value, string owner); + event Deposit(uint256 indexed _from, bytes32 indexed _id, uint _value) anonymous; + function deposit(bytes32 _id) public payable { + emit Deposit(0x5ddaa77ac5bda319ba947e31bee594711f39ed1b20d079d438dbad5ed729fb30, _id, msg.value); // 0x5ddaa77a -> 'Withdraw(uint256,string)' + } +} +// ==== +// compileViaYul: also +// ---- +// deposit(bytes32), 18 wei: 0x1234 -> +// ~ emit Withdraw(uint256,string): #0x1234, 0x12 diff --git a/test/libsolidity/semanticTests/events/event_anonymous_with_topics.sol b/test/libsolidity/semanticTests/events/event_anonymous_with_topics.sol new file mode 100644 index 000000000..0bbe9f09b --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_anonymous_with_topics.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint indexed _value, uint indexed _value2, bytes32 data) anonymous; + function deposit(bytes32 _id) public payable { + emit Deposit(msg.sender, _id, msg.value, 2, "abc"); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit(bytes32), 18 wei: 0x1234 -> +// ~ emit : #0x1212121212121212121212121212120000000012, #0x1234, #0x12, #0x02, "abc" diff --git a/test/libsolidity/semanticTests/events/event_constructor.sol b/test/libsolidity/semanticTests/events/event_constructor.sol new file mode 100644 index 000000000..f5fa4e119 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_constructor.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint _value); + constructor() { + emit Deposit(msg.sender, bytes32("abc"), 7); + } +} +// ==== +// compileViaYul: also +// ---- +// constructor() +// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #"abc", 0x07 diff --git a/test/libsolidity/semanticTests/events/event_dynamic_array_memory.sol b/test/libsolidity/semanticTests/events/event_dynamic_array_memory.sol new file mode 100644 index 000000000..943d3b1ac --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_dynamic_array_memory.sol @@ -0,0 +1,15 @@ +contract C { + event E(uint[]); + function createEvent(uint x) public { + uint[] memory arr = new uint[](3); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c diff --git a/test/libsolidity/semanticTests/events/event_dynamic_array_memory_v2.sol b/test/libsolidity/semanticTests/events/event_dynamic_array_memory_v2.sol new file mode 100644 index 000000000..c7b564d38 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_dynamic_array_memory_v2.sol @@ -0,0 +1,16 @@ +pragma abicoder v2; +contract C { + event E(uint[]); + function createEvent(uint x) public { + uint[] memory arr = new uint[](3); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c diff --git a/test/libsolidity/semanticTests/events/event_dynamic_array_storage.sol b/test/libsolidity/semanticTests/events/event_dynamic_array_storage.sol new file mode 100644 index 000000000..43ad75580 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_dynamic_array_storage.sol @@ -0,0 +1,20 @@ +contract C { + event E(uint[]); + uint[] arr; + function createEvent(uint x) public { + while (arr.length < 3) + arr.push(); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c +// gas irOptimized: 115211 +// gas legacy: 116393 +// gas legacyOptimized: 114415 diff --git a/test/libsolidity/semanticTests/events/event_dynamic_array_storage_v2.sol b/test/libsolidity/semanticTests/events/event_dynamic_array_storage_v2.sol new file mode 100644 index 000000000..5c48bcb02 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_dynamic_array_storage_v2.sol @@ -0,0 +1,21 @@ +pragma abicoder v2; +contract C { + event E(uint[]); + uint[] arr; + function createEvent(uint x) public { + while (arr.length < 3) + arr.push(); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E(uint256[]): 0x20, 0x03, 0x2a, 0x2b, 0x2c +// gas irOptimized: 115211 +// gas legacy: 116393 +// gas legacyOptimized: 114415 diff --git a/test/libsolidity/semanticTests/events/event_dynamic_nested_array_memory_v2.sol b/test/libsolidity/semanticTests/events/event_dynamic_nested_array_memory_v2.sol new file mode 100644 index 000000000..13698e200 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_dynamic_nested_array_memory_v2.sol @@ -0,0 +1,19 @@ +pragma abicoder v2; +contract C { + event E(uint[][]); + function createEvent(uint x) public { + uint[][] memory arr = new uint[][](2); + arr[0] = new uint[](2); + arr[1] = new uint[](2); + arr[0][0] = x; + arr[0][1] = x + 1; + arr[1][0] = x + 2; + arr[1][1] = x + 3; + emit E(arr); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E(uint256[][]): 0x20, 0x02, 0x40, 0xa0, 0x02, 0x2a, 0x2b, 0x02, 0x2c, 0x2d diff --git a/test/libsolidity/semanticTests/events/event_dynamic_nested_array_storage_v2.sol b/test/libsolidity/semanticTests/events/event_dynamic_nested_array_storage_v2.sol new file mode 100644 index 000000000..409136b3d --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_dynamic_nested_array_storage_v2.sol @@ -0,0 +1,22 @@ +pragma abicoder v2; +contract C { + event E(uint[][]); + uint[][] arr; + function createEvent(uint x) public { + arr.push(new uint[](2)); + arr.push(new uint[](2)); + arr[0][0] = x; + arr[0][1] = x + 1; + arr[1][0] = x + 2; + arr[1][1] = x + 3; + emit E(arr); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E(uint256[][]): 0x20, 0x02, 0x40, 0xa0, 0x02, 0x2a, 0x2b, 0x02, 0x2c, 0x2d +// gas irOptimized: 185905 +// gas legacy: 187621 +// gas legacyOptimized: 184551 diff --git a/test/libsolidity/semanticTests/events/event_emit.sol b/test/libsolidity/semanticTests/events/event_emit.sol new file mode 100644 index 000000000..70cd70589 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_emit.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit(address indexed _from, bytes32 indexed _id, uint _value); + function deposit(bytes32 _id) public payable { + emit Deposit(msg.sender, _id, msg.value); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit(bytes32), 18 wei: 0x1234 -> +// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #0x1234, 0x12 diff --git a/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol new file mode 100644 index 000000000..128cf00ea --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_emit_from_other_contract.sol @@ -0,0 +1,22 @@ +contract D { + event Deposit(address indexed _from, bytes32 indexed _id, uint _value); + function deposit(bytes32 _id) public payable { + emit Deposit(msg.sender, _id, msg.value); + } +} +contract C { + D d; + constructor() { + d = new D(); + } + function deposit(bytes32 _id) public payable { + d.deposit(_id); + } +} +// ==== +// compileViaYul: also +// ---- +// constructor() -> +// gas legacy: 249112 +// deposit(bytes32), 18 wei: 0x1234 -> +// ~ emit Deposit(address,bytes32,uint256) from 0xf01f7809444bd9a93a854361c6fae3f23d9e23db: #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b, #0x1234, 0x00 diff --git a/test/libsolidity/semanticTests/events/event_indexed_function.sol b/test/libsolidity/semanticTests/events/event_indexed_function.sol new file mode 100644 index 000000000..400d6d93f --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_indexed_function.sol @@ -0,0 +1,11 @@ +contract C { + event Test(function() external indexed); + function f() public { + emit Test(this.f); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> +// ~ emit Test(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b26121ff00000000000000000 diff --git a/test/libsolidity/semanticTests/events/event_indexed_function2.sol b/test/libsolidity/semanticTests/events/event_indexed_function2.sol new file mode 100644 index 000000000..508744ca1 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_indexed_function2.sol @@ -0,0 +1,17 @@ +contract C { + event TestA(function() external indexed); + event TestB(function(uint256) external indexed); + function f1() public { + emit TestA(this.f1); + } + function f2(uint256 a) public { + emit TestB(this.f2); + } +} +// ==== +// compileViaYul: also +// ---- +// f1() -> +// ~ emit TestA(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87bc27fc3050000000000000000 +// f2(uint256): 1 -> +// ~ emit TestB(function): #0x0fdd67305928fcac8d213d1e47bfa6165cd0b87bbf3724af0000000000000000 diff --git a/test/libsolidity/semanticTests/events/event_indexed_string.sol b/test/libsolidity/semanticTests/events/event_indexed_string.sol new file mode 100644 index 000000000..be275081b --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_indexed_string.sol @@ -0,0 +1,24 @@ +contract C { + string x; + uint[4] y; + event E(string indexed r, uint[4] indexed t); + function deposit() public { + for (uint i = 0; i < 90; i++) + bytes(x).push(0); + for (uint8 i = 0; i < 90; i++) + bytes(x)[i] = bytes1(i); + y[0] = 4; + y[1] = 5; + y[2] = 6; + y[3] = 7; + emit E(x, y); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> +// ~ emit E(string,uint256[4]): #0xa7fb06bb999a5eb9aff9e0779953f4e1e4ce58044936c2f51c7fb879b85c08bd, #0xe755d8cc1a8cde16a2a31160dcd8017ac32d7e2f13215b29a23cdae40a78aa81 +// gas irOptimized: 368478 +// gas legacy: 390742 +// gas legacyOptimized: 376774 diff --git a/test/libsolidity/semanticTests/events/event_lots_of_data.sol b/test/libsolidity/semanticTests/events/event_lots_of_data.sol new file mode 100644 index 000000000..c38537f5a --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_lots_of_data.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit(address _from, bytes32 _id, uint _value, bool _flag); + function deposit(bytes32 _id) public payable { + emit Deposit(msg.sender, _id, msg.value, true); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit(bytes32), 18 wei: 0x1234 -> +// ~ emit Deposit(address,bytes32,uint256,bool): 0x1212121212121212121212121212120000000012, 0x1234, 0x12, true diff --git a/test/libsolidity/semanticTests/events/event_no_arguments.sol b/test/libsolidity/semanticTests/events/event_no_arguments.sol new file mode 100644 index 000000000..ba4048107 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_no_arguments.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit(); + function deposit() public { + emit Deposit(); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> +// ~ emit Deposit() diff --git a/test/libsolidity/semanticTests/events/event_really_lots_of_data.sol b/test/libsolidity/semanticTests/events/event_really_lots_of_data.sol new file mode 100644 index 000000000..7322e56d3 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_really_lots_of_data.sol @@ -0,0 +1,11 @@ +contract ClientReceipt { + event Deposit(uint fixeda, bytes dynx, uint fixedb); + function deposit() public { + emit Deposit(10, msg.data, 15); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> +// ~ emit Deposit(uint256,bytes,uint256): 0x0a, 0x60, 0x0f, 0x04, 0xd0e30db000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/events/event_really_lots_of_data_from_storage.sol b/test/libsolidity/semanticTests/events/event_really_lots_of_data_from_storage.sol new file mode 100644 index 000000000..da8e7799d --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_really_lots_of_data_from_storage.sol @@ -0,0 +1,15 @@ +contract ClientReceipt { + bytes x; + event Deposit(uint fixeda, bytes dynx, uint fixedb); + function deposit() public { + x.push("A"); + x.push("B"); + x.push("C"); + emit Deposit(10, x, 15); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> +// ~ emit Deposit(uint256,bytes,uint256): 0x0a, 0x60, 0x0f, 0x03, "ABC" diff --git a/test/libsolidity/semanticTests/events/event_really_really_lots_of_data_from_storage.sol b/test/libsolidity/semanticTests/events/event_really_really_lots_of_data_from_storage.sol new file mode 100644 index 000000000..f944163eb --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_really_really_lots_of_data_from_storage.sol @@ -0,0 +1,17 @@ +contract ClientReceipt { + bytes x; + event Deposit(uint fixeda, bytes dynx, uint fixedb); + function deposit() public { + x = new bytes(31); + x[0] = "A"; + x[1] = "B"; + x[2] = "C"; + x[30] = "Z"; + emit Deposit(10, x, 15); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> +// ~ emit Deposit(uint256,bytes,uint256): 0x0a, 0x60, 0x0f, 0x1f, "ABC\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Z" diff --git a/test/libsolidity/semanticTests/events/event_signature_in_library.sol b/test/libsolidity/semanticTests/events/event_signature_in_library.sol new file mode 100644 index 000000000..e43fc4c64 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_signature_in_library.sol @@ -0,0 +1,23 @@ +pragma abicoder v2; +library L { + struct S { + uint8 a; + int16 b; + } + event E(S indexed, S); + function f() internal { + S memory s; + emit E(s, s); + } +} +contract C { + constructor() { + L.f(); + } +} +// ==== +// compileViaYul: also +// ---- +// constructor() +// ~ emit E((uint8,int16),(uint8,int16)): #0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5, 0x00, 0x00 +// gas legacy: 150662 diff --git a/test/libsolidity/semanticTests/events/event_string.sol b/test/libsolidity/semanticTests/events/event_string.sol new file mode 100644 index 000000000..e383ef934 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_string.sol @@ -0,0 +1,11 @@ +contract C { + event E(string r); + function deposit() public { + emit E("HELLO WORLD"); + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> +// ~ emit E(string): 0x20, 0x0b, "HELLO WORLD" diff --git a/test/libsolidity/semanticTests/events/event_struct_memory_v2.sol b/test/libsolidity/semanticTests/events/event_struct_memory_v2.sol new file mode 100644 index 000000000..a08b4f574 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_struct_memory_v2.sol @@ -0,0 +1,13 @@ +pragma abicoder v2; +contract C { + struct S { uint a; } + event E(S); + function createEvent(uint x) public { + emit E(S(x)); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E((uint256)): 0x2a diff --git a/test/libsolidity/semanticTests/events/event_struct_storage_v2.sol b/test/libsolidity/semanticTests/events/event_struct_storage_v2.sol new file mode 100644 index 000000000..ae91efc3e --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_struct_storage_v2.sol @@ -0,0 +1,15 @@ +pragma abicoder v2; +contract C { + struct S { uint a; } + event E(S); + S s; + function createEvent(uint x) public { + s.a = x; + emit E(s); + } +} +// ==== +// compileViaYul: also +// ---- +// createEvent(uint256): 42 -> +// ~ emit E((uint256)): 0x2a diff --git a/test/libsolidity/semanticTests/events/events_with_same_name.sol b/test/libsolidity/semanticTests/events/events_with_same_name.sol new file mode 100644 index 000000000..5eef0deb9 --- /dev/null +++ b/test/libsolidity/semanticTests/events/events_with_same_name.sol @@ -0,0 +1,33 @@ +contract ClientReceipt { + event Deposit(); + event Deposit(address _addr); + event Deposit(address _addr, uint _amount); + event Deposit(address _addr, bool _flag); + function deposit() public returns (uint) { + emit Deposit(); + return 1; + } + function deposit(address _addr) public returns (uint) { + emit Deposit(_addr); + return 2; + } + function deposit(address _addr, uint _amount) public returns (uint) { + emit Deposit(_addr, _amount); + return 3; + } + function deposit(address _addr, bool _flag) public returns (uint) { + emit Deposit(_addr, _flag); + return 4; + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> 1 +// ~ emit Deposit() +// deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988 -> 2 +// ~ emit Deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988 +// deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 100 -> 3 +// ~ emit Deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 0x64 +// deposit(address,bool): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, false -> 4 +// ~ emit Deposit(address,bool): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, false diff --git a/test/libsolidity/semanticTests/events/events_with_same_name_inherited_emit.sol b/test/libsolidity/semanticTests/events/events_with_same_name_inherited_emit.sol new file mode 100644 index 000000000..472502504 --- /dev/null +++ b/test/libsolidity/semanticTests/events/events_with_same_name_inherited_emit.sol @@ -0,0 +1,32 @@ +contract A { + event Deposit(); +} + +contract B { + event Deposit(address _addr); +} + +contract ClientReceipt is A, B { + event Deposit(address _addr, uint _amount); + function deposit() public returns (uint) { + emit Deposit(); + return 1; + } + function deposit(address _addr) public returns (uint) { + emit Deposit(_addr); + return 1; + } + function deposit(address _addr, uint _amount) public returns (uint) { + emit Deposit(_addr, _amount); + return 1; + } +} +// ==== +// compileViaYul: also +// ---- +// deposit() -> 1 +// ~ emit Deposit() +// deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988 -> 1 +// ~ emit Deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988 +// deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 100 -> 1 +// ~ emit Deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 0x64 diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index c8d22c944..dc356f003 100644 --- a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol +++ b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol @@ -197,12 +197,14 @@ contract DepositContract is IDepositContract, ERC165 { // gas legacyOptimized: 122798 // get_deposit_count() -> 0x20, 8, 0 // deposit(bytes,bytes,bytes,bytes32), 1 ether: 0x80, 0xe0, 0x120, 0xaa4a8d0b7d9077248630f1a4701ae9764e42271d7f22b7838778411857fd349e, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0x00f50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8 -> # txhash: 0x7085c586686d666e8bb6e9477a0f0b09565b2060a11f1c4209d3a52295033832 # +// ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f73292, 0x67a8811c397529dac52ae1342ba58c9500000000000000000000000000000000, 0x20, 0xf50428677c60f997aadeab24aabf7fceaef491c96a52b463ae91f95611cf71, 0x08, 0xca9a3b00000000000000000000000000000000000000000000000000000000, 0x60, 0xa29d01cc8c6296a8150e515b5995390ef841dc18948aa3e79be6d7c1851b4cbb, 0x5d6ff49fa70b9c782399506a22a85193151b9b691245cebafd2063012443c132, 0x4b6c36debaedefb7b2d71b0503ffdc00150aaffd42e63358238ec888901738b8, 0x08, 0x00 // get_deposit_root() -> 0x2089653123d9c721215120b6db6738ba273bbc5228ac093b1f983badcdc8a438 // gas irOptimized: 127486 // gas legacy: 150475 // gas legacyOptimized: 122811 // get_deposit_count() -> 0x20, 8, 0x0100000000000000000000000000000000000000000000000000000000000000 // deposit(bytes,bytes,bytes,bytes32), 32 ether: 0x80, 0xe0, 0x120, 0xdbd986dc85ceb382708cf90a3500f500f0a393c5ece76963ac3ed72eccd2c301, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x00344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d -> # txhash: 0x404d8e109822ce448e68f45216c12cb051b784d068fbe98317ab8e50c58304ac # +// ~ emit DepositEvent(bytes,bytes,bytes,bytes,bytes): 0xa0, 0x0100, 0x0140, 0x0180, 0x0200, 0x30, 0xb2ce0f79f90e7b3a113ca5783c65756f96c4b4673c2b5c1eb4efc22280259441, 0x06d601211e8866dc5b50dc48a244dd7c00000000000000000000000000000000, 0x20, 0x344b6c73f71b11c56aba0d01b7d8ad83559f209d0a4101a515f6ad54c89771, 0x08, 0x40597307000000000000000000000000000000000000000000000000000000, 0x60, 0x945caaf82d18e78c033927d51f452ebcd76524497b91d7a11219cb3db6a1d369, 0x7595fc095ce489e46b2ef129591f2f6d079be4faaf345a02c5eb133c072e7c56, 0x0c6c3617eee66b4b878165c502357d49485326bc6b31bc96873f308c8f19c09d, 0x08, 0x0100000000000000000000000000000000000000000000000000000000000000 // get_deposit_root() -> 0x40255975859377d912c53aa853245ebd939bdd2b33a28e084babdcc1ed8238ee // gas irOptimized: 127486 // gas legacy: 150475 diff --git a/test/libsolidity/semanticTests/externalContracts/snark.sol b/test/libsolidity/semanticTests/externalContracts/snark.sol index 10c129b20..94e3e781c 100644 --- a/test/libsolidity/semanticTests/externalContracts/snark.sol +++ b/test/libsolidity/semanticTests/externalContracts/snark.sol @@ -277,7 +277,7 @@ contract Test { input[7] = 9643208548031422463313148630985736896287522941726746581856185889848792022807; input[8] = 18066496933330839731877828156604; if (verify(input, proof) == 0) { - emit Verified("Transaction successfully verified."); + emit Verified("Successfully verified."); return true; } else { return false; @@ -296,6 +296,7 @@ contract Test { // g() -> true // pair() -> true // verifyTx() -> true -// gas irOptimized: 111716 -// gas legacy: 114371 -// gas legacyOptimized: 83947 +// ~ emit Verified(string): 0x20, 0x16, "Successfully verified." +// gas irOptimized: 111439 +// gas legacy: 114094 +// gas legacyOptimized: 83670 diff --git a/test/libsolidity/semanticTests/structs/event.sol b/test/libsolidity/semanticTests/structs/event.sol index 191f4f892..36df8787f 100644 --- a/test/libsolidity/semanticTests/structs/event.sol +++ b/test/libsolidity/semanticTests/structs/event.sol @@ -15,3 +15,4 @@ contract C { // ---- // library: L // f() -> +// ~ emit Ev((uint256)): 0x01 diff --git a/test/libsolidity/semanticTests/viaYul/erc20.sol b/test/libsolidity/semanticTests/viaYul/erc20.sol index d9493d8e8..3ceda24a1 100644 --- a/test/libsolidity/semanticTests/viaYul/erc20.sol +++ b/test/libsolidity/semanticTests/viaYul/erc20.sol @@ -98,7 +98,10 @@ contract ERC20 { // ---- // totalSupply() -> 20 // transfer(address,uint256): 2, 5 -> true +// ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x05 // decreaseAllowance(address,uint256): 2, 0 -> true +// ~ emit Approval(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x00 // decreaseAllowance(address,uint256): 2, 1 -> FAILURE, hex"4e487b71", 0x11 // transfer(address,uint256): 2, 14 -> true +// ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x0e // transfer(address,uint256): 2, 2 -> FAILURE, hex"4e487b71", 0x11 diff --git a/test/libsolidity/util/SoltestTypes.h b/test/libsolidity/util/SoltestTypes.h index f945a367f..f1b284135 100644 --- a/test/libsolidity/util/SoltestTypes.h +++ b/test/libsolidity/util/SoltestTypes.h @@ -19,6 +19,8 @@ #include +#include + namespace solidity::frontend::test { @@ -311,4 +313,24 @@ struct FunctionCall using Builtin = std::function(FunctionCall const&)>; using SideEffectHook = std::function(FunctionCall const&)>; +struct LogRecord +{ + util::h160 creator; + bytes data; + std::vector topics; + + LogRecord(util::h160 _creator, bytes _data, std::vector _topics): + creator(std::move(_creator)), data(std::move(_data)), topics(std::move(_topics)) {} + + bool operator==(LogRecord const& other) const noexcept + { + return creator == other.creator && data == other.data && topics == other.topics; + } + + bool operator!=(LogRecord const& other) const noexcept + { + return !operator==(other); + } +}; + } diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index ad543b06b..65a7bd69d 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -196,8 +196,6 @@ string TestFunctionCall::format( } } - stream << formatGasExpectations(_linePrefix, _renderMode == RenderMode::ExpectedValuesActualGas, _interactivePrint); - vector sideEffects; if (_renderMode == RenderMode::ExpectedValuesExpectedGas || _renderMode == RenderMode::ExpectedValuesActualGas) sideEffects = m_call.expectedSideEffects; @@ -214,6 +212,8 @@ string TestFunctionCall::format( stream << std::endl; } } + + stream << formatGasExpectations(_linePrefix, _renderMode == RenderMode::ExpectedValuesActualGas, _interactivePrint); }; formatOutput(m_call.displayMode == FunctionCall::DisplayMode::SingleLine);