Merge pull request #4305 from ethereum/transactionReceipts

Determine transaction status in RPC sessions.
This commit is contained in:
chriseth 2018-07-02 16:09:59 +02:00 committed by GitHub
commit 08aa7e47e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 57 additions and 1 deletions

View File

@ -39,6 +39,7 @@ Language Features:
Compiler Features: Compiler Features:
* Type Checker: Show named argument in case of error. * Type Checker: Show named argument in case of error.
* Tests: Determine transaction status during IPC calls.
Bugfixes: Bugfixes:
* Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum. * Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum.

View File

@ -142,6 +142,11 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
entry.data = fromHex(log.data, WhenError::Throw); entry.data = fromHex(log.data, WhenError::Throw);
m_logs.push_back(entry); 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) void ExecutionFramework::sendEther(Address const& _to, u256 const& _value)

View File

@ -72,6 +72,7 @@ public:
) )
{ {
compileAndRunWithoutCheck(_sourceCode, _value, _contractName, _arguments, _libraryAddresses); compileAndRunWithoutCheck(_sourceCode, _value, _contractName, _arguments, _libraryAddresses);
BOOST_REQUIRE(m_transactionSuccessful);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
return m_output; return m_output;
} }
@ -234,6 +235,7 @@ protected:
unsigned m_optimizeRuns = 200; unsigned m_optimizeRuns = 200;
bool m_optimize = false; bool m_optimize = false;
bool m_showMessages = false; bool m_showMessages = false;
bool m_transactionSuccessful = true;
Address m_sender; Address m_sender;
Address m_contractAddress; Address m_contractAddress;
u256 m_blockNumber; u256 m_blockNumber;

View File

@ -163,6 +163,11 @@ RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string cons
receipt.gasUsed = result["gasUsed"].asString(); receipt.gasUsed = result["gasUsed"].asString();
receipt.contractAddress = result["contractAddress"].asString(); receipt.contractAddress = result["contractAddress"].asString();
receipt.blockNumber = result["blockNumber"].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"]) for (auto const& log: result["logs"])
{ {
LogEntry entry; LogEntry entry;
@ -225,7 +230,10 @@ void RPCSession::test_setChainParams(vector<string> const& _accounts)
if (test::Options::get().evmVersion() >= solidity::EVMVersion::spuriousDragon()) if (test::Options::get().evmVersion() >= solidity::EVMVersion::spuriousDragon())
forks += "\"EIP158ForkBlock\": \"0x00\",\n"; forks += "\"EIP158ForkBlock\": \"0x00\",\n";
if (test::Options::get().evmVersion() >= solidity::EVMVersion::byzantium()) if (test::Options::get().evmVersion() >= solidity::EVMVersion::byzantium())
{
forks += "\"byzantiumForkBlock\": \"0x00\",\n"; forks += "\"byzantiumForkBlock\": \"0x00\",\n";
m_receiptHasStatusField = true;
}
if (test::Options::get().evmVersion() >= solidity::EVMVersion::constantinople()) if (test::Options::get().evmVersion() >= solidity::EVMVersion::constantinople())
forks += "\"constantinopleForkBlock\": \"0x00\",\n"; forks += "\"constantinopleForkBlock\": \"0x00\",\n";
static string const c_configString = R"( static string const c_configString = R"(

View File

@ -99,6 +99,8 @@ public:
std::string contractAddress; std::string contractAddress;
std::vector<LogEntry> logEntries; std::vector<LogEntry> logEntries;
std::string blockNumber; std::string blockNumber;
/// note: pre-byzantium the status field will be empty
std::string status;
}; };
static RPCSession& instance(std::string const& _path); static RPCSession& instance(std::string const& _path);
@ -136,6 +138,7 @@ private:
unsigned m_maxMiningTime = 6000000; // 600 seconds unsigned m_maxMiningTime = 6000000; // 600 seconds
unsigned m_sleepTime = 10; // 10 milliseconds unsigned m_sleepTime = 10; // 10 milliseconds
unsigned m_successfulMineRuns = 0; unsigned m_successfulMineRuns = 0;
bool m_receiptHasStatusField = false;
std::vector<std::string> m_accounts; std::vector<std::string> m_accounts;
}; };

