Browse Source

Much better exception error reporting.

Readying things for phone-home on badblock.
cl-refactor
Gav Wood 10 years ago
parent
commit
cd2236b468
  1. 8
      libethcore/Exceptions.h
  2. 2
      libethereum/Executive.cpp
  3. 70
      libethereum/State.cpp
  4. 14
      libethereum/State.h
  5. 43
      libethereum/Transaction.cpp
  6. 6
      libethereum/Transaction.h
  7. 4
      mix/MixClient.cpp

8
libethcore/Exceptions.h

@ -39,6 +39,7 @@ using BadFieldError = boost::tuple<errinfo_field, errinfo_data>;
struct DatabaseAlreadyOpen: virtual dev::Exception {}; struct DatabaseAlreadyOpen: virtual dev::Exception {};
struct OutOfGasBase: virtual dev::Exception {}; struct OutOfGasBase: virtual dev::Exception {};
struct OutOfGasIntrinsic: virtual dev::Exception {};
struct NotEnoughAvailableSpace: virtual dev::Exception {}; struct NotEnoughAvailableSpace: virtual dev::Exception {};
struct NotEnoughCash: virtual dev::Exception {}; struct NotEnoughCash: virtual dev::Exception {};
struct GasPriceTooLow: virtual dev::Exception {}; struct GasPriceTooLow: virtual dev::Exception {};
@ -51,20 +52,15 @@ struct ExtraDataTooBig: virtual dev::Exception {};
struct InvalidSignature: virtual dev::Exception {}; struct InvalidSignature: virtual dev::Exception {};
struct InvalidBlockFormat: virtual dev::Exception {}; struct InvalidBlockFormat: virtual dev::Exception {};
struct InvalidUnclesHash: virtual dev::Exception {}; struct InvalidUnclesHash: virtual dev::Exception {};
struct InvalidUncle: virtual dev::Exception {};
struct TooManyUncles: virtual dev::Exception {}; struct TooManyUncles: virtual dev::Exception {};
struct UncleTooOld: virtual dev::Exception {}; struct UncleTooOld: virtual dev::Exception {};
struct UncleIsBrother: virtual dev::Exception {}; struct UncleIsBrother: virtual dev::Exception {};
struct UncleInChain: virtual dev::Exception {}; struct UncleInChain: virtual dev::Exception {};
struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {}; struct InvalidStateRoot: virtual dev::Exception {};
struct InvalidGasUsed: virtual dev::Exception {}; struct InvalidGasUsed: virtual dev::Exception {};
struct InvalidTransactionsHash: virtual dev::Exception {}; struct InvalidTransactionsRoot: virtual dev::Exception {};
struct InvalidTransaction: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {};
struct InvalidGasLimit: virtual dev::Exception {}; struct InvalidGasLimit: virtual dev::Exception {};
struct InvalidTransactionGasUsed: virtual dev::Exception {};
struct InvalidTransactionsStateRoot: virtual dev::Exception {};
struct InvalidReceiptsStateRoot: virtual dev::Exception {}; struct InvalidReceiptsStateRoot: virtual dev::Exception {};
struct InvalidTimestamp: virtual dev::Exception {}; struct InvalidTimestamp: virtual dev::Exception {};
struct InvalidLogBloom: virtual dev::Exception {}; struct InvalidLogBloom: virtual dev::Exception {};

2
libethereum/Executive.cpp

@ -68,7 +68,7 @@ void Executive::initialize(Transaction const& _transaction)
if (!m_t.checkPayment()) if (!m_t.checkPayment())
{ {
clog(ExecutiveWarnChannel) << "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; m_excepted = TransactionException::OutOfGasBase;
BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(m_t.gasRequired(), (bigint)m_t.gas())); BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(m_t.gasRequired(), (bigint)m_t.gas()));
} }

70
libethereum/State.cpp

