Browse Source

Merge branch 'develop' into windows_debug

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
259443a653
  1. 16
      alethzero/MainWin.cpp
  2. 8
      alethzero/MainWin.h
  3. 60
      libdevcore/CommonJS.cpp
  4. 7
      libdevcore/CommonJS.h
  5. 4
      libethereum/Executive.h
  6. 18
      libevmcore/Instruction.h
  7. 86
      mix/AppContext.cpp
  8. 30
      mix/AppContext.h
  9. 103
      mix/AssemblyDebuggerCtrl.cpp
  10. 70
      mix/AssemblyDebuggerCtrl.h
  11. 120
      mix/AssemblyDebuggerModel.cpp
  12. 56
      mix/AssemblyDebuggerModel.h
  13. 22
      mix/CodeEditorExtensionManager.cpp
  14. 4
      mix/CodeEditorExtensionManager.h
  15. 17
      mix/ConstantCompilationCtrl.cpp
  16. 7
      mix/ConstantCompilationCtrl.h
  17. 6
      mix/ConstantCompilationModel.cpp
  18. 5
      mix/ConstantCompilationModel.h
  19. 158
      mix/DebuggingStateWrapper.cpp
  20. 139
      mix/DebuggingStateWrapper.h
  21. 49
      mix/Extension.cpp
  22. 23
      mix/Extension.h
  23. 29
      mix/KeyEventManager.cpp
  24. 42
      mix/KeyEventManager.h
  25. 2
      mix/MixApplication.cpp
  26. 1
      mix/MixApplication.h
  27. 40
      mix/TransactionBuilder.cpp
  28. 43
      mix/TransactionBuilder.h
  29. 9
      mix/main.cpp
  30. 5
      mix/qml.qrc
  31. 27
      mix/qml/AlertMessageDialog.qml
  32. 21
      mix/qml/BasicMessage.qml
  33. 232
      mix/qml/Debugger.qml
  34. 18
      mix/qml/MainContent.qml
  35. 27
      mix/qml/ModalDialog.qml
  36. 62
      mix/qml/js/Debugger.js
  37. 24
      mix/qml/main.qml

16
alethzero/MainWin.cpp

@ -65,7 +65,7 @@ static void initUnits(QComboBox* _b)
_b->addItem(QString::fromStdString(units()[n].second), n);
}
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr)
QString Main::fromRaw(dev::h256 _n, unsigned* _inc)
{
if (_n)
{
@ -149,7 +149,7 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->mineStatus);
statusBar()->addPermanentWidget(ui->blockCount);
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"}));
@ -173,17 +173,17 @@ Main::Main(QWidget *parent) :
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qweb));
connect(m_qweb, SIGNAL(onNewId(QString)), this, SLOT(addNewId(QString)));
});
connect(ui->webView, &QWebView::loadFinished, [=]()
{
m_qweb->poll();
});
connect(ui->webView, &QWebView::titleChanged, [=]()
{
ui->tabWidget->setTabText(0, ui->webView->title());
});
readSettings();
installWatches();
startTimer(100);
@ -1067,7 +1067,7 @@ void Main::timerEvent(QTimerEvent*)
// 7/18, Alex: aggregating timers, prelude to better threading?
// Runs much faster on slower dual-core processors
static int interval = 100;
// refresh mining every 200ms
if (interval / 100 % 2 == 0)
refreshMining();
@ -1093,7 +1093,7 @@ void Main::timerEvent(QTimerEvent*)
}
else
interval += 100;
if (m_qweb)
m_qweb->poll();
@ -1711,7 +1711,7 @@ void Main::on_net_triggered()
{
ui->port->setEnabled(!ui->net->isChecked());
ui->clientName->setEnabled(!ui->net->isChecked());
string n = string("AlethZero/v") + dev::Version;
string n = string("AlethZero/v") + dev::Version;
if (ui->clientName->text().size())
n += "/" + ui->clientName->text().toStdString();
n += "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM);

8
alethzero/MainWin.h

@ -69,7 +69,7 @@ struct WorldState
class Main : public QMainWindow
{
Q_OBJECT
public:
explicit Main(QWidget *parent = 0);
~Main();
@ -79,7 +79,7 @@ public:
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
public slots:
void load(QString _file);
void note(QString _entry);
@ -146,7 +146,7 @@ private slots:
void on_debugDumpState_triggered(int _add = 1);
void on_debugDumpStatePre_triggered();
void on_refresh_triggered();
void on_usePrivate_triggered();
void on_usePrivate_triggered();
void on_enableOptimizer_triggered();
void on_turboMining_triggered();
void on_go_triggered();
@ -259,4 +259,6 @@ private:
std::unique_ptr<QWebThreeConnector> m_qwebConnector;
std::unique_ptr<OurWebThreeStubServer> m_server;
QWebThree* m_qweb = nullptr;
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr);
};

60
libdevcore/CommonJS.cpp

@ -54,4 +54,64 @@ bytes unpadded(bytes _b)
return _b;
}
std::string prettyU256(u256 _n)
{
unsigned inc = 0;
std::string raw;
std::ostringstream s;
if (!(_n >> 64))
s << " " << (uint64_t)_n << " (0x" << (uint64_t)_n << ")";
else if (!~(_n >> 64))
s << " " << (int64_t)_n << " (0x" << (int64_t)_n << ")";
else if ((_n >> 160) == 0)
{
Address a = right160(_n);
std::string n = a.abridged();
if (n.empty())
s << "0x" << a;
else
s << n << "(0x" << a.abridged() << ")";
}
else if ((raw = fromRaw((h256)_n, &inc)).size())
return "\"" + raw + "\"" + (inc ? " + " + std::to_string(inc) : "");
else
s << "" << (h256)_n;
return s.str();
}
std::string fromRaw(h256 _n, unsigned* _inc)
{
if (_n)
{
std::string s((char const*)_n.data(), 32);
auto l = s.find_first_of('\0');
if (!l)
return "";
if (l != std::string::npos)
{
auto p = s.find_first_not_of('\0', l);
if (!(p == std::string::npos || (_inc && p == 31)))
return "";
if (_inc)
*_inc = (byte)s[31];
s.resize(l);
}
for (auto i: s)
if (i < 32)
return "";
return s;
}
return "";
}
Address fromString(std::string const& _sn)
{
if (_sn.size() == 40)
return Address(fromHex(_sn));
else
return Address();
}
}

7
libdevcore/CommonJS.h

