From 334c023c7231810f28ca5ea04f14df3f722cea07 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 15 Jun 2018 12:18:00 +0200 Subject: Determine transaction status in RPC sessions. --- Changelog.md | 1 + test/ExecutionFramework.cpp | 5 +++++ test/ExecutionFramework.h | 2 ++ test/RPCSession.cpp | 8 ++++++++ test/RPCSession.h | 3 +++ test/contracts/AuctionRegistrar.cpp | 1 + test/contracts/FixedFeeRegistrar.cpp | 1 + test/contracts/LLL_ENS.cpp | 1 + test/contracts/LLL_ERC20.cpp | 5 +++++ test/contracts/Wallet.cpp | 1 + test/liblll/EndToEndTest.cpp | 3 +++ test/libsolidity/GasMeter.cpp | 1 + test/libsolidity/SolidityEndToEndTest.cpp | 26 +++++++++++++++++++++++++- 13 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index b1f742bf..8c5c523e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -38,6 +38,7 @@ Language Features: Compiler Features: * Type Checker: Show named argument in case of error. + * Tests: Determine transaction status during IPC calls. Bugfixes: * Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum. diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index a24f78fb..00f5e697 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -142,6 +142,11 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 entry.data = fromHex(log.data, WhenError::Throw); m_logs.push_back(entry); } + + if (!receipt.status.empty()) + m_transactionSuccessful = (receipt.status == "1"); + else + m_transactionSuccessful = (m_gas != m_gasUsed); } void ExecutionFramework::sendEther(Address const& _to, u256 const& _value) diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index 4525cbf9..cdbec81d 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -72,6 +72,7 @@ public: ) { compileAndRunWithoutCheck(_sourceCode, _value, _contractName, _arguments, _libraryAddresses); + BOOST_REQUIRE(m_transactionSuccessful); BOOST_REQUIRE(!m_output.empty()); return m_output; } @@ -234,6 +235,7 @@ protected: unsigned m_optimizeRuns = 200; bool m_optimize = false; bool m_showMessages = false; + bool m_transactionSuccessful = true; Address m_sender; Address m_contractAddress; u256 m_blockNumber; diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp index 160b0047..9a253794 100644 --- a/test/RPCSession.cpp +++ b/test/RPCSession.cpp @@ -163,6 +163,11 @@ RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string cons receipt.gasUsed = result["gasUsed"].asString(); receipt.contractAddress = result["contractAddress"].asString(); receipt.blockNumber = result["blockNumber"].asString(); + if (m_receiptHasStatusField) + { + BOOST_REQUIRE(!result["status"].isNull()); + receipt.status = result["status"].asString(); + } for (auto const& log: result["logs"]) { LogEntry entry; @@ -225,7 +230,10 @@ void RPCSession::test_setChainParams(vector const& _accounts) if (test::Options::get().evmVersion() >= solidity::EVMVersion::spuriousDragon()) forks += "\"EIP158ForkBlock\": \"0x00\",\n"; if (test::Options::get().evmVersion() >= solidity::EVMVersion::byzantium()) + { forks += "\"byzantiumForkBlock\": \"0x00\",\n"; + m_receiptHasStatusField = true; + } if (test::Options::get().evmVersion() >= solidity::EVMVersion::constantinople()) forks += "\"constantinopleForkBlock\": \"0x00\",\n"; static string const c_configString = R"( diff --git a/test/RPCSession.h b/test/RPCSession.h index 63f1dd21..5af2e26a 100644 --- a/test/RPCSession.h +++ b/test/RPCSession.h @@ -99,6 +99,8 @@ public: std::string contractAddress; std::vector logEntries; std::string blockNumber; + /// note: pre-byzantium the status field will be empty + std::string status; }; static RPCSession& instance(std::string const& _path); @@ -136,6 +138,7 @@ private: unsigned m_maxMiningTime = 6000000; // 600 seconds unsigned m_sleepTime = 10; // 10 milliseconds unsigned m_successfulMineRuns = 0; + bool m_receiptHasStatusField = false; std::vector m_accounts; }; diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp index f5abb83d..0b888b90 100644 --- a/test/contracts/AuctionRegistrar.cpp +++ b/test/contracts/AuctionRegistrar.cpp @@ -223,6 +223,7 @@ protected: s_compiledRegistrar.reset(new bytes(compileContract(registrarCode, "GlobalRegistrar"))); sendMessage(*s_compiledRegistrar, true); + BOOST_REQUIRE(m_transactionSuccessful); BOOST_REQUIRE(!m_output.empty()); } diff --git a/test/contracts/FixedFeeRegistrar.cpp b/test/contracts/FixedFeeRegistrar.cpp index 142f4144..630d2ab9 100644 --- a/test/contracts/FixedFeeRegistrar.cpp +++ b/test/contracts/FixedFeeRegistrar.cpp @@ -135,6 +135,7 @@ protected: s_compiledRegistrar.reset(new bytes(compileContract(registrarCode, "FixedFeeRegistrar"))); sendMessage(*s_compiledRegistrar, true); + BOOST_REQUIRE(m_transactionSuccessful); BOOST_REQUIRE(!m_output.empty()); } u256 const m_fee = u256("69000000000000000000"); diff --git a/test/contracts/LLL_ENS.cpp b/test/contracts/LLL_ENS.cpp index 028d58c8..3461c577 100644 --- a/test/contracts/LLL_ENS.cpp +++ b/test/contracts/LLL_ENS.cpp @@ -349,6 +349,7 @@ protected: BOOST_REQUIRE(errors.empty()); } sendMessage(*s_compiledEns, true); + BOOST_REQUIRE(m_transactionSuccessful); BOOST_REQUIRE(!m_output.empty()); } diff --git a/test/contracts/LLL_ERC20.cpp b/test/contracts/LLL_ERC20.cpp index 60b43e4f..89d1c4f0 100644 --- a/test/contracts/LLL_ERC20.cpp +++ b/test/contracts/LLL_ERC20.cpp @@ -400,6 +400,7 @@ protected: BOOST_REQUIRE(errors.empty()); } sendMessage(*s_compiledErc20, true); + BOOST_REQUIRE(m_transactionSuccessful); BOOST_REQUIRE(!m_output.empty()); } @@ -629,18 +630,22 @@ BOOST_AUTO_TEST_CASE(bad_data) // Correct data: transfer(address _to, 1). sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a123456789a") + encodeArgs(1), false, 0); + BOOST_CHECK(m_transactionSuccessful); BOOST_CHECK(m_output == SUCCESS); // Too little data (address is truncated by one byte). sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a12345678") + encodeArgs(1), false, 0); + BOOST_CHECK(!m_transactionSuccessful); BOOST_CHECK(m_output != SUCCESS); // Too much data (address is extended with a zero byte). sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a123456789a00") + encodeArgs(1), false, 0); + BOOST_CHECK(!m_transactionSuccessful); BOOST_CHECK(m_output != SUCCESS); // Invalid address (a bit above the 160th is set). sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000100123456789a123456789a123456789a123456789a") + encodeArgs(1), false, 0); + BOOST_CHECK(!m_transactionSuccessful); BOOST_CHECK(m_output != SUCCESS); } diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp index 6328b518..470551df 100644 --- a/test/contracts/Wallet.cpp +++ b/test/contracts/Wallet.cpp @@ -451,6 +451,7 @@ protected: bytes args = encodeArgs(u256(0x60), _required, _dailyLimit, u256(_owners.size()), _owners); sendMessage(*s_compiledWallet + args, true, _value); + BOOST_REQUIRE(m_transactionSuccessful); BOOST_REQUIRE(!m_output.empty()); } }; diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp index fd8099f2..ceaf450e 100644 --- a/test/liblll/EndToEndTest.cpp +++ b/test/liblll/EndToEndTest.cpp @@ -50,6 +50,7 @@ BOOST_AUTO_TEST_CASE(bare_panic) { char const* sourceCode = "(panic)"; compileAndRunWithoutCheck(sourceCode); + BOOST_REQUIRE(!m_transactionSuccessful); BOOST_REQUIRE(m_output.empty()); } @@ -57,6 +58,7 @@ BOOST_AUTO_TEST_CASE(panic) { char const* sourceCode = "{ (panic) }"; compileAndRunWithoutCheck(sourceCode); + BOOST_REQUIRE(!m_transactionSuccessful); BOOST_REQUIRE(m_output.empty()); } @@ -69,6 +71,7 @@ BOOST_AUTO_TEST_CASE(macro_zeroarg) (zeroarg))) )"; compileAndRun(sourceCode); + BOOST_CHECK(m_transactionSuccessful); BOOST_CHECK(callFallback() == encodeArgs(u256(0x1234))); } diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp index 42965582..d8954f83 100644 --- a/test/libsolidity/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -87,6 +87,7 @@ public: for (bytes const& arguments: _argumentVariants) { sendMessage(hash.asBytes() + arguments, false, 0); + BOOST_CHECK(m_transactionSuccessful); gasUsed = max(gasUsed, m_gasUsed); gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false)); } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 7ea6cf98..ea90a5be 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -49,6 +49,25 @@ namespace test BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityExecutionFramework) +BOOST_AUTO_TEST_CASE(transaction_status) +{ + char const* sourceCode = R"( + contract test { + function f() { } + function g() { revert(); } + function h() { assert(false); } + } + )"; + compileAndRun(sourceCode); + callContractFunction("f()"); + BOOST_CHECK(m_transactionSuccessful); + callContractFunction("g()"); + BOOST_CHECK(!m_transactionSuccessful); + callContractFunction("h()"); + BOOST_CHECK(!m_transactionSuccessful); +} + + BOOST_AUTO_TEST_CASE(smoke_test) { char const* sourceCode = R"( @@ -3106,9 +3125,11 @@ BOOST_AUTO_TEST_CASE(short_data_calls_fallback) compileAndRun(sourceCode); // should call fallback sendMessage(asBytes("\xd8\x8e\x0b"), false, 0); + BOOST_CHECK(m_transactionSuccessful); ABI_CHECK(callContractFunction("x()"), encodeArgs(2)); // should call function sendMessage(asBytes(string("\xd8\x8e\x0b") + string(1, 0)), false, 0); + BOOST_CHECK(m_transactionSuccessful); ABI_CHECK(callContractFunction("x()"), encodeArgs(3)); } @@ -3793,6 +3814,7 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory) compileAndRun(sourceCode); bytes calldata1 = FixedHash<4>(dev::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12); sendMessage(calldata1, false); + BOOST_CHECK(m_transactionSuccessful); BOOST_CHECK(m_output == encodeArgs(dev::keccak256(bytes{'a', 'b', 'c'} + calldata1))); } @@ -3928,7 +3950,8 @@ BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data) ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true)); BOOST_CHECK(!storageEmpty(m_contractAddress)); sendMessage(bytes(), false); - BOOST_CHECK(m_output == bytes()); + BOOST_CHECK(m_transactionSuccessful); + BOOST_CHECK(m_output.empty()); BOOST_CHECK(storageEmpty(m_contractAddress)); } @@ -6243,6 +6266,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) } )"; ABI_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A"), encodeArgs()); + BOOST_CHECK(!m_transactionSuccessful); } BOOST_AUTO_TEST_CASE(positive_integers_to_signed) -- cgit