From 0a831eb79b66fabb10dce20e23e832be18a4aab1 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 9 Feb 2015 16:16:16 +0100 Subject: [PATCH] Mix: call filter for transaction log --- mix/ClientModel.cpp | 25 ++++++------- mix/ClientModel.h | 32 +++++++++-------- mix/MachineStates.h | 8 +++-- mix/MixClient.cpp | 73 +++++++++++++++++--------------------- mix/MixClient.h | 8 ++--- mix/qml/CallStack.qml | 31 ---------------- mix/qml/DebugInfoList.qml | 1 + mix/qml/TransactionLog.qml | 41 +++++++++++---------- mix/qml/main.qml | 10 ++++++ mix/res.qrc | 1 - 10 files changed, 105 insertions(+), 125 deletions(-) delete mode 100644 mix/qml/CallStack.qml diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 602940078..10a60811f 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -82,7 +82,7 @@ ClientModel::ClientModel(AppContext* _context): qRegisterMetaType("QInstruction"); qRegisterMetaType("QCode"); qRegisterMetaType("QCallData"); - qRegisterMetaType("TransactionLogEntry"); + qRegisterMetaType("RecordLogEntry"); connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); @@ -313,10 +313,10 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) } -void ClientModel::debugTransaction(unsigned _block, unsigned _index) +void ClientModel::debugRecord(unsigned _index) { - auto const& t = m_client->execution(_block, _index); - showDebuggerForTransaction(t); + ExecutionResult const& e = m_client->executions().at(_index); + showDebuggerForTransaction(e); } void ClientModel::showDebugError(QString const& _error) @@ -346,9 +346,10 @@ void ClientModel::onStateReset() void ClientModel::onNewTransaction() { - unsigned block = m_client->number() + 1; - unsigned index = m_client->pendingExecutions().size() - 1; ExecutionResult const& tr = m_client->lastExecution(); + unsigned block = m_client->number() + 1; + unsigned recordIndex = m_client->executions().size() - 1; + QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex); QString address = QString::fromStdString(toJS(tr.address)); QString value = QString::fromStdString(dev::toString(tr.value)); QString contract = address; @@ -359,7 +360,7 @@ void ClientModel::onNewTransaction() //TODO: handle value transfer FixedHash<4> functionHash; - bool call = false; + bool abi = false; if (creation) { //contract creation @@ -374,12 +375,12 @@ void ClientModel::onNewTransaction() } else { - //call + //transaction/call if (tr.transactionData.size() > 0 && tr.transactionData.front().size() >= 4) { functionHash = FixedHash<4>(tr.transactionData.front().data(), FixedHash<4>::ConstructFromPointer); function = QString::fromStdString(toJS(functionHash)); - call = true; + abi = true; } else function = QObject::tr(""); @@ -393,7 +394,7 @@ void ClientModel::onNewTransaction() auto compilerRes = m_context->codeModel()->code(); QContractDefinition* def = compilerRes->contract(); contract = def->name(); - if (call) + if (abi) { QFunctionDefinition* funcDef = def->getFunction(functionHash); if (funcDef) @@ -407,9 +408,9 @@ void ClientModel::onNewTransaction() } } - TransactionLogEntry* log = new TransactionLogEntry(block, index, contract, function, value, address, returned); + RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall()); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); - emit newTransaction(log); + emit newRecord(log); } } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index bb912f983..530dc50cf 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -69,13 +69,13 @@ struct TransactionSettings /// UI Transaction log record -class TransactionLogEntry: public QObject +class RecordLogEntry: public QObject { Q_OBJECT - /// Transaction block number - Q_PROPERTY(unsigned block MEMBER m_block CONSTANT) - /// Transaction index within the block - Q_PROPERTY(unsigned tindex MEMBER m_index CONSTANT) + /// Recording index + Q_PROPERTY(unsigned recordIndex MEMBER m_recordIndex CONSTANT) + /// Human readable transaction bloack and transaction index + Q_PROPERTY(QString transactionIndex MEMBER m_transactionIndex CONSTANT) /// Contract name if any Q_PROPERTY(QString contract MEMBER m_contract CONSTANT) /// Function name if any @@ -86,21 +86,25 @@ class TransactionLogEntry: public QObject Q_PROPERTY(QString address MEMBER m_address CONSTANT) /// Returned value or transaction address in case of creation Q_PROPERTY(QString returned MEMBER m_returned CONSTANT) + /// true if call, false if transaction + Q_PROPERTY(bool call MEMBER m_call CONSTANT) + public: - TransactionLogEntry(): - m_block(0), m_index(0) {} - TransactionLogEntry(int _block, int _index, QString _contract, QString _function, QString _value, QString _address, QString _returned): - m_block(_block), m_index(_index), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned) {} + RecordLogEntry(): + m_recordIndex(0), m_call(false) {} + RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call): + m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call) {} private: - unsigned m_block; - unsigned m_index; + unsigned m_recordIndex; + QString m_transactionIndex; QString m_contract; QString m_function; QString m_value; QString m_address; QString m_returned; + bool m_call; }; /** @@ -133,8 +137,8 @@ public slots: /// Setup state, run transaction sequence, show debugger for the last transaction /// @param _state JS object with state configuration void setupState(QVariantMap _state); - /// Show the debugger for a specified transaction - Q_INVOKABLE void debugTransaction(unsigned _block, unsigned _index); + /// Show the debugger for a specified record + Q_INVOKABLE void debugRecord(unsigned _index); private slots: /// Update UI with machine states result. Display a modal dialog. @@ -168,7 +172,7 @@ signals: /// @param _message RPC response in Json format void apiResponse(QString const& _message); /// New transaction log entry - void newTransaction(TransactionLogEntry* _tr); + void newRecord(RecordLogEntry* _r); /// State (transaction log) cleared void stateCleared(); diff --git a/mix/MachineStates.h b/mix/MachineStates.h index d19fd9b74..9506dcf63 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -61,7 +61,7 @@ namespace mix */ struct ExecutionResult { - ExecutionResult() : receipt(dev::h256(), dev::h256(), dev::eth::LogEntries()) {} + ExecutionResult(): transactionIndex(std::numeric_limits::max()) {} std::vector machineStates; std::vector transactionData; @@ -71,9 +71,11 @@ namespace mix dev::Address sender; dev::Address contractAddress; dev::u256 value; - dev::eth::TransactionReceipt receipt; + unsigned transactionIndex; + + bool isCall() const { return transactionIndex == std::numeric_limits::max(); } }; using ExecutionResults = std::vector; } -} \ No newline at end of file +} diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index f182211c9..b2a367929 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -15,7 +15,6 @@ along with cpp-ethereum. If not, see . */ /** @file MixClient.cpp - * @author Yann yann@ethdev.com * @author Arkadiy Paronyan arkadiy@ethdev.com * @date 2015 * Ethereum IDE client. @@ -90,11 +89,10 @@ void MixClient::resetState(u256 _balance) m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Empty); m_state.sync(bc()); m_startState = m_state; - m_pendingExecutions.clear(); m_executions.clear(); } -void MixClient::executeTransaction(Transaction const& _t, State& _state) +void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call) { bytes rlp = _t.rlp(); @@ -171,30 +169,33 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state) d.value = _t.value(); if (_t.isCreation()) d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); - d.receipt = TransactionReceipt(execState.rootHash(), execution.gasUsed(), execution.logs()); //TODO: track gas usage - m_pendingExecutions.emplace_back(std::move(d)); + if (!_call) + d.transactionIndex = m_state.pending().size(); + m_executions.emplace_back(std::move(d)); // execute on a state - _state.execute(lastHashes, rlp, nullptr, true); - - // collect watches - h256Set changed; - Guard l(m_filterLock); - for (std::pair& i: m_filters) - if ((unsigned)i.second.filter.latest() > bc().number()) - { - // acceptable number. - auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); - if (m.size()) + if (!_call) + { + _state.execute(lastHashes, rlp, nullptr, true); + // collect watches + h256Set changed; + Guard l(m_filterLock); + for (std::pair& i: m_filters) + if ((unsigned)i.second.filter.latest() > bc().number()) { - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); - changed.insert(i.first); + // acceptable number. + auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); + if (m.size()) + { + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); + changed.insert(i.first); + } } - } - changed.insert(dev::eth::PendingChangedFilter); - noteChanged(changed); + changed.insert(dev::eth::PendingChangedFilter); + noteChanged(changed); + } } void MixClient::mine() @@ -206,28 +207,18 @@ void MixClient::mine() bc().import(m_state.blockData(), m_stateDB); m_state.sync(bc()); m_startState = m_state; - m_executions.emplace_back(std::move(m_pendingExecutions)); h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; noteChanged(changed); } -ExecutionResult const& MixClient::execution(unsigned _block, unsigned _transaction) const -{ - if (_block == bc().number() + 1) - return m_pendingExecutions.at(_transaction); - return m_executions.at(_block - 1).at(_transaction); -} - ExecutionResult const& MixClient::lastExecution() const { - if (m_pendingExecutions.size() > 0) - return m_pendingExecutions.back(); - return m_executions.back().back(); + return m_executions.back(); } -ExecutionResults const& MixClient::pendingExecutions() const +ExecutionResults const& MixClient::executions() const { - return m_pendingExecutions; + return m_executions; } State MixClient::asOf(int _block) const @@ -246,7 +237,7 @@ void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - executeTransaction(t, m_state); + executeTransaction(t, m_state, false); } Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) @@ -254,7 +245,7 @@ Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init, WriteGuard l(x_state); u256 n = m_state.transactionsFrom(toAddress(_secret)); eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); - executeTransaction(t, m_state); + executeTransaction(t, m_state, false); Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); return address; } @@ -263,7 +254,7 @@ void MixClient::inject(bytesConstRef _rlp) { WriteGuard l(x_state); eth::Transaction t(_rlp, CheckSignature::None); - executeTransaction(t, m_state); + executeTransaction(t, m_state, false); } void MixClient::flushTransactions() @@ -282,8 +273,8 @@ bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _ Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, temp); - return m_pendingExecutions.back().returnValue; + executeTransaction(t, temp, true); + return lastExecution().returnValue; } u256 MixClient::balanceAt(Address _a, int _block) const diff --git a/mix/MixClient.h b/mix/MixClient.h index 9e376e5b1..9ec5ff659 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -45,9 +45,8 @@ public: void resetState(u256 _balance); KeyPair const& userAccount() const { return m_userAccount; } void mine(); - ExecutionResult const& execution(unsigned _block, unsigned _transaction) const; ExecutionResult const& lastExecution() const; - ExecutionResults const& pendingExecutions() const; + ExecutionResults const& executions() const; //dev::eth::Interface void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; @@ -90,7 +89,7 @@ public: bool submitNonce(h256 const&) override { return false; } private: - void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state); + void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); void noteChanged(h256Set const& _filters); dev::eth::State asOf(int _block) const; MixBlockChain& bc() { return *m_bc; } @@ -105,8 +104,7 @@ private: mutable std::mutex m_filterLock; std::map m_filters; std::map m_watches; - std::vector m_executions; - ExecutionResults m_pendingExecutions; + ExecutionResults m_executions; std::string m_dbPath; unsigned m_minigThreads; }; diff --git a/mix/qml/CallStack.qml b/mix/qml/CallStack.qml deleted file mode 100644 index 218c8c02e..000000000 --- a/mix/qml/CallStack.qml +++ /dev/null @@ -1,31 +0,0 @@ -import QtQuick 2.2 -import QtQuick.Controls.Styles 1.1 -import QtQuick.Controls 1.1 -import QtQuick.Layouts 1.1 - -Item { - property alias model: callTable.model - signal frameActivated(int index) - ColumnLayout { - anchors.fill: parent - Text { - text: qsTr("Call Stack") - Layout.fillWidth: true - } - TableView { - id: callTable - Layout.fillWidth: true - Layout.fillHeight: true - headerDelegate: null - - TableViewColumn { - role: "modelData" - title: qsTr("Address") - width: parent.width - } - onActivated: { - frameActivated(row); - } - } - } -} diff --git a/mix/qml/DebugInfoList.qml b/mix/qml/DebugInfoList.qml index 80c2d5509..c1ab11596 100644 --- a/mix/qml/DebugInfoList.qml +++ b/mix/qml/DebugInfoList.qml @@ -115,6 +115,7 @@ ColumnLayout { //storageContainer.state = ""; } } + onActivated: rowActivated(row); TableViewColumn { role: "modelData" width: parent.width diff --git a/mix/qml/TransactionLog.qml b/mix/qml/TransactionLog.qml index 970c4c21d..b31956898 100644 --- a/mix/qml/TransactionLog.qml +++ b/mix/qml/TransactionLog.qml @@ -5,6 +5,14 @@ import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 Item { + + property bool showLogs: true + property ListModel fullModel: ListModel{} + property ListModel transactionModel: ListModel{} + onShowLogsChanged: { + logTable.model = showLogs ? fullModel : transactionModel + } + Action { id: addStateAction text: "Add State" @@ -70,17 +78,13 @@ Item { } } TableView { + id: logTable Layout.fillWidth: true Layout.fillHeight: true - model: logModel + model: fullModel TableViewColumn { - role: "block" - title: qsTr("Block") - width: 40 - } - TableViewColumn { - role: "tindex" + role: "transactionIndex" title: qsTr("Index") width: 40 } @@ -110,30 +114,31 @@ Item { width: 120 } onActivated: { - var item = logModel.get(row); - clientModel.debugTransaction(item.block, item.tindex); + var item = logTable.model.get(row); + clientModel.debugRecord(item.recordIndex); } Keys.onPressed: { - if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logModel.count) { - var item = logModel.get(currentRow); + if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { + var item = logTable.model.get(currentRow); appContext.toClipboard(item.returned); } } } } - ListModel { - id: logModel - } - Connections { target: clientModel onStateCleared: { - logModel.clear(); + fullModel.clear(); + transactionModel.clear(); } - onNewTransaction: { + onNewRecord: { if (recording.checked) - logModel.append(_tr); + { + fullModel.append(_r); + if (!_r.call) + transactionModel.append(_r); + } } } diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 7998cbb20..ea5d6dd04 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -54,6 +54,7 @@ ApplicationWindow { MenuItem { action: toggleTransactionLogAction } MenuItem { action: toggleWebPreviewAction } MenuItem { action: toggleWebPreviewOrientationAction } + MenuItem { action: toggleCallsInLog } } } @@ -162,6 +163,15 @@ ApplicationWindow { onTriggered: mainContent.toggleWebPreviewOrientation(); } + Action { + id: toggleCallsInLog + text: qsTr("Show Calls in Transaction Log") + shortcut: "" + checkable: true + checked: mainContent.rightPane.transactionLog.showLogs + onTriggered: mainContent.rightPane.transactionLog.showLogs = !mainContent.rightPane.transactionLog.showLogs + } + Action { id: toggleRunOnLoadAction text: qsTr("Load State on Startup") diff --git a/mix/res.qrc b/mix/res.qrc index d17c32549..a33323870 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -61,7 +61,6 @@ stdc/std.sol qml/TransactionLog.qml res/mix_256x256x32.png - qml/CallStack.qml qml/QVariableDeclaration.qml qml/Style.qml qml/qmldir