@ -35,12 +35,12 @@ template <unsigned S> std::string toJS(FixedHash<S> const& _h)
{
return "0x" + toHex(_h.ref());
}
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n)
{
return "0x" + toHex(toCompactBigEndian(_n));
}
inline std::string toJS(dev::bytes const& _n)
{
return "0x" + dev::toHex(_n);
@ -49,6 +49,9 @@ inline std::string toJS(dev::bytes const& _n)
bytes jsToBytes(std::string const& _s);
bytes padded(bytes _b, unsigned _l);
bytes unpadded(bytes _s);
std::string prettyU256(u256 _n);
std::string fromRaw(h256 _n, unsigned* _inc = nullptr);
Address fromString(std::string const& _a);
template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{

4
libethereum/Executive.h

@ -113,8 +113,8 @@ private:
bool m_excepted = false; ///< True if the VM execution resulted in an exception.
u256 m_endGas; ///< The final amount of gas for the transaction.
Transaction m_t; ///< The original transaction in the case that setup() was called.
LogEntries m_logs; ///< The log entries created by this transaction. Only valid
Transaction m_t; ///< The original transaction. Set by setup().
LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize().
};
}

18
libevmcore/Instruction.h

@ -173,6 +173,24 @@ enum class Instruction: uint8_t
SUICIDE = 0xff ///< halt execution and register account for later deletion
};
/// @returns the number of PUSH Instruction _inst
inline unsigned getPushNumber(Instruction _inst)
{
return (byte)_inst - unsigned(Instruction::PUSH1) + 1;
}
/// @returns the number of DUP Instruction _inst
inline unsigned getDupNumber(Instruction _inst)
{
return (byte)_inst - unsigned(Instruction::DUP1) + 1;
}
/// @returns the number of SWAP Instruction _inst
inline unsigned getSwapNumber(Instruction _inst)
{
return (byte)_inst - unsigned(Instruction::SWAP1) + 1;
}
/// @returns the PUSH<_number> instruction
inline Instruction pushInstruction(unsigned _number)
{

86
mix/AppContext.cpp

@ -0,0 +1,86 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AppContext.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Provides access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* In the future this class can be extended to add more variable related to the context of the application.
* For now AppContext provides reference to:
* - QQmlApplicationEngine
* - dev::WebThreeDirect (and dev::eth::Client)
* - KeyEventManager
*/
#include <QDebug>
#include <QMessageBox>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include "libdevcrypto/FileSystem.h"
#include "KeyEventManager.h"
#include "AppContext.h"
using namespace dev;
using namespace dev::mix;
using namespace dev::eth;
AppContext* AppContext::Instance = nullptr;
AppContext::AppContext(QQmlApplicationEngine* _engine)
{
m_applicationEngine = std::unique_ptr<QQmlApplicationEngine>(_engine);
m_keyEventManager = std::unique_ptr<KeyEventManager>(new KeyEventManager());
m_webThree = std::unique_ptr<dev::WebThreeDirect>(new WebThreeDirect(std::string("Mix/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/Mix", false, {"eth", "shh"}));
}
QQmlApplicationEngine* AppContext::appEngine()
{
return m_applicationEngine.get();
}
dev::eth::Client* AppContext::getEthereumClient()
{
return m_webThree->ethereum();
}
void AppContext::initKeyEventManager(QObject* _res)
{
QObject* mainContent = _res->findChild<QObject*>("mainContent", Qt::FindChildrenRecursively);
if (mainContent)
QObject::connect(mainContent, SIGNAL(keyPressed(QVariant)), m_keyEventManager.get(), SLOT(keyPressed(QVariant)));
else
qDebug() << "Unable to find QObject of mainContent.qml. KeyEvent will not be handled!";
}
KeyEventManager* AppContext::getKeyEventManager()
{
return m_keyEventManager.get();
}
void AppContext::setApplicationContext(QQmlApplicationEngine* _engine)
{
if (Instance == nullptr)
Instance = new AppContext(_engine);
}
void AppContext::displayMessageDialog(QString _title, QString _message)
{
QObject* dialogWin = m_applicationEngine.get()->rootObjects().at(0)->findChild<QObject*>("alertMessageDialog", Qt::FindChildrenRecursively);
QObject* dialogWinComponent = m_applicationEngine.get()->rootObjects().at(0)->findChild<QObject*>("alertMessageDialogContent", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
dialogWinComponent->setProperty("source", QString("qrc:/qml/BasicMessage.qml"));
dialogWin->setProperty("title", _title);
dialogWin->setProperty("width", "250");
dialogWin->setProperty("height", "100");
dialogWin->findChild<QObject*>("messageContent", Qt::FindChildrenRecursively)->setProperty("text", _message);
QMetaObject::invokeMethod(dialogWin, "open");
}

30
mix/ApplicationCtx.h → mix/AppContext.h

@ -14,40 +14,52 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ApplicationCtx.h
/** @file AppContext.h
* @author Yann yann@ethdev.com
* @date 2014
* Provide an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* Provides access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* In the future this class can be extended to add more variable related to the context of the application.
* For now AppContext provides reference to:
* - QQmlApplicationEngine
* - dev::WebThreeDirect (and dev::eth::Client)
* - KeyEventManager
*/
#pragma once
#include <QQmlApplicationEngine>
#include "libwebthree/WebThree.h"
#include "KeyEventManager.h"
namespace dev
{
namespace mix
{
class ApplicationCtx: public QObject
class AppContext: public QObject
{
Q_OBJECT
public:
ApplicationCtx(QQmlApplicationEngine* _engine) { m_applicationEngine = _engine; }
~ApplicationCtx() { delete m_applicationEngine; }
static ApplicationCtx* getInstance() { return Instance; }
AppContext(QQmlApplicationEngine* _engine);
~AppContext() {}
static AppContext* getInstance() { return Instance; }
static void setApplicationContext(QQmlApplicationEngine* _engine);
QQmlApplicationEngine* appEngine();
dev::eth::Client* getEthereumClient();
void initKeyEventManager(QObject* _obj);
KeyEventManager* getKeyEventManager();
void displayMessageDialog(QString _title, QString _message);
private:
static ApplicationCtx* Instance;
QQmlApplicationEngine* m_applicationEngine;
static AppContext* Instance;
std::unique_ptr<QQmlApplicationEngine> m_applicationEngine;
std::unique_ptr<dev::WebThreeDirect> m_webThree;
std::unique_ptr<KeyEventManager> m_keyEventManager;
public slots:
void quitApplication() { delete Instance; }
void resourceLoaded(QObject* _obj, QUrl _url) { Q_UNUSED(_url); initKeyEventManager(_obj); }
};
}

103
mix/AssemblyDebuggerCtrl.cpp

@ -0,0 +1,103 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerCtrl.h
* @author Yann yann@ethdev.com
* @date 2014
* display opcode debugging.
*/
#include <QtConcurrent/QtConcurrent>
#include <QDebug>
#include <QQmlContext>
#include <QModelIndex>
#include "libethereum/Transaction.h"
#include "AssemblyDebuggerModel.h"
#include "AssemblyDebuggerCtrl.h"
#include "TransactionBuilder.h"
#include "KeyEventManager.h"
#include "AppContext.h"
#include "DebuggingStateWrapper.h"
using namespace dev::mix;
AssemblyDebuggerCtrl::AssemblyDebuggerCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::ModalDialog)
{
qRegisterMetaType<AssemblyDebuggerData>();
qRegisterMetaType<DebuggingStatusResult>();
connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList<QObject*>, AssemblyDebuggerData)),
this, SLOT(updateGUI(bool, DebuggingStatusResult, QList<QObject*>, AssemblyDebuggerData)), Qt::QueuedConnection);
m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
m_doc = _doc;
}
QString AssemblyDebuggerCtrl::contentUrl() const
{
return QStringLiteral("qrc:/qml/Debugger.qml");
}
QString AssemblyDebuggerCtrl::title() const
{
return QApplication::tr("debugger");
}
void AssemblyDebuggerCtrl::start() const
{
//start to listen on F5
m_ctx->getKeyEventManager()->registerEvent(this, SLOT(keyPressed(int)));
}
void AssemblyDebuggerCtrl::keyPressed(int _key)
{
if (_key == Qt::Key_F5)
{
QString code = m_doc->toPlainText();
QtConcurrent::run([this, code]()
{
if (!m_modelDebugger->compile(m_doc->toPlainText()))
{
emit dataAvailable(false, DebuggingStatusResult::Compilationfailed);
return;
}
u256 gasPrice = 10000000000000;
u256 gas = 1000000;
u256 amount = 100;
DebuggingContent debuggingContent = m_modelDebugger->getContractInitiationDebugStates(amount, gasPrice, gas, m_doc->toPlainText());
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.states.size(); i++)
{
DebuggingStateWrapper* s = new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes(), this);
s->setState(debuggingContent.states.at(i));
wStates.append(s);
}
AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode, this);
emit dataAvailable(true, DebuggingStatusResult::Ok, wStates, code);
});
}
}
void AssemblyDebuggerCtrl::updateGUI(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates, AssemblyDebuggerData _code)
{
Q_UNUSED(reason);
if (success)
{
m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates));
m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code)));
m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code)));
this->addContentOn(this);
}
else
m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("compilation failed"));
}

