Browse Source

improved debugging model

cl-refactor
arkpar 10 years ago
parent
commit
50a1edb23b
  1. 172
      mix/AssemblyDebuggerControl.cpp
  2. 33
      mix/AssemblyDebuggerControl.h
  3. 27
      mix/AssemblyDebuggerModel.cpp
  4. 6
      mix/AssemblyDebuggerModel.h
  5. 4
      mix/CodeEditorExtensionManager.cpp
  6. 12
      mix/CodeModel.cpp
  7. 22
      mix/CodeModel.h
  8. 11
      mix/ConstantCompilationControl.cpp
  9. 1
      mix/ConstantCompilationControl.h
  10. 2
      mix/MixApplication.cpp
  11. 13
      mix/qml/StateList.qml
  12. 7
      mix/qml/main.qml

172
mix/AssemblyDebuggerControl.cpp

@ -22,6 +22,8 @@
#include <libsolidity/Token.h> #include <libsolidity/Token.h>
#include <libsolidity/Types.h> #include <libsolidity/Types.h>
#include <utility> #include <utility>
#include <stdexcept>
#include <boost/exception/diagnostic_information.hpp>
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include <QDebug> #include <QDebug>
#include <QQmlContext> #include <QQmlContext>
@ -55,7 +57,8 @@ QString toQString(dev::u256 _value)
return QString::fromStdString(s.str()); return QString::fromStdString(s.str());
} }
AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::ModalDialog) AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context):
Extension(_context, ExtensionDisplayBehavior::ModalDialog), m_running(false)
{ {
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*"); qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*"); qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*");
@ -63,14 +66,11 @@ AssemblyDebuggerControl::AssemblyDebuggerControl(AppContext* _context): Extensio
qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>"); qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>");
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*"); qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*");
qRegisterMetaType<AssemblyDebuggerData>("AssemblyDebuggerData"); qRegisterMetaType<AssemblyDebuggerData>("AssemblyDebuggerData");
qRegisterMetaType<DebuggingStatusResult>("DebuggingStatusResult");
connect(this, SIGNAL(dataAvailable(bool, DebuggingStatusResult, QList<QVariableDefinition*>, QList<QObject*>, AssemblyDebuggerData)), connect(this, &AssemblyDebuggerControl::dataAvailable, this, &AssemblyDebuggerControl::showDebugger, Qt::QueuedConnection);
this, SLOT(updateGUI(bool, DebuggingStatusResult, QList<QVariableDefinition*>, QList<QObject*>, AssemblyDebuggerData)), Qt::QueuedConnection); m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
_context->appEngine()->rootContext()->setContextProperty("debugModel", this); _context->appEngine()->rootContext()->setContextProperty("debugModel", this);
m_modelDebugger = std::unique_ptr<AssemblyDebuggerModel>(new AssemblyDebuggerModel);
} }
QString AssemblyDebuggerControl::contentUrl() const QString AssemblyDebuggerControl::contentUrl() const
@ -80,7 +80,7 @@ QString AssemblyDebuggerControl::contentUrl() const
QString AssemblyDebuggerControl::title() const QString AssemblyDebuggerControl::title() const
{ {
return QApplication::tr("debugger"); return QApplication::tr("Debugger");
} }
void AssemblyDebuggerControl::start() const void AssemblyDebuggerControl::start() const
@ -89,7 +89,7 @@ void AssemblyDebuggerControl::start() const
void AssemblyDebuggerControl::debugDeployment() void AssemblyDebuggerControl::debugDeployment()
{ {
deployContract(); executeSequence(std::vector<TransactionSettings>(), 0);
} }
void AssemblyDebuggerControl::debugState(QVariantMap _state) void AssemblyDebuggerControl::debugState(QVariantMap _state)
@ -97,8 +97,7 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state)
u256 balance = fromQString(_state.value("balance").toString()); u256 balance = fromQString(_state.value("balance").toString());
QVariantList transactions = _state.value("transactions").toList(); QVariantList transactions = _state.value("transactions").toList();
resetState(); std::vector<TransactionSettings> transactionSequence;
deployContract();
for (auto const& t : transactions) for (auto const& t : transactions)
{ {
@ -114,93 +113,106 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state)
for (auto p = params.cbegin(); p != params.cend(); ++p) for (auto p = params.cbegin(); p != params.cend(); ++p)
transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString())));
runTransaction(transactionSettings); transactionSequence.push_back(transactionSettings);
} }
executeSequence(transactionSequence, balance);
} }
void AssemblyDebuggerControl::resetState() void AssemblyDebuggerControl::executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance)
{
m_modelDebugger->resetState();
m_ctx->displayMessageDialog(QApplication::tr("State status"), QApplication::tr("State reseted ... need to redeploy contract"));
}
void AssemblyDebuggerControl::callContract(TransactionSettings _tr, dev::Address _contract)
{ {
if (m_running)
throw (std::logic_error("debugging already running"));
auto compilerRes = m_ctx->codeModel()->code(); auto compilerRes = m_ctx->codeModel()->code();
if (!compilerRes->successfull()) std::shared_ptr<QContractDefinition> contractDef = compilerRes->sharedContract();
m_ctx->displayMessageDialog("debugger","compilation failed"); m_running = true;
else
emit runStarted();
emit stateChanged();
//run sequence
QtConcurrent::run([=]()
{ {
ContractCallDataEncoder c; try
QContractDefinition const* contractDef = compilerRes->contract();
QFunctionDefinition* f = nullptr;
for (int k = 0; k < contractDef->functionsList().size(); k++)
{ {
if (contractDef->functionsList().at(k)->name() == _tr.functionId) bytes contractCode = compilerRes->bytes();
std::vector<dev::bytes> transactonData;
QFunctionDefinition* f;
ContractCallDataEncoder c;
//encode data for all transactions
for (auto const& t : _sequence)
{ {
f = contractDef->functionsList().at(k); f = nullptr;
break; for (int k = 0; k < contractDef->functionsList().size(); k++)
{
if (contractDef->functionsList().at(k)->name() == t.functionId)
{
f = contractDef->functionsList().at(k);
break;
}
}
if (!f)
throw std::runtime_error("function " + t.functionId.toStdString() + " not found");
c.encode(f->index());
for (int k = 0; k < f->parametersList().size(); k++)
{
QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k);
u256 value = 0;
auto v = t.parameterValues.find(var->name());
if (v != t.parameterValues.cend())
value = v->second;
c.encode(var, value);
}
transactonData.emplace_back(c.encodedData());
} }
}
if (!f) //run contract creation first
m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("function not found. Please redeploy this contract.")); m_modelDebugger->resetState(_balance);
else DebuggingContent debuggingContent = m_modelDebugger->deployContract(contractCode);
{ Address address = debuggingContent.contractAddress;
c.encode(f->index()); for (unsigned i = 0; i < _sequence.size(); ++i)
for (int k = 0; k < f->parametersList().size(); k++) debuggingContent = m_modelDebugger->callContract(address, transactonData.at(i), _sequence.at(i));
if (f)
debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue);
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.machineStates.size(); i++)
{ {
QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k); QPointer<DebuggingStateWrapper> s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes()));
c.encode(var, _tr.parameterValues[var->name()]); s->setState(debuggingContent.machineStates.at(i));
wStates.append(s);
} }
DebuggingContent debuggingContent = m_modelDebugger->callContract(_contract, c.encodedData(), _tr); //collect states for last transaction
debuggingContent.returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode);
finalizeExecution(debuggingContent); emit dataAvailable(debuggingContent.returnParameters, wStates, code);
emit runComplete();
}
catch(boost::exception const& e)
{
emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information()));
} }
}
}
void AssemblyDebuggerControl::deployContract()
{
auto compilerRes = m_ctx->codeModel()->code();
if (!compilerRes->successfull())
emit dataAvailable(false, DebuggingStatusResult::Compilationfailed);
else
{
m_previousDebugResult = m_modelDebugger->deployContract(compilerRes->bytes());
finalizeExecution(m_previousDebugResult);
}
}
void AssemblyDebuggerControl::finalizeExecution(DebuggingContent _debuggingContent) catch(std::exception const& e)
{ {
//we need to wrap states in a QObject before sending to QML. emit runFailed(e.what());
QList<QObject*> wStates; }
for(int i = 0; i < _debuggingContent.machineStates.size(); i++) m_running = false;
{ emit stateChanged();
QPointer<DebuggingStateWrapper> s(new DebuggingStateWrapper(_debuggingContent.executionCode, _debuggingContent.executionData.toBytes())); });
s->setState(_debuggingContent.machineStates.at(i));
wStates.append(s);
}
AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(_debuggingContent.executionCode);
emit dataAvailable(true, DebuggingStatusResult::Ok, _debuggingContent.returnParameters, wStates, code);
} }
void AssemblyDebuggerControl::updateGUI(bool _success, DebuggingStatusResult const& _reason, QList<QVariableDefinition*> const& _returnParam, QList<QObject*> const& _wStates, AssemblyDebuggerData const& _code) void AssemblyDebuggerControl::showDebugger(QList<QVariableDefinition*> const& _returnParam, QList<QObject*> const& _wStates, AssemblyDebuggerData const& _code)
{ {
Q_UNUSED(_reason); m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates));
if (_success) m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code)));
{ m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code)));
m_appEngine->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam)));
m_appEngine->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); this->addContentOn(this);
m_appEngine->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code)));
m_appEngine->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam)));
this->addContentOn(this);
}
else
m_ctx->displayMessageDialog(QApplication::tr("debugger"), QApplication::tr("compilation failed"));
} }
void AssemblyDebuggerControl::runTransaction(TransactionSettings const& _tr) void AssemblyDebuggerControl::showDebugError(QString const& _error)
{ {
callContract(_tr, m_previousDebugResult.contractAddress); m_ctx->displayMessageDialog(QApplication::tr("Debugger"), _error);
} }

