From 513fc897d82a6b9c851920699f20a3bd4a2bd49e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 15 Feb 2015 13:05:49 +0100 Subject: [PATCH] External Debugger for debugging past transactions, too. --- alethzero/Debugger.cpp | 16 ++++++++++++---- alethzero/Debugger.h | 4 ++-- alethzero/MainWin.cpp | 22 +++++++--------------- libethereum/BlockChain.h | 4 ++++ libethereum/Executive.cpp | 6 ++++++ libethereum/Executive.h | 5 +++++ 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/alethzero/Debugger.cpp b/alethzero/Debugger.cpp index 442868a94..93d6b1f6a 100644 --- a/alethzero/Debugger.cpp +++ b/alethzero/Debugger.cpp @@ -56,18 +56,26 @@ void Debugger::init() } } -void Debugger::populate(dev::eth::Executive& _executive, dev::bytesConstRef _transactionRLP) +void Debugger::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction) { finished(); - if (m_session.populate(_executive, _transactionRLP)) + if (m_session.populate(_executive, _transaction)) init(); update(); } -bool DebugSession::populate(dev::eth::Executive& _executive, dev::bytesConstRef _transactionRLP) +bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction) { - if (_executive.setup(_transactionRLP)) + try { + if (_executive.setup(_transaction)) + return false; + } + catch (...) + { + // Invalid transaction return false; + } + vector levels; bytes lastExtCode; bytesConstRef lastData; diff --git a/alethzero/Debugger.h b/alethzero/Debugger.h index 1b08e8f92..370ad6e30 100644 --- a/alethzero/Debugger.h +++ b/alethzero/Debugger.h @@ -53,7 +53,7 @@ struct DebugSession { DebugSession() {} - bool populate(dev::eth::Executive& _executive, dev::bytesConstRef _transactionRLP); + bool populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction); dev::h256 currentCode; dev::h256 currentData; @@ -73,7 +73,7 @@ public: explicit Debugger(Context* _context, QWidget* _parent = 0); ~Debugger(); - void populate(dev::eth::Executive& _executive, dev::bytesConstRef _transactionRLP); + void populate(dev::eth::Executive& _executive, dev::eth::Transaction const& _transaction); protected slots: void on_callStack_currentItemChanged(); diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 6c9c4a069..62bc5e069 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1478,13 +1478,12 @@ void Main::on_debugCurrent_triggered() if (!item->data(Qt::UserRole + 1).isNull()) { unsigned txi = item->data(Qt::UserRole + 1).toInt(); - m_executiveState = ethereum()->state(txi + 1, h); - m_currentExecution = unique_ptr(new Executive(m_executiveState, ethereum()->blockChain(), 0)); - Transaction t = m_executiveState.pending()[txi]; - m_executiveState = m_executiveState.fromPending(txi); - auto r = t.rlp(); - populateDebugger(&r); - m_currentExecution.reset(); + bytes t = ethereum()->blockChain().transaction(h, txi); + State s(ethereum()->state(txi, h)); + Executive e(s, ethereum()->blockChain(), 0); + Debugger dw(this, this); + dw.populate(e, Transaction(t, CheckSignature::Sender)); + dw.exec(); } } } @@ -1991,7 +1990,6 @@ void Main::keysChanged() void Main::on_debug_clicked() { - debugFinished(); try { u256 totalReq = value() + fee(); @@ -2002,16 +2000,10 @@ void Main::on_debug_clicked() Transaction t = isCreation() ? Transaction(value(), gasPrice(), ui->gas->value(), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s) : Transaction(value(), gasPrice(), ui->gas->value(), fromString(ui->destination->currentText()), m_data, m_executiveState.transactionsFrom(dev::toAddress(s)), s); - auto r = t.rlp(); Debugger dw(this, this); Executive e(m_executiveState, ethereum()->blockChain(), 0); - dw.populate(e, &r); + dw.populate(e, t); dw.exec(); - - /*m_executiveState = ethereum()->postState(); - m_currentExecution = unique_ptr(new Executive(m_executiveState, ethereum()->blockChain(), 0)); - populateDebugger(&r); - m_currentExecution.reset();*/ return; } statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50ad78dac..0c5587d2a 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -112,6 +112,10 @@ public: bytes block(h256 _hash) const; bytes block() const { return block(currentHash()); } + /// Get a block's transaction (RLP format) for the given block hash (or the most recent mined if none given) & index. Thread-safe. + bytes transaction(h256 _hash, unsigned _i) const { bytes b = block(_hash); return RLP(b)[1][_i].data().toBytes(); } + bytes transaction(unsigned _i) const { return transaction(currentHash(), _i); } + /// Get a number for the given hash (or the most recent mined if none given). Thread-safe. unsigned number(h256 _hash) const { return details(_hash).number; } unsigned number() const { return number(currentHash()); } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index cea7d21f4..f407a6f0b 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -54,6 +54,12 @@ bool Executive::setup(bytesConstRef _rlp) { // Entry point for a user-executed transaction. m_t = Transaction(_rlp, CheckSignature::Sender); + return setup(); +} + +bool Executive::setup() +{ + // Entry point for a user-executed transaction. // Avoid invalid transactions. auto nonceReq = m_s.transactionsFrom(m_t.sender()); diff --git a/libethereum/Executive.h b/libethereum/Executive.h index d743e3746..bb5563604 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -62,6 +62,9 @@ public: /// Set up the executive for evaluating a transaction. You must call finalize() following this. /// @returns true iff go() must be called (and thus a VM execution in required). bool setup(bytesConstRef _transaction); + /// Set up the executive for evaluating a transaction. You must call finalize() following this. + /// @returns true iff go() must be called (and thus a VM execution in required). + bool setup(Transaction const& _transaction) { m_t = _transaction; return setup(); } /// Finalise a transaction previously set up with setup(). /// @warning Only valid after setup(), and possibly go(). void finalize(); @@ -101,6 +104,8 @@ public: bool excepted() const { return m_excepted; } private: + bool setup(); + State& m_s; ///< The state to which this operation/transaction is applied. LastHashes m_lastHashes; std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required.