70
mix/AssemblyDebuggerCtrl.h

@ -0,0 +1,70 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerCtrl.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QKeySequence>
#include "QTextDocument"
#include "Extension.h"
#include "ConstantCompilationModel.h"
#include "AssemblyDebuggerModel.h"
#include "AppContext.h"
using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>;
enum DebuggingStatusResult
{
Ok,
Compilationfailed
};
Q_DECLARE_METATYPE(AssemblyDebuggerData)
Q_DECLARE_METATYPE(DebuggingStatusResult)
namespace dev
{
namespace mix
{
class AssemblyDebuggerCtrl: public Extension
{
Q_OBJECT
public:
AssemblyDebuggerCtrl(QTextDocument*);
~AssemblyDebuggerCtrl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
private:
std::unique_ptr<AssemblyDebuggerModel> m_modelDebugger;
QTextDocument* m_doc;
public slots:
void keyPressed(int);
void updateGUI(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates = QList<QObject*>(), AssemblyDebuggerData _code = AssemblyDebuggerData());
signals:
void dataAvailable(bool success, DebuggingStatusResult reason, QList<QObject*> _wStates = QList<QObject*>(), AssemblyDebuggerData _code = AssemblyDebuggerData());
};
}
}

120
mix/AssemblyDebuggerModel.cpp

@ -0,0 +1,120 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerModel.h
* @author Yann yann@ethdev.com
* @date 2014
* used as a model to debug contract assembly code.
*/
#include <QApplication>
#include <libdevcore/Common.h>
#include <libevm/VM.h>
#include <libethereum/Executive.h>
#include <libethereum/Transaction.h>
#include <libethereum/ExtVM.h>
#include "AppContext.h"
#include "TransactionBuilder.h"
#include "AssemblyDebuggerModel.h"
#include "ConstantCompilationModel.h"
#include "DebuggingStateWrapper.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
AssemblyDebuggerModel::AssemblyDebuggerModel():
m_userAccount(KeyPair::create()),
m_baseState(Address(), m_overlayDB, BaseState::Empty)
{
m_baseState.addBalance(m_userAccount.address(), 10000000 * ether);
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, 0));
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(dev::bytesConstRef _rawTransaction)
{
// Reset the state back to our clean premine.
m_executiveState = m_baseState;
QList<DebuggingState> states;
m_currentExecution->setup(_rawTransaction);
std::vector<DebuggingState const*> levels;
bytes code;
bytesConstRef data;
bool firstIteration = true;
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt)
{
VM& vm = *(VM*)voidVM;
ExtVM const& ext = *(ExtVM const*)voidExt;
if (firstIteration)
{
code = ext.code;
data = ext.data;
firstIteration = false;
}
if (levels.size() < ext.depth)
levels.push_back(&states.back());
else
levels.resize(ext.depth);
states.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
m_currentExecution->go(onOp);
cdebug << states.size();
m_currentExecution->finalize(onOp);
DebuggingContent d;
d.states = states;
d.executionCode = code;
d.executionData = data;
d.contentAvailable = true;
d.message = "ok";
return d;
}
DebuggingContent AssemblyDebuggerModel::getContractInitiationDebugStates(
dev::u256 _value,
dev::u256 _gasPrice,
dev::u256 _gas,
QString _code
)
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(_code);
if (!res.success)
{
DebuggingContent r;
r.contentAvailable = false;
r.message = QApplication::tr("compilation failed");
return r;
}
TransactionBuilder trBuild;
Transaction tr = trBuild.getCreationTransaction(_value, _gasPrice, min(_gas, m_baseState.gasLimitRemaining()), res.bytes,
m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
bytes b = tr.rlp();
dev::bytesConstRef bytesRef = &b;
return getContractInitiationDebugStates(bytesRef);
}
bool AssemblyDebuggerModel::compile(QString _code)
{
ConstantCompilationModel compiler;
CompilerResult res = compiler.compile(_code);
return res.success;
}

56
mix/AssemblyDebuggerModel.h