33
mix/AssemblyDebuggerControl.h

@ -28,14 +28,8 @@
#include "AssemblyDebuggerModel.h" #include "AssemblyDebuggerModel.h"
using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>; using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>;
enum DebuggingStatusResult
{
Ok,
Compilationfailed
};
Q_DECLARE_METATYPE(AssemblyDebuggerData) Q_DECLARE_METATYPE(AssemblyDebuggerData)
Q_DECLARE_METATYPE(DebuggingStatusResult)
Q_DECLARE_METATYPE(dev::mix::DebuggingContent) Q_DECLARE_METATYPE(dev::mix::DebuggingContent)
class AppContext; class AppContext;
@ -59,26 +53,35 @@ public:
QString title() const override; QString title() const override;
QString contentUrl() const override; QString contentUrl() const override;
Q_PROPERTY(bool running MEMBER m_running NOTIFY stateChanged)
private: private:
void deployContract(); void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance);
void callContract(TransactionSettings _tr, Address _contract);
void finalizeExecution(DebuggingContent _content);
std::unique_ptr<AssemblyDebuggerModel> m_modelDebugger; std::unique_ptr<AssemblyDebuggerModel> m_modelDebugger;
DebuggingContent m_previousDebugResult; //TODO: to be replaced in a more consistent struct. Used for now to keep the contract address in case of future transaction call. bool m_running;
public slots: public slots:
/// Run the contract constructor and show debugger window.
void debugDeployment(); void debugDeployment();
/// Setup state, run transaction sequence, show debugger for the last transaction
/// @param _state JS object with state configuration
void debugState(QVariantMap _state); void debugState(QVariantMap _state);
void resetState();
private slots:
/// Update UI with machine states result. Display a modal dialog. /// Update UI with machine states result. Display a modal dialog.
void updateGUI(bool _success, DebuggingStatusResult const& _reason, QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); void showDebugger(QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData());
/// Run the given transaction. void showDebugError(QString const& _error);
void runTransaction(TransactionSettings const& _tr);
signals: signals:
void runStarted();
void runComplete();
void runFailed(QString const& _message);
void stateChanged();
/// Emited when machine states are available. /// Emited when machine states are available.
void dataAvailable(bool _success, DebuggingStatusResult const& _reason, QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); void dataAvailable(QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData());
}; };
} }

