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. 110
      libethereum/State.cpp
  4. 14
      libethereum/State.h
  5. 43
      libethereum/Transaction.cpp
  6. 6
      libethereum/Transaction.h
  7. 44
      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 OutOfGasBase: virtual dev::Exception {};
struct OutOfGasIntrinsic: virtual dev::Exception {};
struct NotEnoughAvailableSpace: virtual dev::Exception {};
struct NotEnoughCash: virtual dev::Exception {};
struct GasPriceTooLow: virtual dev::Exception {};
@ -51,20 +52,15 @@ struct ExtraDataTooBig: virtual dev::Exception {};
struct InvalidSignature: virtual dev::Exception {};
struct InvalidBlockFormat: virtual dev::Exception {};
struct InvalidUnclesHash: virtual dev::Exception {};
struct InvalidUncle: virtual dev::Exception {};
struct TooManyUncles: virtual dev::Exception {};
struct UncleTooOld: virtual dev::Exception {};
struct UncleIsBrother: virtual dev::Exception {};
struct UncleInChain: virtual dev::Exception {};
struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {};
struct InvalidGasUsed: virtual dev::Exception {};
struct InvalidTransactionsHash: virtual dev::Exception {};
struct InvalidTransaction: virtual dev::Exception {};
struct InvalidTransactionsRoot: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {};
struct InvalidGasLimit: virtual dev::Exception {};
struct InvalidTransactionGasUsed: virtual dev::Exception {};
struct InvalidTransactionsStateRoot: virtual dev::Exception {};
struct InvalidReceiptsStateRoot: virtual dev::Exception {};
struct InvalidTimestamp: 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())
{
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()));
}

110
libethereum/State.cpp

@ -605,6 +605,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
#endif
if (m_currentBlock.parentHash != m_previousBlock.hash())
// Internal client error.
BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values.
@ -624,16 +625,19 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
unsigned i = 0;
for (auto const& tr: rlp[1])
{
try {
try
{
LogOverride<ExecutiveWarnChannel> o(false);
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;
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;
}
@ -658,7 +662,12 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
cwarn << " " << TransactionReceipt(&b);
}
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())
@ -671,7 +680,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().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.
@ -681,45 +693,70 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (rlp[2].itemCount() > 2)
{
badBlock(_block, "Too many uncles");
BOOST_THROW_EXCEPTION(TooManyUncles());
BOOST_THROW_EXCEPTION(TooManyUncles() << errinfo_max(2) << errinfo_got(rlp[2].itemCount()));
}
vector<BlockInfo> rewarded;
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
excluded.insert(m_currentBlock.hash());
unsigned ii = 0;
for (auto const& i: rlp[2])
{
auto h = sha3(i.data());
if (excluded.count(h))
try
{
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())));
}
excluded.insert(h);
auto h = sha3(i.data());
if (excluded.count(h))
{
badBlock(_block, "Invalid uncle included");
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);
BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
BlockInfo uncleParent(_bc.block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
{
badBlock(_block, "Uncle too old");
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
BOOST_THROW_EXCEPTION(UncleTooOld());
BlockInfo uncle;
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)
{
badBlock(_block, "Uncle too old");
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
UncleTooOld ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
BOOST_THROW_EXCEPTION(ex);
}
else if (uncle.number == m_currentBlock.number)
{
badBlock(_block, "Uncle is brother");
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
UncleIsBrother ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
BOOST_THROW_EXCEPTION(ex);
}
uncle.verifyParent(uncleParent);
// tdIncrease += uncle.difficulty;
rewarded.push_back(uncle);
++ii;
}
else if (uncle.number == m_currentBlock.number)
catch (Exception& ex)
{
badBlock(_block, "Uncle is brother");
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
BOOST_THROW_EXCEPTION(UncleIsBrother());
ex << errinfo_uncleIndex(ii);
throw;
}
uncle.verifyParent(uncleParent);
// tdIncrease += uncle.difficulty;
rewarded.push_back(uncle);
}
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())
{
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();
BOOST_THROW_EXCEPTION(InvalidStateRoot());
BOOST_THROW_EXCEPTION(InvalidStateRoot() << HashMismatchError(rootHash(), m_currentBlock.stateRoot));
}
if (m_currentBlock.gasUsed != gasUsed())

14
libethereum/State.h

@ -46,6 +46,20 @@ namespace test { class ImportTest; class StateLoader; }
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 State;

43
libethereum/Transaction.cpp

@ -60,8 +60,25 @@ std::string badTransaction(bytesConstRef _tx, string const& _err)
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))
return TransactionException::BadInstruction;
if (!!dynamic_cast<BadJumpDestination const*>(&_e))
@ -75,6 +92,28 @@ TransactionException dev::eth::toTransactionException(VMException const& _e)
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)
{
int field = 0;
@ -114,7 +153,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
throw;
}
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

6
libethereum/Transaction.h

@ -25,6 +25,7 @@
#include <libdevcore/SHA3.h>
#include <libethcore/Common.h>
#include <libevmcore/Params.h>
namespace dev
{
namespace eth
@ -48,6 +49,8 @@ enum class TransactionException
{
None = 0,
Unknown,
BadRLP,
OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost.
InvalidSignature,
InvalidNonce,
NotEnoughCash,
@ -69,7 +72,8 @@ enum class CodeDeposit
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.
struct ExecutionResult

44
mix/MixClient.cpp

@ -203,27 +203,29 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
switch (er.excepted)
{
case TransactionException::None:
break;
case TransactionException::NotEnoughCash:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment"));
case TransactionException::OutOfGasBase:
case TransactionException::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas"));
case TransactionException::BlockGasLimitReached:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached"));
case TransactionException::OutOfStack:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack"));
case TransactionException::StackUnderflow:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow"));
//these should not happen in mix
case TransactionException::Unknown:
case TransactionException::BadInstruction:
case TransactionException::BadJumpDestination:
case TransactionException::InvalidSignature:
case TransactionException::InvalidNonce:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error"));
};
case TransactionException::None:
break;
case TransactionException::NotEnoughCash:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment"));
case TransactionException::OutOfGasIntrinsic:
case TransactionException::OutOfGasBase:
case TransactionException::OutOfGas:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas"));
case TransactionException::BlockGasLimitReached:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached"));
case TransactionException::OutOfStack:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack"));
case TransactionException::StackUnderflow:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow"));
//these should not happen in mix
case TransactionException::Unknown:
case TransactionException::BadInstruction:
case TransactionException::BadJumpDestination:
case TransactionException::InvalidSignature:
case TransactionException::InvalidNonce:
case TransactionException::BadRLP:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error"));
}
ExecutionResult d;
d.result = er;

Loading…
Cancel
Save