@ -0,0 +1,56 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerModel.h
* @author Yann yann@ethdev.com
* @date 2014
* serves as a model to debug contract assembly code.
*/
#pragma once
#include <QObject>
#include <QList>
#include <libdevcore/Common.h>
#include <libdevcrypto/Common.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include "DebuggingStateWrapper.h"
namespace dev
{
namespace mix
{
/**
* @brief Long-life object for managing all executions.
*/
class AssemblyDebuggerModel
{
public:
AssemblyDebuggerModel();
DebuggingContent getContractInitiationDebugStates(u256, u256, u256, QString);
DebuggingContent getContractInitiationDebugStates(bytesConstRef);
bool compile(QString);
private:
KeyPair m_userAccount;
OverlayDB m_overlayDB;
eth::State m_baseState;
eth::State m_executiveState;
std::unique_ptr<eth::Executive> m_currentExecution;
};
}
}

22
mix/CodeEditorExtensionManager.cpp

@ -27,7 +27,8 @@
#include <QQuickTextDocument>
#include <libevm/VM.h>
#include "ConstantCompilationCtrl.h"
#include "ApplicationCtx.h"
#include "AssemblyDebuggerCtrl.h"
#include "AppContext.h"
#include "CodeEditorExtensionManager.h"
using namespace dev::mix;
@ -58,22 +59,27 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
void CodeEditorExtensionManager::initExtensions()
{
//only one for now
std::shared_ptr<ConstantCompilationCtrl> constantCompilation = std::make_shared<ConstantCompilationCtrl>(m_doc);
if (constantCompilation.get()->contentUrl() != "")
initExtension(std::make_shared<ConstantCompilationCtrl>(m_doc));
initExtension(std::make_shared<AssemblyDebuggerCtrl>(m_doc));
}
void CodeEditorExtensionManager::initExtension(std::shared_ptr<Extension> _ext)
{
if (!_ext->contentUrl().isEmpty())
{
try
{
constantCompilation.get()->addContentOn(m_tabView);
if (_ext->getDisplayBehavior() == ExtensionDisplayBehavior::Tab)
_ext->addTabOn(m_tabView);
}
catch (...)
{
qDebug() << "Exception when adding content into view.";
qDebug() << "Exception when adding tab into view.";
return;
}
}
constantCompilation.get()->start();
m_features.append(constantCompilation);
_ext->start();
m_features.append(_ext);
}
void CodeEditorExtensionManager::setEditor(QQuickItem* _editor)

4
mix/CodeEditorExtensionManager.h

@ -30,7 +30,6 @@
namespace dev
{
namespace mix
{
@ -45,12 +44,13 @@ public:
CodeEditorExtensionManager() {}
~CodeEditorExtensionManager();
void initExtensions();
void initExtension(std::shared_ptr<Extension>);
void setEditor(QQuickItem*);
void setTabView(QQuickItem*);
private:
QQuickItem* m_editor;
QVector<std::shared_ptr<ConstantCompilationCtrl>> m_features;
QVector<std::shared_ptr<Extension>> m_features;
QQuickItem* m_tabView;
QTextDocument* m_doc;
void loadEditor(QQuickItem*);

17
mix/ConstantCompilationCtrl.cpp

@ -30,15 +30,10 @@
#include "ConstantCompilationModel.h"
using namespace dev::mix;
ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc)
ConstantCompilationCtrl::ConstantCompilationCtrl(QTextDocument* _doc): Extension(ExtensionDisplayBehavior::Tab)
{
m_editor = _doc;
m_compilationModel = new ConstantCompilationModel();
}
ConstantCompilationCtrl::~ConstantCompilationCtrl()
{
delete m_compilationModel;
m_compilationModel = std::unique_ptr<ConstantCompilationModel>(new ConstantCompilationModel());
}
QString ConstantCompilationCtrl::contentUrl() const
@ -48,7 +43,7 @@ QString ConstantCompilationCtrl::contentUrl() const
QString ConstantCompilationCtrl::title() const
{
return "compiler";
return QApplication::tr("compiler");
}
void ConstantCompilationCtrl::start() const
@ -64,7 +59,7 @@ void ConstantCompilationCtrl::compile()
resetOutPut();
return;
}
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText());
CompilerResult res = m_compilationModel->compile(m_editor->toPlainText().replace("\t", " "));
writeOutPut(res);
}
@ -85,13 +80,13 @@ void ConstantCompilationCtrl::writeOutPut(CompilerResult const& _res)
status->setProperty("text", "succeeded");
status->setProperty("color", "green");
content->setProperty("text", _res.hexCode);
qDebug() << QString("compile succeeded " + _res.hexCode);
qDebug() << QString(QApplication::tr("compile succeeded") + " " + _res.hexCode);
}
else
{
status->setProperty("text", "failure");
status->setProperty("color", "red");
content->setProperty("text", _res.comment);
qDebug() << QString("compile failed " + _res.comment);
qDebug() << QString(QApplication::tr("compile failed") + " " + _res.comment);
}
}

7
mix/ConstantCompilationCtrl.h

@ -25,7 +25,6 @@
namespace dev
{
namespace mix
{
@ -35,18 +34,18 @@ class ConstantCompilationCtrl: public Extension
public:
ConstantCompilationCtrl(QTextDocument*);
~ConstantCompilationCtrl();
~ConstantCompilationCtrl() {}
void start() const override;
QString title() const override;
QString contentUrl() const override;
private:
QTextDocument* m_editor;
ConstantCompilationModel* m_compilationModel;
std::unique_ptr<ConstantCompilationModel> m_compilationModel;
void writeOutPut(CompilerResult const&);
void resetOutPut();
public Q_SLOTS:
public slots:
void compile();
};

6
mix/ConstantCompilationModel.cpp

@ -20,6 +20,7 @@
* Ethereum IDE client.
*/
#include <QApplication>
#include <QObject>
#include <libevm/VM.h>
#include <libsolidity/Scanner.h>
@ -42,19 +43,20 @@ CompilerResult ConstantCompilationModel::compile(QString _code)
res.success = true;
res.comment = "ok";
res.hexCode = QString::fromStdString(dev::eth::disassemble(m_data));
res.bytes = m_data;
}
catch (dev::Exception const& _exception)
{
ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", compiler);
res.success = false;
res.comment = QString::fromStdString(error.str()).toHtmlEscaped();
res.comment = QString::fromStdString(error.str());
res.hexCode = "";
}
catch (...)
{
res.success = false;
res.comment = "Uncaught exception.";
res.comment = QApplication::tr("Uncaught exception.");
res.hexCode = "";
}
return res;