27
mix/AssemblyDebuggerModel.cpp

@ -41,20 +41,17 @@ namespace mix
{ {
AssemblyDebuggerModel::AssemblyDebuggerModel(): AssemblyDebuggerModel::AssemblyDebuggerModel():
m_userAccount(KeyPair::create()), m_userAccount(KeyPair::create())
m_baseState(Address(), m_overlayDB, BaseState::Empty)
{ {
m_baseState.addBalance(m_userAccount.address(), 10000000 * ether); resetState(10000000 * ether);
m_executiveState = m_baseState;
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, 0));
} }
DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction) DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction)
{ {
QList<DebuggingState> machineStates; QList<DebuggingState> machineStates;
// Reset the state back to our clean premine. // Reset the state back to our clean premine.
m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, 0)); eth::Executive execution(m_executiveState, 0);
m_currentExecution->setup(_rawTransaction); execution.setup(_rawTransaction);
std::vector<DebuggingState const*> levels; std::vector<DebuggingState const*> levels;
bytes code; bytes code;
bytesConstRef data; bytesConstRef data;
@ -80,12 +77,12 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const&
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
}; };
m_currentExecution->go(onOp); execution.go(onOp);
m_currentExecution->finalize(onOp); execution.finalize(onOp);
m_executiveState.completeMine(); m_executiveState.completeMine();
DebuggingContent d; DebuggingContent d;
d.returnValue = m_currentExecution->out().toVector(); d.returnValue = execution.out().toVector();
d.machineStates = machineStates; d.machineStates = machineStates;
d.executionCode = code; d.executionCode = code;
d.executionData = data; d.executionData = data;
@ -99,7 +96,7 @@ DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code)
u256 gasPrice = 10000000000000; u256 gasPrice = 10000000000000;
u256 gas = 1000000; u256 gas = 1000000;
u256 amount = 100; u256 amount = 100;
Transaction _tr(amount, gasPrice, min(gas, m_baseState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); Transaction _tr(amount, gasPrice, min(gas, m_executiveState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
bytes b = _tr.rlp(); bytes b = _tr.rlp();
dev::bytesConstRef bytesRef = &b; dev::bytesConstRef bytesRef = &b;
DebuggingContent d = executeTransaction(bytesRef); DebuggingContent d = executeTransaction(bytesRef);
@ -110,7 +107,7 @@ DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code)
DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)
{ {
Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_baseState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_executiveState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
bytes b = tr.rlp(); bytes b = tr.rlp();
dev::bytesConstRef bytesRef = &b; dev::bytesConstRef bytesRef = &b;
DebuggingContent d = executeTransaction(bytesRef); DebuggingContent d = executeTransaction(bytesRef);
@ -118,10 +115,10 @@ DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, b
return d; return d;
} }
void AssemblyDebuggerModel::resetState() void AssemblyDebuggerModel::resetState(u256 _balance)
{ {
// Reset the state back to our clean premine. m_executiveState = eth::State(Address(), m_overlayDB, BaseState::Empty);
m_executiveState = m_baseState; m_executiveState.addBalance(m_userAccount.address(), _balance);
} }
} }

