From d1f19fe2d4fe75788669535af5e8aa40b791d89a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 20:11:59 +0800 Subject: [PATCH] Fix for windows. Better failure reporting on consensus issues. --- libethereum/Executive.cpp | 11 ++++++----- libethereum/Executive.h | 1 + libethereum/State.cpp | 33 ++++++++++++++++++++++++++++++++- libethereum/Transaction.cpp | 21 +++++++++++++++++++++ libethereum/Transaction.h | 3 +++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 09cdc6b04..8c77903ef 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -32,6 +32,7 @@ using namespace dev; using namespace dev::eth; const char* VMTraceChannel::name() { return "EVM"; } +const char* ExecutiveWarnChannel::name() { return WarnChannel::name(); } Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), @@ -63,7 +64,7 @@ void Executive::initialize(Transaction const& _transaction) u256 startGasUsed = m_s.gasUsed(); if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) { - clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); } @@ -71,7 +72,7 @@ void Executive::initialize(Transaction const& _transaction) // Check gas cost is enough. if (!m_t.checkPayment()) { - clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas(); m_excepted = TransactionException::OutOfGas; BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(m_t.gasRequired(), (bigint)m_t.gas())); } @@ -84,13 +85,13 @@ void Executive::initialize(Transaction const& _transaction) } catch (...) { - clog(StateDetail) << "Invalid Signature"; + clog(ExecutiveWarnChannel) << "Invalid Signature"; m_excepted = TransactionException::InvalidSignature; throw; } if (m_t.nonce() != nonceReq) { - clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); + clog(ExecutiveWarnChannel) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); m_excepted = TransactionException::InvalidNonce; BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce())); } @@ -100,7 +101,7 @@ void Executive::initialize(Transaction const& _transaction) m_totalCost = m_t.value() + m_gasCost; if (m_s.balance(m_t.sender()) < m_totalCost) { - clog(StateDetail) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()); + clog(ExecutiveWarnChannel) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()); m_excepted = TransactionException::NotEnoughCash; BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender()))); } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 949e2dc34..447f76eb9 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -36,6 +36,7 @@ class ExtVM; struct Manifest; struct VMTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 11; }; +struct ExecutiveWarnChannel: public LogChannel { static const char* name(); static const int verbosity = 6; }; /** * @brief Message-call/contract-creation executor; useful for executing transactions. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 23405912c..20249f2eb 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -592,6 +592,24 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ss.str(); } +template +class LogOverride +{ +public: + LogOverride(bool _value): m_old(g_logOverride.count(&typeid(Channel)) ? (int)g_logOverride[&typeid(Channel)] : c_null) { g_logOverride[&typeid(Channel)] = _value; } + ~LogOverride() + { + if (m_old == c_null) + g_logOverride.erase(&typeid(Channel)); + else + g_logOverride[&typeid(Channel)] = (bool)m_old; + } + +private: + static const int c_null = -1; + int m_old; +}; + u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) { // m_currentBlock is assumed to be prepopulated and reset. @@ -624,7 +642,19 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement unsigned i = 0; for (auto const& tr: rlp[1]) { - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + try { + LogOverride o(false); + execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + } + catch (...) + { + badBlock(_block, "Invalid transaction"); + cwarn << " Transaction Index:" << i; + LogOverride o(true); + execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + throw; + } + RLPStream receiptRLP; m_receipts.back().streamRLP(receiptRLP); receipts.push_back(receiptRLP.out()); @@ -1163,6 +1193,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif + (void)_onOp; if (!e.execute()) #if ETH_VMTRACE e.go(e.simpleTrace()); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 975af53a5..b8d8d64c1 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -39,6 +39,27 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _e return _out; } +std::string badTransaction(bytesConstRef _tx, string const& _err) +{ + stringstream ret; + ret << "========================================================================" << endl; + ret << "== Software Failure " << (_err + string(max(0, 44 - _err.size()), ' ')) << " ==" << endl; + ret << "== Guru Meditation " << sha3(_tx).abridged() << " ==" << endl; + ret << "========================================================================" << endl; + ret << " Transaction: " << toHex(_tx) << endl; + ret << " Transaction RLP: "; + try { + ret << RLP(_tx); + } + catch (Exception& _e) + { + ret << "Invalid: " << _e.what(); + } + ret << endl; + + return ret.str(); +} + TransactionException dev::eth::toTransactionException(VMException const& _e) { if (!!dynamic_cast(&_e)) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 09d6cd54c..935b78c2a 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -235,5 +235,8 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) return _out; } +void badTransaction(bytesConstRef _tx, std::string const& _err); +inline void badTransaction(bytes const& _tx, std::string const& _err) { badTransaction(&_tx, _err); } + } }