5
mix/ConstantCompilationModel.h

@ -22,11 +22,11 @@
#pragma once
#include <libevm/VM.h>
#include <QObject>
namespace dev
{
namespace mix
{
@ -34,6 +34,7 @@ struct CompilerResult
{
QString hexCode;
QString comment;
dev::bytes bytes;
bool success;
};
@ -43,7 +44,7 @@ class ConstantCompilationModel
public:
ConstantCompilationModel() {}
~ConstantCompilationModel() {}
CompilerResult compile(QString code);
CompilerResult compile(QString _code);
};
}

158
mix/DebuggingStateWrapper.cpp

@ -0,0 +1,158 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file DebuggingStateWrapper.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Used to translate c++ type (u256, bytes, ...) into friendly value (to be used by QML).
*/
#include <QApplication>
#include <QDebug>
#include "libevmcore/Instruction.h"
#include "libdevcore/CommonJS.h"
#include "libdevcrypto/Common.h"
#include "libevmcore/Instruction.h"
#include "libdevcore/Common.h"
#include "DebuggingStateWrapper.h"
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;
std::tuple<QList<QObject*>, QQMLMap*> DebuggingStateWrapper::getHumanReadableCode(const bytes& _code, QObject* _objUsedAsParent)
{
QList<QObject*> codeStr;
QMap<int, int> codeMapping;
for (unsigned i = 0; i <= _code.size(); ++i)
{
byte b = i < _code.size() ? _code[i] : 0;
try
{
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << std::hex << std::setw(4) << std::setfill('0') << i;
codeMapping[i] = codeStr.size();
int line = i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = getPushNumber((Instruction)b);
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc)));
i += bc;
}
HumanReadableCode* humanCode = new HumanReadableCode(QString::fromStdString(out.str()) + " " + s, line, _objUsedAsParent);
codeStr.append(humanCode);
}
catch (...)
{
qDebug() << QString("Unhandled exception!") << endl <<
QString::fromStdString(boost::current_exception_diagnostic_information());
break; // probably hit data segment
}
}
return std::make_tuple(codeStr, new QQMLMap(codeMapping, _objUsedAsParent));
}
QString DebuggingStateWrapper::gasLeft()
{
std::ostringstream ss;
ss << std::dec << (m_state.gas - m_state.gasCost);
return QString::fromStdString(ss.str());
}
QString DebuggingStateWrapper::gasCost()
{
std::ostringstream ss;
ss << std::dec << m_state.gasCost;
return QString::fromStdString(ss.str());
}
QString DebuggingStateWrapper::gas()
{
std::ostringstream ss;
ss << std::dec << m_state.gas;
return QString::fromStdString(ss.str());
}
QString DebuggingStateWrapper::debugStack()
{
QString stack;
for (auto i: m_state.stack)
stack.prepend(QString::fromStdString(prettyU256(i)) + "\n");
return stack;
}
QString DebuggingStateWrapper::debugStorage()
{
std::stringstream s;
for (auto const& i: m_state.storage)
s << "@" << prettyU256(i.first) << "&nbsp;&nbsp;&nbsp;&nbsp;" << prettyU256(i.second);
return QString::fromStdString(s.str());
}
QString DebuggingStateWrapper::debugMemory()
{
return QString::fromStdString(memDump(m_state.memory, 16, false));
}
QString DebuggingStateWrapper::debugCallData()
{
return QString::fromStdString(memDump(m_data, 16, false));
}
QStringList DebuggingStateWrapper::levels()
{
QStringList levelsStr;
for (unsigned i = 0; i <= m_state.levels.size(); ++i)
{
std::ostringstream out;
out << m_state.cur.abridged();
if (i)
out << " " << instructionInfo(m_state.inst).name << " @0x" << std::hex << m_state.curPC;
levelsStr.append(QString::fromStdString(out.str()));
}
return levelsStr;
}
QString DebuggingStateWrapper::headerInfo()
{
std::ostringstream ss;
ss << std::dec << " " << QApplication::tr("STEP").toStdString() << " : " << m_state.steps << " | PC: 0x" << std::hex << m_state.curPC << " : " << dev::eth::instructionInfo(m_state.inst).name << " | ADDMEM: " << std::dec << m_state.newMemSize << " " << QApplication::tr("words").toStdString() << " | " << QApplication::tr("COST").toStdString() << " : " << std::dec << m_state.gasCost << " | " << QApplication::tr("GAS").toStdString() << " : " << std::dec << m_state.gas;
return QString::fromStdString(ss.str());
}
QString DebuggingStateWrapper::endOfDebug()
{
if (m_state.gasCost > m_state.gas)
return QApplication::tr("OUT-OF-GAS");
else if (m_state.inst == Instruction::RETURN && m_state.stack.size() >= 2)
{
unsigned from = (unsigned)m_state.stack.back();
unsigned size = (unsigned)m_state.stack[m_state.stack.size() - 2];
unsigned o = 0;
bytes out(size, 0);
for (; o < size && from + o < m_state.memory.size(); ++o)
out[o] = m_state.memory[from + o];
return QApplication::tr("RETURN") + " " + QString::fromStdString(dev::memDump(out, 16, false));
}
else if (m_state.inst == Instruction::STOP)
return QApplication::tr("STOP");
else if (m_state.inst == Instruction::SUICIDE && m_state.stack.size() >= 1)
return QApplication::tr("SUICIDE") + " 0x" + QString::fromStdString(toString(right160(m_state.stack.back())));
else
return QApplication::tr("EXCEPTION");
}

139
mix/DebuggingStateWrapper.h

