From 2321f2914ba2b5023332ae80a7346352bcc7220b Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 25 Mar 2015 12:58:06 +0100 Subject: [PATCH 1/6] - bugfix: #1397. - Debugger panel: UI bug fixes. --- mix/ContractCallDataEncoder.cpp | 16 ++++++++++------ mix/qml/QHashTypeView.qml | 1 - mix/qml/QIntTypeView.qml | 1 - mix/qml/QStringTypeView.qml | 1 - mix/qml/StructView.qml | 11 ++++++----- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index fc5dcee03..6553244dc 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -76,18 +76,22 @@ unsigned ContractCallDataEncoder::encodeSingleItem(QVariant const& _data, Solidi unsigned const alignSize = 32; QString src = _data.toString(); bytes result; - if (src.length() >= 2 && ((src.startsWith("\"") && src.endsWith("\"")) || (src.startsWith("\'") && src.endsWith("\'")))) - { + + if ((src.startsWith("\"") && src.endsWith("\"")) || (src.startsWith("\'") && src.endsWith("\'"))) src = src.remove(src.length() - 1, 1).remove(0, 1); - QByteArray bytesAr = src.toLocal8Bit(); - result = bytes(bytesAr.begin(), bytesAr.end()); - } - else if (src.startsWith("0x")) + + QRegExp rx("[a-z]+"); + if (src.startsWith("0x")) { result = fromHex(src.toStdString().substr(2)); if (_type.type != SolidityType::Type::Bytes) result = padded(result, alignSize); } + else if (rx.indexIn(src.toLower(), 0) != -1) + { + QByteArray bytesAr = src.toLocal8Bit(); + result = bytes(bytesAr.begin(), bytesAr.end()); + } else { bigint i(src.toStdString()); diff --git a/mix/qml/QHashTypeView.qml b/mix/qml/QHashTypeView.qml index 77da45365..a097c22dd 100644 --- a/mix/qml/QHashTypeView.qml +++ b/mix/qml/QHashTypeView.qml @@ -15,7 +15,6 @@ Item Rectangle { anchors.fill: parent radius: 4 - color: "#f7f7f7" TextInput { id: textinput text: value diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml index 206b641f3..8adb46846 100644 --- a/mix/qml/QIntTypeView.qml +++ b/mix/qml/QIntTypeView.qml @@ -16,7 +16,6 @@ Item Rectangle { anchors.fill: parent radius: 4 - color: "#f7f7f7" TextInput { id: textinput text: value diff --git a/mix/qml/QStringTypeView.qml b/mix/qml/QStringTypeView.qml index 0cde9b662..ffbde734c 100644 --- a/mix/qml/QStringTypeView.qml +++ b/mix/qml/QStringTypeView.qml @@ -15,7 +15,6 @@ Item Rectangle { anchors.fill: parent radius: 4 - color: "#f7f7f7" TextInput { id: textinput text: value diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 312a24804..045b2eabc 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -24,24 +24,24 @@ Column height: 20 id: typeLabel text: modelData.type.name - Layout.preferredWidth: 60 + anchors.verticalCenter: parent.verticalCenter } DefaultLabel { id: nameLabel text: modelData.name - Layout.preferredWidth: 100 + anchors.verticalCenter: parent.verticalCenter } DefaultLabel { id: equalLabel text: "=" - Layout.preferredWidth: 15 + anchors.verticalCenter: parent.verticalCenter } Loader { id: typeLoader - Layout.preferredWidth: 150 + anchors.verticalCenter: parent.verticalCenter sourceComponent: { var t = modelData.type.category; @@ -63,7 +63,8 @@ Column var ptype = members[index].type; var pname = members[index].name; var vals = value; - if (ptype.category === QSolidityType.Struct && !item.members) { + if (ptype.category === QSolidityType.Struct && !item.members) + { item.value = getValue(); item.members = ptype.members; } From 5b18f853b7d645734884545ecf849030d1ad12d6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 25 Mar 2015 15:28:23 +0100 Subject: [PATCH 2/6] - bug fix: #1399 --- mix/MixClient.cpp | 11 ++++++----- mix/MixClient.h | 2 +- mix/qml/html/WebContainer.html | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index fd7b2263d..0272cc129 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -89,6 +89,7 @@ void MixClient::resetState(std::map _accounts) SecureTrieDB accountState(&m_stateDB); accountState.init(); + m_userAccounts.clear(); std::map genesisState; for (auto account: _accounts) { @@ -243,15 +244,15 @@ ExecutionResult MixClient::execution(unsigned _index) const return m_executions.at(_index); } -State MixClient::asOf(int _block) const +State MixClient::asOf(BlockNumber _h) const { ReadGuard l(x_state); - if (_block == 0) - return m_state; - else if (_block == -1) + if (_h == PendingBlock) return m_startState; + else if (_h == LatestBlock) + return m_state; else - return State(m_stateDB, bc(), bc().numberHash(_block)); + return State(m_stateDB, bc(), bc().numberHash(_h)); } void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) diff --git a/mix/MixClient.h b/mix/MixClient.h index e1085a20e..4c45e3162 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -100,7 +100,7 @@ public: private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); void noteChanged(h256Set const& _filters); - dev::eth::State asOf(int _block) const; + dev::eth::State asOf(eth::BlockNumber _block) const; MixBlockChain& bc() { return *m_bc; } MixBlockChain const& bc() const { return *m_bc; } diff --git a/mix/qml/html/WebContainer.html b/mix/qml/html/WebContainer.html index fb716507f..dfce64979 100644 --- a/mix/qml/html/WebContainer.html +++ b/mix/qml/html/WebContainer.html @@ -23,9 +23,9 @@ updateContracts = function(contracts) { var contractProto = window.web3.eth.contract(contracts[c].interface); var contract = new contractProto(contracts[c].address); window.contracts[c] = { - address: c.address, - interface: c.interface, - contract: contract, + address: contracts[c].address, + interface: contracts[c].interface, + contract: contract }; } } From 568146724726cde36f769c7dfefdb36ed835754b Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Mar 2015 14:42:28 +0100 Subject: [PATCH 3/6] - Hide mapping type from debugger. - Better highlighting if debugger in external source. - Always use pendingBlock when making call and transact MixClient. - Compilation errors not kept in logs history. --- mix/ClientModel.cpp | 11 ++++++----- mix/DebuggingStateWrapper.h | 6 ++++-- mix/MixClient.cpp | 16 ++++++---------- mix/MixClient.h | 3 --- mix/qml/CodeEditorView.qml | 21 ++++++++++++++++++++- mix/qml/LogsPane.qml | 25 ------------------------- mix/qml/StatusPane.qml | 1 - 7 files changed, 36 insertions(+), 47 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index b490661ae..082ff59e6 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -350,10 +350,6 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) CompiledContract const* contract = contracts[s.codeIndex]; AssemblyItem const& instruction = codeItems[s.codeIndex][instructionIndex]; - std::stringstream str; - str << instruction.getLocation().sourceName; - qDebug() << QString::fromStdString(str.str()); - if (instruction.type() == dev::eth::Push && !instruction.data()) { //register new local variable initialization @@ -380,8 +376,11 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) for(auto l: solLocals) if (l.first < (int)s.stack.size()) { + if (l.second->type()->name().startsWith("mapping")) + break; //mapping type not yet managed localDeclarations.push_back(QVariant::fromValue(l.second)); localValues[l.second->name()] = formatValue(l.second->type()->type(), s.stack[l.first]); + } locals["variables"] = localDeclarations; locals["values"] = localValues; @@ -404,6 +403,8 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) storageDec = new QVariableDeclaration(debugData, storageIter.value().name.toStdString(), storageIter.value().type); storageDeclarations[storageDec->name()] = storageDec; } + if (storageDec->type()->name().startsWith("mapping")) + break; //mapping type not yet managed storageDeclarationList.push_back(QVariant::fromValue(storageDec)); storageValues[storageDec->name()] = formatValue(storageDec->type()->type(), st.second); } @@ -412,7 +413,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) storage["values"] = storageValues; prevInstructionIndex = instructionIndex; - solState = new QSolState(debugData, std::move(storage), std::move(solCallStack), std::move(locals), instruction.getLocation().start, instruction.getLocation().end); + solState = new QSolState(debugData, std::move(storage), std::move(solCallStack), std::move(locals), instruction.getLocation().start, instruction.getLocation().end, QString::fromUtf8(instruction.getLocation().sourceName->c_str())); } states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState))); diff --git a/mix/DebuggingStateWrapper.h b/mix/DebuggingStateWrapper.h index b9eea9365..37bc194fb 100644 --- a/mix/DebuggingStateWrapper.h +++ b/mix/DebuggingStateWrapper.h @@ -65,10 +65,11 @@ class QSolState: public QObject Q_PROPERTY(QVariantMap locals MEMBER m_locals CONSTANT) Q_PROPERTY(int start MEMBER m_start CONSTANT) Q_PROPERTY(int end MEMBER m_end CONSTANT) + Q_PROPERTY(QString sourceName MEMBER m_sourceName CONSTANT) public: - QSolState(QObject* _parent, QVariantMap&& _storage, QVariantList&& _callStack, QVariantMap&& _locals, int _start, int _end): - QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end) + QSolState(QObject* _parent, QVariantMap&& _storage, QVariantList&& _callStack, QVariantMap&& _locals, int _start, int _end, QString _sourceName): + QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end), m_sourceName(_sourceName) { } private: @@ -77,6 +78,7 @@ private: QVariantMap m_locals; int m_start; int m_end; + QString m_sourceName; }; /** diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 47983822a..19d946d01 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -235,15 +235,10 @@ ExecutionResult MixClient::execution(unsigned _index) const return m_executions.at(_index); } -State MixClient::asOf(BlockNumber _h) const +State MixClient::asOf(h256 const& _block) const { ReadGuard l(x_state); - if (_h == PendingBlock) - return m_startState; - else if (_h == LatestBlock) - return m_state; - else - return State(m_stateDB, bc(), bc().numberHash(_h)); + return State(m_stateDB, bc(), _block); } void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) @@ -266,8 +261,8 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) { - - State temp = asOf(_blockNumber); + (void)_blockNumber; + State temp = asOf(eth::PendingBlock); u256 n = temp.transactionsFrom(toAddress(_secret)); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); bytes rlp = t.rlp(); @@ -278,11 +273,12 @@ dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _ dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) { + (void)_blockNumber; u256 n; State temp; { ReadGuard lr(x_state); - temp = asOf(_blockNumber); + temp = asOf(eth::PendingBlock); n = temp.transactionsFrom(toAddress(_secret)); } Transaction t(_value, _gasPrice, _gas, _data, n, _secret); diff --git a/mix/MixClient.h b/mix/MixClient.h index a25657905..179b445ac 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -88,9 +88,6 @@ protected: private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); void noteChanged(h256Set const& _filters); - dev::eth::State asOf(eth::BlockNumber _block) const; - MixBlockChain& bc() { return *m_bc; } - MixBlockChain const& bc() const { return *m_bc; } std::vector m_userAccounts; eth::State m_state; diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 4d8559200..01aa0955f 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -68,9 +68,28 @@ Item { } function highlightExecution(documentId, location) { + var editor = getEditor(documentId); if (editor) - editor.highlightExecution(location); + { + if (documentId !== location.sourceName) + findAndHightlight(location.start, location.end, location.sourceName) + else + editor.highlightExecution(location); + } + } + + // Execution is not in the current document. Try: + // Open targeted document and hightlight (TODO) or + // Relevant hightlighting on the current document + function findAndHightlight(start, end, sourceName) + { + var editor = getEditor(currentDocumentId); + if (editor) + { + var sourceIndex = editor.getText().indexOf(sourceName); + highlightExecution(currentDocumentId, { start: sourceIndex, end: sourceIndex + sourceName.length, sourceName: currentDocumentId }); + } } function editingContract() { diff --git a/mix/qml/LogsPane.qml b/mix/qml/LogsPane.qml index b40dfc4c7..3601483a0 100644 --- a/mix/qml/LogsPane.qml +++ b/mix/qml/LogsPane.qml @@ -153,31 +153,6 @@ Rectangle } } - ToolButton { - id: compilationButton - checkable: true - height: LogsPaneStyle.generic.layout.headerButtonHeight - anchors.verticalCenter: parent.verticalCenter - checked: false - onCheckedChanged: { - proxyModel.toogleFilter("compilation") - } - tooltip: qsTr("Compilation") - style: - ButtonStyle { - label: - Item { - DefaultLabel { - font.family: LogsPaneStyle.generic.layout.logLabelFont - font.pointSize: Style.absoluteSize(-3) - color: "#5391d8" - anchors.centerIn: parent - text: qsTr("Compilation") - } - } - } - } - DefaultTextField { id: searchBox diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 6d4b5e7e1..1e440b3a8 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -24,7 +24,6 @@ Rectangle { var errorInfo = ErrorLocationFormater.extractErrorInfo(message, true); status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail; debugImg.state = ""; - errorMessage(status.text, "Compilation"); } debugRunActionIcon.enabled = codeModel.hasContract; } From 55e34ddadecca5f8d24f6f3b14a080a3f4129d04 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Mar 2015 15:22:16 +0100 Subject: [PATCH 4/6] - warn user if source not available --- mix/qml/CodeEditorView.qml | 11 ++++------- mix/qml/WebCodeEditor.qml | 5 +++++ mix/qml/html/codeeditor.js | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 01aa0955f..f948f882c 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -67,8 +67,8 @@ Item { return null; } - function highlightExecution(documentId, location) { - + function highlightExecution(documentId, location) + { var editor = getEditor(documentId); if (editor) { @@ -81,15 +81,12 @@ Item { // Execution is not in the current document. Try: // Open targeted document and hightlight (TODO) or - // Relevant hightlighting on the current document + // Warn user that file is not available function findAndHightlight(start, end, sourceName) { var editor = getEditor(currentDocumentId); if (editor) - { - var sourceIndex = editor.getText().indexOf(sourceName); - highlightExecution(currentDocumentId, { start: sourceIndex, end: sourceIndex + sourceName.length, sourceName: currentDocumentId }); - } + editor.showWarning(qsTr("Currently debugging in " + sourceName + ". Source not available.")); } function editingContract() { diff --git a/mix/qml/WebCodeEditor.qml b/mix/qml/WebCodeEditor.qml index 7e5945fc7..3313cd2dd 100644 --- a/mix/qml/WebCodeEditor.qml +++ b/mix/qml/WebCodeEditor.qml @@ -45,6 +45,11 @@ Item { editorBrowser.runJavaScript("highlightExecution(" + location.start + "," + location.end + ")"); } + function showWarning(content) { + if (initialized) + editorBrowser.runJavaScript("showWarning('" + content + "')"); + } + function getBreakpoints() { return currentBreakpoints; } diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index daf1286d8..da87e63e0 100644 --- a/mix/qml/html/codeeditor.js +++ b/mix/qml/html/codeeditor.js @@ -134,6 +134,8 @@ highlightExecution = function(start, end) { executionMark.clear(); if (start === 0 && end + 1 === editor.getValue().length) return; // Do not hightlight the whole document. + if (debugWarning) + debugWarning.clear(); executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" }); } @@ -148,6 +150,20 @@ isClean = function() return editor.isClean(changeId); } +var debugWarning = null; +showWarning = function(content) +{ + if (executionMark) + executionMark.clear(); + if (debugWarning) + debugWarning.clear(); + var node = document.createElement("div"); + node.id = "annotation" + node.innerHTML = content; + node.className = "CodeMirror-errorannotation-context"; + debugWarning = editor.addLineWidget(0, node, { coverGutter: false, above: true }); +} + var annotation = null; var compilationCompleteBool = true; compilationError = function(line, column, content) From 6bdb3ed08008e1457acdab6f929d91c451bbde96 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Mar 2015 15:25:46 +0100 Subject: [PATCH 5/6] small changes --- mix/ClientModel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 082ff59e6..a49ee3661 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -380,7 +380,6 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) break; //mapping type not yet managed localDeclarations.push_back(QVariant::fromValue(l.second)); localValues[l.second->name()] = formatValue(l.second->type()->type(), s.stack[l.first]); - } locals["variables"] = localDeclarations; locals["values"] = localValues; From c17edbff0a7c5e01b1b4a2a9d51112a9a6127a66 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 26 Mar 2015 16:41:23 +0100 Subject: [PATCH 6/6] - bug fix #1386 --- mix/ClientModel.cpp | 15 ++++++++++++--- mix/qml/StatusPane.qml | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index a49ee3661..6ba7e54f9 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -242,7 +242,12 @@ void ClientModel::executeSequence(std::vector const& _seque break; } if (!f) - BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString())); + { + emit runFailed("Function '" + transaction.functionId + tr("' not found. Please check transactions or the contract code.")); + m_running = false; + emit runStateChanged(); + return; + } if (!transaction.functionId.isEmpty()) encoder.encode(f); for (QVariableDeclaration const* p: f->parametersList()) @@ -269,7 +274,12 @@ void ClientModel::executeSequence(std::vector const& _seque { auto contractAddressIter = m_contractAddresses.find(transaction.contractId); if (contractAddressIter == m_contractAddresses.end()) - BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Contract not deployed: " + transaction.contractId.toStdString())); + { + emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); + m_running = false; + emit runStateChanged(); + return; + } callContract(contractAddressIter->second, encoder.encodedData(), transaction); } } @@ -283,7 +293,6 @@ void ClientModel::executeSequence(std::vector const& _seque std::cerr << boost::current_exception_diagnostic_information(); emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } - catch(std::exception const& e) { std::cerr << boost::current_exception_diagnostic_information(); diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 1e440b3a8..70a4b1d30 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -76,9 +76,9 @@ Rectangle { function format(_message) { var formatted = _message.match(/(?:)/); - if (formatted === null) + if (formatted) formatted = _message.match(/(?:)/); - if (formatted.length > 1) + if (formatted && formatted.length > 1) formatted = formatted[1]; else return _message;