6
mix/AssemblyDebuggerModel.h

@ -66,15 +66,13 @@ public:
DebuggingContent callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); DebuggingContent callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr);
/// Deploy the contract described by _code. /// Deploy the contract described by _code.
DebuggingContent deployContract(bytes const& _code); DebuggingContent deployContract(bytes const& _code);
/// Reset state to the base state. /// Reset state to the empty state with given balance.
void resetState(); void resetState(u256 _balance);
private: private:
KeyPair m_userAccount; KeyPair m_userAccount;
OverlayDB m_overlayDB; OverlayDB m_overlayDB;
eth::State m_baseState;
eth::State m_executiveState; eth::State m_executiveState;
std::unique_ptr<eth::Executive> m_currentExecution;
DebuggingContent executeTransaction(dev::bytesConstRef const& _rawTransaction); DebuggingContent executeTransaction(dev::bytesConstRef const& _rawTransaction);
}; };

4
mix/CodeEditorExtensionManager.cpp

@ -64,11 +64,13 @@ void CodeEditorExtensionManager::loadEditor(QQuickItem* _editor)
void CodeEditorExtensionManager::initExtensions() void CodeEditorExtensionManager::initExtensions()
{ {
initExtension(std::make_shared<ConstantCompilationControl>(m_appContext)); std::shared_ptr<ConstantCompilationControl> output = std::make_shared<ConstantCompilationControl>(m_appContext);
std::shared_ptr<AssemblyDebuggerControl> debug = std::make_shared<AssemblyDebuggerControl>(m_appContext); std::shared_ptr<AssemblyDebuggerControl> debug = std::make_shared<AssemblyDebuggerControl>(m_appContext);
std::shared_ptr<StateListView> stateList = std::make_shared<StateListView>(m_appContext); std::shared_ptr<StateListView> stateList = std::make_shared<StateListView>(m_appContext);
QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); }); QObject::connect(m_doc, &QTextDocument::contentsChanged, [=]() { m_appContext->codeModel()->registerCodeChange(m_doc->toPlainText()); });
QObject::connect(debug.get(), &AssemblyDebuggerControl::runFailed, output.get(), &ConstantCompilationControl::displayError);
initExtension(output);
initExtension(debug); initExtension(debug);
initExtension(stateList); initExtension(stateList);
} }