@ -0,0 +1,139 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file DebuggingStateWrapper.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QStringList>
#include "libethereum/State.h"
#include "libethereum/Executive.h"
#include "libdevcore/Common.h"
namespace dev
{
namespace mix
{
struct DebuggingState
{
uint64_t steps;
dev::Address cur;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<DebuggingState const*> levels;
};
struct DebuggingContent
{
QList<DebuggingState> states;
bytes executionCode;
bytesConstRef executionData;
bool contentAvailable;
QString message;
};
/**
* @brief Contains the line nb of the assembly code and the corresponding index in the code bytes array.
*/
class HumanReadableCode: public QObject
{
Q_OBJECT
Q_PROPERTY(QString line READ line)
Q_PROPERTY(int processIndex READ processIndex)
public:
HumanReadableCode(QString _line, int _processIndex, QObject* _parent): QObject(_parent), m_line(_line), m_processIndex(_processIndex) {}
QString line() { return m_line; }
int processIndex() { return m_processIndex; }
private:
QString m_line;
int m_processIndex;
};
/**
* @brief Publish QMap type to QML.
*/
class QQMLMap: public QObject
{
Q_OBJECT
public:
QQMLMap(QMap<int, int> _map, QObject* _parent): QObject(_parent), m_map(_map) { }
Q_INVOKABLE int getValue(int _key) { return m_map.value(_key); }
private:
QMap<int, int> m_map;
};
/**
* @brief Wrap DebuggingState in QObject
*/
class DebuggingStateWrapper: public QObject
{
Q_OBJECT
Q_PROPERTY(int step READ step)
Q_PROPERTY(int curPC READ curPC)
Q_PROPERTY(QString gasCost READ gasCost)
Q_PROPERTY(QString gas READ gas)
Q_PROPERTY(QString gasLeft READ gasLeft)
Q_PROPERTY(QString debugStack READ debugStack)
Q_PROPERTY(QString debugStorage READ debugStorage)
Q_PROPERTY(QString debugMemory READ debugMemory)
Q_PROPERTY(QString debugCallData READ debugCallData)
Q_PROPERTY(QString headerInfo READ headerInfo)
Q_PROPERTY(QString endOfDebug READ endOfDebug)
Q_PROPERTY(QStringList levels READ levels)
public:
DebuggingStateWrapper(bytes _code, bytes _data, QObject* _parent): QObject(_parent), m_code(_code), m_data(_data) {}
int step() { return (int)m_state.steps; }
int curPC() { return (int)m_state.curPC; }
QString gasLeft();
QString gasCost();
QString gas();
QString debugStack();
QString debugStorage();
QString debugMemory();
QString debugCallData();
QString headerInfo();
QString endOfDebug();
QStringList levels();
DebuggingState state() { return m_state; }
void setState(DebuggingState _state) { m_state = _state; }
static std::tuple<QList<QObject*>, QQMLMap*> getHumanReadableCode(bytes const& _code, QObject* _objUsedAsParent);
private:
DebuggingState m_state;
bytes m_code;
bytes m_data;
};
}
}

49
mix/Extension.cpp

@ -21,24 +21,57 @@
#include <QDebug>
#include <libevm/VM.h>
#include "Extension.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
using namespace dev;
using namespace dev::mix;
void Extension::addContentOn(QObject* _tabView)
Extension::Extension()
{
init();
}
Extension::Extension(ExtensionDisplayBehavior _displayBehavior)
{
init();
m_displayBehavior = _displayBehavior;
}
void Extension::init()
{
m_ctx = AppContext::getInstance();
m_appEngine = m_ctx->appEngine();
}
void Extension::addTabOn(QObject* _view)
{
if (contentUrl() == "")
return;
QVariant returnValue;
QQmlComponent* component = new QQmlComponent(
ApplicationCtx::getInstance()->appEngine(),
QUrl(this->contentUrl()), _tabView);
AppContext::getInstance()->appEngine(),
QUrl(contentUrl()), _view);
QMetaObject::invokeMethod(_tabView, "addTab",
Q_RETURN_ARG(QVariant, returnValue),
Q_ARG(QVariant, this->title()),
Q_ARG(QVariant, QVariant::fromValue(component)));
QMetaObject::invokeMethod(_view, "addTab",
Q_RETURN_ARG(QVariant, returnValue),
Q_ARG(QVariant, this->title()),
Q_ARG(QVariant, QVariant::fromValue(component)));
m_view = qvariant_cast<QObject*>(returnValue);
}
void Extension::addContentOn(QObject* _view)
{
Q_UNUSED(_view);
if (m_displayBehavior == ExtensionDisplayBehavior::ModalDialog)
{
QObject* dialogWin = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("dialog", Qt::FindChildrenRecursively);
QObject* dialogWinComponent = AppContext::getInstance()->appEngine()->rootObjects().at(0)->findChild<QObject*>("modalDialogContent", Qt::FindChildrenRecursively);
QMetaObject::invokeMethod(dialogWin, "close");
dialogWinComponent->setProperty("source", contentUrl());
dialogWin->setProperty("title", title());
QMetaObject::invokeMethod(dialogWin, "open");
}
//TODO add more view type.
}

23
mix/Extension.h