View File

@ -223,6 +223,7 @@ protected:
s_compiledRegistrar.reset(new bytes(compileContract(registrarCode, "GlobalRegistrar"))); s_compiledRegistrar.reset(new bytes(compileContract(registrarCode, "GlobalRegistrar")));
sendMessage(*s_compiledRegistrar, true); sendMessage(*s_compiledRegistrar, true);
BOOST_REQUIRE(m_transactionSuccessful);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
} }

View File

@ -135,6 +135,7 @@ protected:
s_compiledRegistrar.reset(new bytes(compileContract(registrarCode, "FixedFeeRegistrar"))); s_compiledRegistrar.reset(new bytes(compileContract(registrarCode, "FixedFeeRegistrar")));
sendMessage(*s_compiledRegistrar, true); sendMessage(*s_compiledRegistrar, true);
BOOST_REQUIRE(m_transactionSuccessful);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
} }
u256 const m_fee = u256("69000000000000000000"); u256 const m_fee = u256("69000000000000000000");

View File

@ -349,6 +349,7 @@ protected:
BOOST_REQUIRE(errors.empty()); BOOST_REQUIRE(errors.empty());
} }
sendMessage(*s_compiledEns, true); sendMessage(*s_compiledEns, true);
BOOST_REQUIRE(m_transactionSuccessful);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
} }

View File

@ -400,6 +400,7 @@ protected:
BOOST_REQUIRE(errors.empty()); BOOST_REQUIRE(errors.empty());
} }
sendMessage(*s_compiledErc20, true); sendMessage(*s_compiledErc20, true);
BOOST_REQUIRE(m_transactionSuccessful);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
} }
@ -629,18 +630,22 @@ BOOST_AUTO_TEST_CASE(bad_data)
// Correct data: transfer(address _to, 1). // Correct data: transfer(address _to, 1).
sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a123456789a") + encodeArgs(1), false, 0); sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a123456789a") + encodeArgs(1), false, 0);
BOOST_CHECK(m_transactionSuccessful);
BOOST_CHECK(m_output == SUCCESS); BOOST_CHECK(m_output == SUCCESS);
// Too little data (address is truncated by one byte). // Too little data (address is truncated by one byte).
sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a12345678") + encodeArgs(1), false, 0); sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a12345678") + encodeArgs(1), false, 0);
BOOST_CHECK(!m_transactionSuccessful);
BOOST_CHECK(m_output != SUCCESS); BOOST_CHECK(m_output != SUCCESS);
// Too much data (address is extended with a zero byte). // Too much data (address is extended with a zero byte).
sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a123456789a00") + encodeArgs(1), false, 0); sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000000123456789a123456789a123456789a123456789a00") + encodeArgs(1), false, 0);
BOOST_CHECK(!m_transactionSuccessful);
BOOST_CHECK(m_output != SUCCESS); BOOST_CHECK(m_output != SUCCESS);
// Invalid address (a bit above the 160th is set). // Invalid address (a bit above the 160th is set).
sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000100123456789a123456789a123456789a123456789a") + encodeArgs(1), false, 0); sendMessage((bytes)fromHex("a9059cbb") + (bytes)fromHex("000000000000000000000100123456789a123456789a123456789a123456789a") + encodeArgs(1), false, 0);
BOOST_CHECK(!m_transactionSuccessful);
BOOST_CHECK(m_output != SUCCESS); BOOST_CHECK(m_output != SUCCESS);
} }

View File

@ -451,6 +451,7 @@ protected:
bytes args = encodeArgs(u256(0x60), _required, _dailyLimit, u256(_owners.size()), _owners); bytes args = encodeArgs(u256(0x60), _required, _dailyLimit, u256(_owners.size()), _owners);
sendMessage(*s_compiledWallet + args, true, _value); sendMessage(*s_compiledWallet + args, true, _value);
BOOST_REQUIRE(m_transactionSuccessful);
BOOST_REQUIRE(!m_output.empty()); BOOST_REQUIRE(!m_output.empty());
} }
}; };

View File