@ -605,6 +605,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
#endif #endif
if (m_currentBlock.parentHash != m_previousBlock.hash()) if (m_currentBlock.parentHash != m_previousBlock.hash())
// Internal client error.
BOOST_THROW_EXCEPTION(InvalidParentHash()); BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values. // Populate m_currentBlock with the correct values.
@ -624,16 +625,19 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
unsigned i = 0; unsigned i = 0;
for (auto const& tr: rlp[1]) for (auto const& tr: rlp[1])
{ {
try { try
{
LogOverride<ExecutiveWarnChannel> o(false); LogOverride<ExecutiveWarnChannel> o(false);
execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); execute(lh, Transaction(tr.data(), CheckTransaction::Everything));
} }
catch (...) catch (Exception& ex)
{ {
badBlock(_block, "Invalid transaction"); badBlock(_block, "Invalid transaction: " + toString(toTransactionException(ex)));
cwarn << " Transaction Index:" << i; cwarn << " Transaction Index:" << i;
LogOverride<ExecutiveWarnChannel> o(true); LogOverride<ExecutiveWarnChannel> o(true);
execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); DEV_IGNORE_EXCEPTIONS(execute(lh, Transaction(tr.data(), CheckTransaction::Everything)));
ex << errinfo_transactionIndex(i);
throw; throw;
} }
@ -658,7 +662,12 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
cwarn << " " << TransactionReceipt(&b); cwarn << " " << TransactionReceipt(&b);
} }
cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir);
BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
InvalidReceiptsStateRoot ex;
ex << HashMismatchError(receiptsRoot, m_currentBlock.receiptsRoot);
ex << errinfo_receipts(receipts);
ex << errinfo_vmtrace(vmTrace(_block, _bc, _ir));
BOOST_THROW_EXCEPTION(ex);
} }
if (m_currentBlock.logBloom != logBloom()) if (m_currentBlock.logBloom != logBloom())
@ -671,7 +680,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex(); cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex();
} }
cwarn << " Final bloom:" << m_currentBlock.logBloom.hex(); cwarn << " Final bloom:" << m_currentBlock.logBloom.hex();
BOOST_THROW_EXCEPTION(InvalidLogBloom()); InvalidLogBloom ex;
ex << LogBloomMismatchError(logBloom(), m_currentBlock.logBloom);
ex << errinfo_receipts(receipts);
BOOST_THROW_EXCEPTION(ex);
} }
// Initialise total difficulty calculation. // Initialise total difficulty calculation.
@ -681,32 +693,47 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (rlp[2].itemCount() > 2) if (rlp[2].itemCount() > 2)
{ {
badBlock(_block, "Too many uncles"); badBlock(_block, "Too many uncles");
BOOST_THROW_EXCEPTION(TooManyUncles()); BOOST_THROW_EXCEPTION(TooManyUncles() << errinfo_max(2) << errinfo_got(rlp[2].itemCount()));
} }
vector<BlockInfo> rewarded; vector<BlockInfo> rewarded;
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
excluded.insert(m_currentBlock.hash()); excluded.insert(m_currentBlock.hash());
unsigned ii = 0;
for (auto const& i: rlp[2]) for (auto const& i: rlp[2])
{
try
{ {
auto h = sha3(i.data()); auto h = sha3(i.data());
if (excluded.count(h)) if (excluded.count(h))
{ {
badBlock(_block, "Invalid uncle included"); badBlock(_block, "Invalid uncle included");
BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(excluded)) << errinfo_hash256(sha3(i.data()))); UncleInChain ex;
ex << errinfo_comment("Uncle in block already mentioned");
ex << errinfo_unclesExcluded(excluded);
ex << errinfo_hash256(sha3(i.data()));
BOOST_THROW_EXCEPTION(ex);
} }
excluded.insert(h); excluded.insert(h);
BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); BlockInfo uncle;
BlockInfo uncleParent(_bc.block(uncle.parentHash)); BlockInfo uncleParent;
uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
if (!_bc.isKnown(uncle.parentHash))
BOOST_THROW_EXCEPTION(UnknownParent());
uncleParent = BlockInfo(_bc.block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
{ {
badBlock(_block, "Uncle too old"); badBlock(_block, "Uncle too old");
cwarn << " Uncle number: " << uncle.number; cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number; cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number; cwarn << " Block number: " << m_currentBlock.number;
BOOST_THROW_EXCEPTION(UncleTooOld()); UncleTooOld ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
BOOST_THROW_EXCEPTION(ex);
} }
else if (uncle.number == m_currentBlock.number) else if (uncle.number == m_currentBlock.number)
{ {
@ -714,12 +741,22 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
cwarn << " Uncle number: " << uncle.number; cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number; cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number; cwarn << " Block number: " << m_currentBlock.number;
BOOST_THROW_EXCEPTION(UncleIsBrother()); UncleIsBrother ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
BOOST_THROW_EXCEPTION(ex);
} }
uncle.verifyParent(uncleParent); uncle.verifyParent(uncleParent);
// tdIncrease += uncle.difficulty; // tdIncrease += uncle.difficulty;
rewarded.push_back(uncle); rewarded.push_back(uncle);
++ii;
}
catch (Exception& ex)
{
ex << errinfo_uncleIndex(ii);
throw;
}
} }
applyRewards(rewarded); applyRewards(rewarded);
@ -731,15 +768,8 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash())
{ {
badBlock(_block, "Bad state root"); badBlock(_block, "Bad state root");
cnote << " Given to be:" << m_currentBlock.stateRoot;
// TODO: Fix
// cnote << SecureTrieDB<Address, OverlayDB>(&m_db, m_currentBlock.stateRoot);
cnote << " Calculated to be:" << rootHash();
cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir);
// cnote << m_state;
// Rollback the trie.
m_db.rollback(); m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidStateRoot()); BOOST_THROW_EXCEPTION(InvalidStateRoot() << HashMismatchError(rootHash(), m_currentBlock.stateRoot));
} }
if (m_currentBlock.gasUsed != gasUsed()) if (m_currentBlock.gasUsed != gasUsed())