@ -21,26 +21,43 @@
#include <QApplication>
#include <QQmlComponent>
#include "AppContext.h"
namespace dev
{
namespace mix
{
enum ExtensionDisplayBehavior
{
Tab,
ModalDialog
};
class Extension: public QObject
{
Q_OBJECT
public:
Extension() {}
Extension();
Extension(ExtensionDisplayBehavior _displayBehavior);
virtual QString contentUrl() const { return ""; }
virtual QString title() const { return ""; }
virtual void start() const {}
void addContentOn(QObject* tabView);
void addContentOn(QObject* _tabView);
void addTabOn(QObject* _view);
void setDisplayBehavior(ExtensionDisplayBehavior _displayBehavior) { m_displayBehavior = _displayBehavior; }
ExtensionDisplayBehavior getDisplayBehavior() { return m_displayBehavior; }
protected:
QObject* m_view;
ExtensionDisplayBehavior m_displayBehavior;
AppContext* m_ctx;
QQmlApplicationEngine* m_appEngine;
private:
void init();
};
}

29
mix/ApplicationCtx.cpp → mix/KeyEventManager.cpp

@ -1,36 +1,41 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ApplicationCtx.cpp
/** @file KeyEventManager.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Provide an access to the current QQmlApplicationEngine which is used to add QML file on the fly.
* In the future this class can be extended to add more variable related to the context of the application.
* Used as an event handler for all classes which need keyboard interactions.
* Can be improve by adding the possibility to register to a specific key.
*/
#include <QQmlApplicationEngine>
#include "ApplicationCtx.h"
using namespace dev::mix;
#include <QDebug>
#include <QKeySequence>
#include "KeyEventManager.h"
ApplicationCtx* ApplicationCtx::Instance = nullptr;
void KeyEventManager::registerEvent(const QObject* _receiver, const char* _slot)
{
QObject::connect(this, SIGNAL(onKeyPressed(int)), _receiver, _slot);
}
QQmlApplicationEngine* ApplicationCtx::appEngine()
void KeyEventManager::unRegisterEvent(QObject* _receiver)
{
return m_applicationEngine;
QObject::disconnect(_receiver);
}
void ApplicationCtx::setApplicationContext(QQmlApplicationEngine* _engine)
void KeyEventManager::keyPressed(QVariant _event)
{
if (Instance == nullptr)
Instance = new ApplicationCtx(_engine);
emit onKeyPressed(_event.toInt());
}

42
mix/KeyEventManager.h

@ -0,0 +1,42 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file KeyEventManager.h
* @author Yann yann@ethdev.com
* @date 2014
* use as an event handler for all classes which need keyboard interactions
*/
#pragma once
#include <QObject>
class KeyEventManager: public QObject
{
Q_OBJECT
public:
KeyEventManager() {}
void registerEvent(const QObject* _receiver, const char* _slot);
void unRegisterEvent(QObject* _receiver);
signals:
void onKeyPressed(int);
public slots:
void keyPressed(QVariant _event);
};

2
mix/MixApplication.cpp

@ -23,7 +23,7 @@
#include "MixApplication.h"
using namespace dev::mix;
MixApplication::MixApplication(int _argc, char *_argv[]): QApplication(_argc, _argv)
MixApplication::MixApplication(int _argc, char* _argv[]): QApplication(_argc, _argv)
{
}

1
mix/MixApplication.h

@ -27,7 +27,6 @@
namespace dev
{
namespace mix
{

40
mix/TransactionBuilder.cpp

@ -0,0 +1,40 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TransactionBuilder.cpp
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#include "libethereum/Executive.h"
#include "libdevcore/CommonJS.h"
#include "libdevcore/Common.h"
#include "AppContext.h"
#include "TransactionBuilder.h"
using namespace dev::mix;
using namespace dev::eth;
using namespace dev;
Transaction TransactionBuilder::getCreationTransaction(u256 _value, u256 _gasPrice, u256 _gas,
bytes _data, u256 _nonce, Secret _secret) const
{
return Transaction(_value, _gasPrice, _gas, _data, _nonce, _secret);
}
Transaction TransactionBuilder::getBasicTransaction(u256 _value, u256 _gasPrice, u256 _gas,
QString _address, bytes _data, u256 _nonce, Secret _secret) const
{
return Transaction(_value, _gasPrice, _gas, dev::fromString(_address.toStdString()), _data, _nonce, _secret);
}

43
mix/TransactionBuilder.h

@ -0,0 +1,43 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file TransactionBuilder.h
* @author Yann yann@ethdev.com
* @date 2014
* Ethereum IDE client.
*/
#pragma once
#include <QString>
#include "libdevcore/Common.h"
#include "libethereum/Transaction.h"
namespace dev
{
namespace mix
{
class TransactionBuilder
{
public:
TransactionBuilder() {}
dev::eth::Transaction getBasicTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
QString address, bytes _data, dev::u256 _nonce, Secret _secret) const;
dev::eth::Transaction getCreationTransaction(dev::u256 _value, dev::u256 _gasPrice, dev::u256 _gas,
dev::bytes _data, dev::u256 _nonce, Secret _secret) const;
};
}
}

9
mix/main.cpp

@ -24,7 +24,7 @@
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "CodeEditorExtensionManager.h"
#include "ApplicationCtx.h"
#include "AppContext.h"
#include "MixApplication.h"
using namespace dev::mix;
@ -33,8 +33,9 @@ int main(int _argc, char *_argv[])
QApplication app(_argc, _argv);
qmlRegisterType<CodeEditorExtensionManager>("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager");
QQmlApplicationEngine* engine = new QQmlApplicationEngine();
ApplicationCtx::setApplicationContext(engine);
QObject::connect(&app, SIGNAL(lastWindowClosed()), ApplicationCtx::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff
engine->load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
AppContext::setApplicationContext(engine);
QObject::connect(&app, SIGNAL(lastWindowClosed()), AppContext::getInstance(), SLOT(quitApplication())); //use to kill ApplicationContext and other stuff
QObject::connect(engine, SIGNAL(objectCreated(QObject*, QUrl)), AppContext::getInstance(), SLOT(resourceLoaded(QObject*, QUrl)));
engine->load(QUrl("qrc:/qml/main.qml"));
return app.exec();
}

5
mix/qml.qrc

@ -4,5 +4,10 @@
<file>qml/main.qml</file>
<file>qml/MainContent.qml</file>
<file>qml/TabStyle.qml</file>
<file>qml/Debugger.qml</file>
<file>qml/js/Debugger.js</file>
<file>qml/BasicMessage.qml</file>
<file>qml/ModalDialog.qml</file>
<file>qml/AlertMessageDialog.qml</file>
</qresource>
</RCC>

27
mix/qml/AlertMessageDialog.qml

@ -0,0 +1,27 @@
import QtQuick 2.2
import QtQuick.Window 2.0
Window
{
id: alertMessageDialog
title: ""
modality: Qt.WindowModal
height: 150
width: 200
visible: false
Loader
{
focus: true
id: alertMessageDialogContent
objectName: "alertMessageDialogContent"
anchors.fill: parent
}
function open()
{
visible = true
}
function close()
{
visible = false
}
}

21
mix/qml/BasicMessage.qml

@ -0,0 +1,21 @@
import QtQuick 2.2
import QtQuick.Controls.Styles 1.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
Rectangle {
anchors.fill: parent
color: "lightgrey"
Label
{
width: parent.width
height: parent.height
horizontalAlignment: "AlignHCenter"
verticalAlignment: "AlignVCenter"
objectName: "messageContent"
id: messageTxt
text: ""
}
}

232
mix/qml/Debugger.qml

@ -0,0 +1,232 @@
import QtQuick 2.2
import QtQuick.Controls.Styles 1.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import "js/Debugger.js" as Debugger
Rectangle {
anchors.fill: parent;
color: "lightgrey"
Rectangle {
color: "transparent"
id: headerInfo
width: parent.width
height: 30
anchors.top: parent.top
Label {
anchors.centerIn: parent
font.family: "Verdana"
font.pointSize: 9
font.italic: true
id: headerInfoLabel
}
}
Keys.onPressed: {
if (event.key === Qt.Key_F10)
Debugger.moveSelection(1);
else if (event.key === Qt.Key_F9)
Debugger.moveSelection(-1);
}
Rectangle {
color: "transparent"
id: stateListContainer
focus: true
anchors.topMargin: 10
anchors.top: headerInfo.bottom
anchors.left: parent.left
height: parent.height - 30
width: parent.width * 0.5
ListView {
anchors.top: parent.top
height: parent.height * 0.60
width: 200
anchors.horizontalCenter: parent.horizontalCenter
id: statesList
Component.onCompleted: Debugger.init();
model: humanReadableExecutionCode
delegate: renderDelegate
highlight: highlightBar
highlightFollowsCurrentItem: true
}
Component {
id: highlightBar
Rectangle {
height: statesList.currentItem.height
width: statesList.currentItem.width
border.color: "orange"
border.width: 1
Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } }
}
}
Component {
id: renderDelegate
Item {
id: wrapperItem
height: 20
width: parent.width
Text {
anchors.centerIn: parent
text: line
font.pointSize: 9
}
}
}
Rectangle {
id: callStackPanel
anchors.top: statesList.bottom
height: parent.height * 0.35
width: parent.width
anchors.topMargin: 15
color: "transparent"
Label {
id: callStackLabel
anchors.bottomMargin: 10
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
font.letterSpacing: 2
width: parent.width
height: 15
text: "callstack"
}
ListView {
height: parent.height - 15
width: 200
anchors.top: callStackLabel.bottom
anchors.horizontalCenter: parent.horizontalCenter
id: levelList
delegate: Component {
Item {
Text {
font.family: "Verdana"
font.pointSize: 8
text: modelData
}
}
}
}
}
}
Rectangle {
color: "transparent"
anchors.topMargin: 5
anchors.bottomMargin: 10
anchors.rightMargin: 10
height: parent.height - 30
width: parent.width * 0.5
anchors.right: parent.right
anchors.top: headerInfo.bottom
anchors.bottom: parent.bottom
Rectangle {
id: debugStack
anchors.top: parent.top
width: parent.width
height: parent.height * 0.25
color: "transparent"
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
width: parent.width
height: 15
anchors.top : parent.top
text: "debug stack"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
font.family: "Verdana"
font.pointSize: 8
height: parent.height - 15
id:debugStackTxt
readOnly: true;
}
}
Rectangle {
id: debugMemory
anchors.top: debugStack.bottom
width: parent.width
height: parent.height * 0.25
color: "transparent"
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
width: parent.width
height: 15
anchors.top : parent.top
text: "debug memory"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
font.family: "Verdana"
font.pointSize: 8
height: parent.height - 15
id: debugMemoryTxt
readOnly: true;
}
}
Rectangle {
id: debugStorage
anchors.top: debugMemory.bottom
width: parent.width
height: parent.height * 0.25
color: "transparent"
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
width: parent.width
height: 15
anchors.top : parent.top
text: "debug storage"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
font.family: "Verdana"
font.pointSize: 8
height: parent.height - 15
id:debugStorageTxt
readOnly: true;
}
}
Rectangle {
id: debugCallData
anchors.top: debugStorage.bottom
width: parent.width
height: parent.height * 0.25
color: "transparent"
Label {
horizontalAlignment: "AlignHCenter"
font.family: "Verdana"
font.pointSize: 8
width: parent.width
height: 15
anchors.top : parent.top
text: "debug calldata"
}
TextArea {
anchors.bottom: parent.bottom
width: parent.width
height: parent.height - 15
id: debugCallDataTxt
readOnly: true;
}
}
}
}