12
mix/CodeModel.cpp

@ -63,7 +63,7 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con
{} {}
CodeModel::CodeModel(QObject* _parent) : QObject(_parent), CodeModel::CodeModel(QObject* _parent) : QObject(_parent),
m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0) m_compiling(false), m_result(new CompilationResult(nullptr)), m_backgroundWorker(this), m_backgroundJobId(0)
{ {
m_backgroundWorker.moveToThread(&m_backgroundThread); m_backgroundWorker.moveToThread(&m_backgroundThread);
connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection);
@ -94,10 +94,11 @@ void CodeModel::registerCodeChange(const QString &_code)
{ {
// launch the background thread // launch the background thread
m_backgroundJobId++; m_backgroundJobId++;
m_compiling = true;
emit stateChanged();
emit scheduleCompilationJob(m_backgroundJobId, _code); emit scheduleCompilationJob(m_backgroundJobId, _code);
} }
void CodeModel::runCompilationJob(int _jobId, QString const& _code) void CodeModel::runCompilationJob(int _jobId, QString const& _code)
{ {
if (_jobId != m_backgroundJobId) if (_jobId != m_backgroundJobId)
@ -124,11 +125,18 @@ void CodeModel::runCompilationJob(int _jobId, QString const& _code)
void CodeModel::onCompilationComplete(CompilationResult*_newResult) void CodeModel::onCompilationComplete(CompilationResult*_newResult)
{ {
m_compiling = false;
m_result.reset(_newResult); m_result.reset(_newResult);
emit compilationComplete(); emit compilationComplete();
emit stateChanged();
if (m_result->successfull()) if (m_result->successfull())
emit codeChanged(); emit codeChanged();
} }
bool CodeModel::hasContract() const
{
return m_result->contract()->functionsList().size() > 0;
}
} }
} }

22
mix/CodeModel.h

@ -69,8 +69,10 @@ public:
/// Failed compilation result constructor /// Failed compilation result constructor
CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent); CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage, QObject* parent);
/// @returns contract definition /// @returns contract definition for QML property
QContractDefinition* contract() { return m_contract.get(); } QContractDefinition* contract() { return m_contract.get(); }
/// @returns contract definition
std::shared_ptr<QContractDefinition> sharedContract() { return m_contract; }
/// Indicates if the compilation was successfull /// Indicates if the compilation was successfull
bool successfull() const { return m_successfull; } bool successfull() const { return m_successfull; }
@ -96,12 +98,6 @@ private:
/// Background code compiler /// Background code compiler
class CodeModel : public QObject class CodeModel : public QObject
{ {
enum Status
{
Idle, ///< No compiation in progress
Compiling, ///< Compilation currently in progress
};
Q_OBJECT Q_OBJECT
public: public:
@ -114,10 +110,17 @@ public:
CompilationResult const* code() const { return m_result.get(); } CompilationResult const* code() const { return m_result.get(); }
Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged) Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged)
Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged)
Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged)
/// @returns compilation status
bool isCompiling() const { return m_compiling; }
/// @returns true if contract has at least one function
bool hasContract() const;
signals: signals:
/// Emited on compilation status change /// Emited on compilation state change
void statusChanged(Status _from, Status _to); void stateChanged();
/// Emitted on compilation complete /// Emitted on compilation complete
void compilationComplete(); void compilationComplete();
/// Internal signal used to transfer compilation job to background thread /// Internal signal used to transfer compilation job to background thread
@ -138,6 +141,7 @@ private:
void runCompilationJob(int _jobId, QString const& _content); void runCompilationJob(int _jobId, QString const& _content);
void stop(); void stop();
bool m_compiling;
std::unique_ptr<CompilationResult> m_result; std::unique_ptr<CompilationResult> m_result;
QThread m_backgroundThread; QThread m_backgroundThread;
BackgroundWorker m_backgroundWorker; BackgroundWorker m_backgroundWorker;