@ -50,6 +50,7 @@ BOOST_AUTO_TEST_CASE(bare_panic)
{ {
char const* sourceCode = "(panic)"; char const* sourceCode = "(panic)";
compileAndRunWithoutCheck(sourceCode); compileAndRunWithoutCheck(sourceCode);
BOOST_REQUIRE(!m_transactionSuccessful);
BOOST_REQUIRE(m_output.empty()); BOOST_REQUIRE(m_output.empty());
} }
@ -57,6 +58,7 @@ BOOST_AUTO_TEST_CASE(panic)
{ {
char const* sourceCode = "{ (panic) }"; char const* sourceCode = "{ (panic) }";
compileAndRunWithoutCheck(sourceCode); compileAndRunWithoutCheck(sourceCode);
BOOST_REQUIRE(!m_transactionSuccessful);
BOOST_REQUIRE(m_output.empty()); BOOST_REQUIRE(m_output.empty());
} }
@ -69,6 +71,7 @@ BOOST_AUTO_TEST_CASE(macro_zeroarg)
(zeroarg))) (zeroarg)))
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(m_transactionSuccessful);
BOOST_CHECK(callFallback() == encodeArgs(u256(0x1234))); BOOST_CHECK(callFallback() == encodeArgs(u256(0x1234)));
} }

View File

@ -87,6 +87,7 @@ public:
for (bytes const& arguments: _argumentVariants) for (bytes const& arguments: _argumentVariants)
{ {
sendMessage(hash.asBytes() + arguments, false, 0); sendMessage(hash.asBytes() + arguments, false, 0);
BOOST_CHECK(m_transactionSuccessful);
gasUsed = max(gasUsed, m_gasUsed); gasUsed = max(gasUsed, m_gasUsed);
gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false)); gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false));
} }

View File

@ -49,6 +49,25 @@ namespace test
BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityExecutionFramework) 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) BOOST_AUTO_TEST_CASE(smoke_test)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -3106,9 +3125,11 @@ BOOST_AUTO_TEST_CASE(short_data_calls_fallback)
compileAndRun(sourceCode); compileAndRun(sourceCode);
// should call fallback // should call fallback
sendMessage(asBytes("\xd8\x8e\x0b"), false, 0); sendMessage(asBytes("\xd8\x8e\x0b"), false, 0);
BOOST_CHECK(m_transactionSuccessful);
ABI_CHECK(callContractFunction("x()"), encodeArgs(2)); ABI_CHECK(callContractFunction("x()"), encodeArgs(2));
// should call function // should call function
sendMessage(asBytes(string("\xd8\x8e\x0b") + string(1, 0)), false, 0); sendMessage(asBytes(string("\xd8\x8e\x0b") + string(1, 0)), false, 0);
BOOST_CHECK(m_transactionSuccessful);
ABI_CHECK(callContractFunction("x()"), encodeArgs(3)); ABI_CHECK(callContractFunction("x()"), encodeArgs(3));
} }
@ -3793,6 +3814,7 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory)
compileAndRun(sourceCode); compileAndRun(sourceCode);
bytes calldata1 = FixedHash<4>(dev::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12); bytes calldata1 = FixedHash<4>(dev::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12);
sendMessage(calldata1, false); sendMessage(calldata1, false);
BOOST_CHECK(m_transactionSuccessful);
BOOST_CHECK(m_output == encodeArgs(dev::keccak256(bytes{'a', 'b', 'c'} + calldata1))); 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)); ABI_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5), encodeArgs(true));
BOOST_CHECK(!storageEmpty(m_contractAddress)); BOOST_CHECK(!storageEmpty(m_contractAddress));
sendMessage(bytes(), false); sendMessage(bytes(), false);
BOOST_CHECK(m_output == bytes()); BOOST_CHECK(m_transactionSuccessful);
BOOST_CHECK(m_output.empty());
BOOST_CHECK(storageEmpty(m_contractAddress)); 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()); ABI_CHECK(compileAndRunWithoutCheck(sourceCode, 0, "A"), encodeArgs());
BOOST_CHECK(!m_transactionSuccessful);
} }
BOOST_AUTO_TEST_CASE(positive_integers_to_signed) BOOST_AUTO_TEST_CASE(positive_integers_to_signed)