18
mix/qml/MainContent.qml

@ -5,6 +5,14 @@ import QtQuick.Controls.Styles 1.1
import CodeEditorExtensionManager 1.0
Rectangle {
objectName: "mainContent"
signal keyPressed(variant event)
focus: true
Keys.enabled: true
Keys.onPressed:
{
root.keyPressed(event.key);
}
anchors.fill: parent
height: parent.height
width: parent.width;
@ -26,11 +34,11 @@ Rectangle {
anchors.centerIn: parent
tabChangesFocus: false
Keys.onPressed: {
if (event.key === Qt.Key_Tab) {
codeEditor.insert(codeEditor.cursorPosition, "\t");
event.accepted = true;
if (event.key === Qt.Key_Tab) {
codeEditor.insert(codeEditor.cursorPosition, "\t");
event.accepted = true;
}
}
}
}
}
Rectangle {
@ -46,7 +54,7 @@ Rectangle {
style: TabStyle {}
}
}
CodeEditorExtensionManager{
CodeEditorExtensionManager {
tabView: contextualTabs
editor: codeEditor
}

27
mix/qml/ModalDialog.qml

@ -0,0 +1,27 @@
import QtQuick 2.2
import QtQuick.Window 2.0
Window
{
id: modalDialog
title: ""
modality: Qt.WindowModal
height: 400
width: 700
visible: false
Loader
{
focus: true
id: modalDialogContent
objectName: "modalDialogContent"
anchors.fill: parent
}
function open()
{
visible = true
}
function close()
{
visible = false
}
}

62
mix/qml/js/Debugger.js

@ -0,0 +1,62 @@
//humanReadableExecutionCode => contain human readable code.
//debugStates => contain all debug states.
//bytesCodeMapping => mapping between humanReadableExecutionCode and bytesCode.
//statesList => ListView
var currentSelectedState = null;
function init()
{
currentSelectedState = 0;
select(currentSelectedState);
}
function moveSelection(incr)
{
if (currentSelectedState + incr >= 0)
{
if (currentSelectedState + incr < debugStates.length)
{
select(currentSelectedState + incr);
}
else
{
endOfDebug();
}
}
}
function select(stateIndex)
{
var state = debugStates[stateIndex];
var codeStr = bytesCodeMapping.getValue(state.curPC);
highlightSelection(codeStr);
currentSelectedState = codeStr;
completeCtxInformation(state);
levelList.model = state.levels;
levelList.update();
}
function highlightSelection(index)
{
console.log(index);
statesList.currentIndex = index;
}
function completeCtxInformation(state)
{
debugStackTxt.text = state.debugStack;
debugStorageTxt.text = state.debugStorage;
debugMemoryTxt.text = state.debugMemory;
debugCallDataTxt.text = state.debugCallData;
headerInfoLabel.text = state.headerInfo
}
function endOfDebug()
{
var state = debugStates[debugStates.length - 1];
debugStorageTxt.text = "";
debugCallDataTxt.text = "";
debugStackTxt.text = "";
debugMemoryTxt.text = state.endOfDebug;
headerInfoLabel.text = "EXIT | GAS: " + state.gasLeft;
}

24
mix/qml/main.qml

@ -1,15 +1,22 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import CodeEditorExtensionManager 1.0
ApplicationWindow {
id: mainApplication
visible: true
width: 1000
height: 480
x: Screen.width / 2 - width / 2
y: Screen.height / 2 - height / 2
width: 1200
height: 600
minimumWidth: 400
minimumHeight: 300
title: qsTr("mix")
menuBar: MenuBar {
Menu {
title: qsTr("File")
@ -19,6 +26,17 @@ ApplicationWindow {
}
}
}
MainContent{
MainContent {
}
ModalDialog {
objectName: "dialog"
id: dialog
}
AlertMessageDialog {
objectName: "alertMessageDialog"
id: messageDialog
}
}

Loading…
Cancel
Save