14
libethereum/State.h

@ -46,6 +46,20 @@ namespace test { class ImportTest; class StateLoader; }
namespace eth namespace eth
{ {
// Import-specific errinfos
using errinfo_uncleIndex = boost::error_info<struct tag_uncleIndex, unsigned>;
using errinfo_currentNumber = boost::error_info<struct tag_currentNumber, u256>;
using errinfo_uncleNumber = boost::error_info<struct tag_uncleNumber, u256>;
using errinfo_unclesExcluded = boost::error_info<struct tag_unclesExcluded, h256Hash>;
using errinfo_transactionIndex = boost::error_info<struct tag_transactionIndex, unsigned>;
using errinfo_vmtrace = boost::error_info<struct tag_vmtrace, std::string>;
using errinfo_receipts = boost::error_info<struct tag_receipts, std::vector<bytes>>;
using errinfo_logBloom = boost::error_info<struct tag_logBloom, LogBloom>;
using LogBloomMismatchError = boost::tuple<errinfo_logBloom, errinfo_logBloom>;
class BlockChain; class BlockChain;
class State; class State;

43
libethereum/Transaction.cpp

@ -60,8 +60,25 @@ std::string badTransaction(bytesConstRef _tx, string const& _err)
return ret.str(); return ret.str();
} }
TransactionException dev::eth::toTransactionException(VMException const& _e) TransactionException dev::eth::toTransactionException(Exception const& _e)
{ {
// Basic Transaction exceptions
if (!!dynamic_cast<BadRLP const*>(&_e))
return TransactionException::BadRLP;
if (!!dynamic_cast<OutOfGasIntrinsic const*>(&_e))
return TransactionException::OutOfGasIntrinsic;
if (!!dynamic_cast<InvalidSignature const*>(&_e))
return TransactionException::InvalidSignature;
// Executive exceptions
if (!!dynamic_cast<OutOfGasBase const*>(&_e))
return TransactionException::OutOfGasBase;
if (!!dynamic_cast<InvalidNonce const*>(&_e))
return TransactionException::InvalidNonce;
if (!!dynamic_cast<NotEnoughCash const*>(&_e))
return TransactionException::NotEnoughCash;
if (!!dynamic_cast<BlockGasLimitReached const*>(&_e))
return TransactionException::BlockGasLimitReached;
// VM execution exceptions
if (!!dynamic_cast<BadInstruction const*>(&_e)) if (!!dynamic_cast<BadInstruction const*>(&_e))
return TransactionException::BadInstruction; return TransactionException::BadInstruction;
if (!!dynamic_cast<BadJumpDestination const*>(&_e)) if (!!dynamic_cast<BadJumpDestination const*>(&_e))
@ -75,6 +92,28 @@ TransactionException dev::eth::toTransactionException(VMException const& _e)
return TransactionException::Unknown; return TransactionException::Unknown;
} }
std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionException const& _er)
{
switch (_er)
{
case TransactionException::None: _out << "None"; break;
case TransactionException::BadRLP: _out << "BadRLP"; break;
case TransactionException::OutOfGasIntrinsic: _out << "OutOfGasIntrinsic"; break;
case TransactionException::InvalidSignature: _out << "InvalidSignature"; break;
case TransactionException::InvalidNonce: _out << "InvalidNonce"; break;
case TransactionException::NotEnoughCash: _out << "NotEnoughCash"; break;
case TransactionException::OutOfGasBase: _out << "OutOfGasBase"; break;
case TransactionException::BlockGasLimitReached: _out << "BlockGasLimitReached"; break;
case TransactionException::BadInstruction: _out << "BadInstruction"; break;
case TransactionException::BadJumpDestination: _out << "BadJumpDestination"; break;
case TransactionException::OutOfGas: _out << "OutOfGas"; break;
case TransactionException::OutOfStack: _out << "OutOfStack"; break;
case TransactionException::StackUnderflow: _out << "StackUnderflow"; break;
default: _out << "Unknown"; break;
}
return _out;
}
Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
{ {
int field = 0; int field = 0;
@ -114,7 +153,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
throw; throw;
} }
if (_checkSig >= CheckTransaction::Cheap && !checkPayment()) if (_checkSig >= CheckTransaction::Cheap && !checkPayment())
BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(gasRequired(), (bigint)gas())); BOOST_THROW_EXCEPTION(OutOfGasIntrinsic() << RequirementError(gasRequired(), (bigint)gas()));
} }
Address const& Transaction::safeSender() const noexcept Address const& Transaction::safeSender() const noexcept