11
mix/ConstantCompilationControl.cpp

@ -37,6 +37,7 @@ using namespace dev::mix;
ConstantCompilationControl::ConstantCompilationControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::Tab) ConstantCompilationControl::ConstantCompilationControl(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::Tab)
{ {
connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update); connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update);
connect(_context->codeModel(), &CodeModel::compilationComplete, this, &ConstantCompilationControl::update);
} }
QString ConstantCompilationControl::contentUrl() const QString ConstantCompilationControl::contentUrl() const
@ -80,3 +81,13 @@ void ConstantCompilationControl::resetOutPut()
status->setProperty("text", ""); status->setProperty("text", "");
content->setProperty("text", ""); content->setProperty("text", "");
} }
void ConstantCompilationControl::displayError(QString const& _error)
{
QObject* status = m_view->findChild<QObject*>("status", Qt::FindChildrenRecursively);
QObject* content = m_view->findChild<QObject*>("content", Qt::FindChildrenRecursively);
status->setProperty("text", "failure");
status->setProperty("color", "red");
content->setProperty("text", _error);
}

1
mix/ConstantCompilationControl.h

@ -45,6 +45,7 @@ private:
public slots: public slots:
void update(); void update();
void displayError(QString const& _error);
}; };
} }

2
mix/MixApplication.cpp

@ -25,6 +25,8 @@
#include "MixApplication.h" #include "MixApplication.h"
#include "AppContext.h" #include "AppContext.h"
#include <QMenuBar>
using namespace dev::mix; using namespace dev::mix;
MixApplication::MixApplication(int _argc, char* _argv[]): MixApplication::MixApplication(int _argc, char* _argv[]):

13
mix/qml/StateList.qml

@ -35,8 +35,7 @@ Rectangle {
Button { Button {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
text: qsTr("Add") action: addStateAction
onClicked: stateListModel.addState();
} }
StateDialog { StateDialog {
@ -61,7 +60,7 @@ Rectangle {
function addState() { function addState() {
var item = { var item = {
title: "", title: "",
balance: "1000000000000", balance: "100000000000000000000000000",
transactions: [] transactions: []
}; };
stateDialog.open(stateListModel.count, item); stateDialog.open(stateListModel.count, item);
@ -121,5 +120,13 @@ Rectangle {
} }
} }
} }
Action {
id: addStateAction
text: "&Add State"
shortcut: "Ctrl+N"
enabled: codeModel.hasContract && !debugModel.running;
onTriggered: stateListModel.addState();
}
} }

7
mix/qml/main.qml

@ -1,6 +1,6 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.1 import QtQuick.Window 2.1
@ -51,6 +51,7 @@ ApplicationWindow {
id: debugRunAction id: debugRunAction
text: "&Run" text: "&Run"
shortcut: "F5" shortcut: "F5"
enabled: codeModel.hasContract && !debugModel.running;
onTriggered: debugModel.debugDeployment(); onTriggered: debugModel.debugDeployment();
} }
@ -60,4 +61,6 @@ ApplicationWindow {
shortcut: "F6" shortcut: "F6"
onTriggered: debugModel.resetState(); onTriggered: debugModel.resetState();
} }
} }

Loading…
Cancel
Save