6
libethereum/Transaction.h

@ -25,6 +25,7 @@
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libevmcore/Params.h> #include <libevmcore/Params.h>
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -48,6 +49,8 @@ enum class TransactionException
{ {
None = 0, None = 0,
Unknown, Unknown,
BadRLP,
OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost.
InvalidSignature, InvalidSignature,
InvalidNonce, InvalidNonce,
NotEnoughCash, NotEnoughCash,
@ -69,7 +72,8 @@ enum class CodeDeposit
struct VMException; struct VMException;
TransactionException toTransactionException(VMException const& _e); TransactionException toTransactionException(Exception const& _e);
std::ostream& operator<<(std::ostream& _out, TransactionException const& _er);
/// Description of the result of executing a transaction. /// Description of the result of executing a transaction.
struct ExecutionResult struct ExecutionResult

4
mix/MixClient.cpp

@ -207,6 +207,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
break; break;
case TransactionException::NotEnoughCash: case TransactionException::NotEnoughCash:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment"));
case TransactionException::OutOfGasIntrinsic:
case TransactionException::OutOfGasBase: case TransactionException::OutOfGasBase:
case TransactionException::OutOfGas: case TransactionException::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas"));
@ -222,8 +223,9 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
case TransactionException::BadJumpDestination: case TransactionException::BadJumpDestination:
case TransactionException::InvalidSignature: case TransactionException::InvalidSignature:
case TransactionException::InvalidNonce: case TransactionException::InvalidNonce:
case TransactionException::BadRLP:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error"));
}; }
ExecutionResult d; ExecutionResult d;
d.result = er; d.result = er;

Loading…
Cancel
Save