Browse Source

Merge remote-tracking branch 'up/develop' into logsManagement

cl-refactor
yann300 10 years ago
parent
commit
e60fe6bc4d
  1. 89
      mix/ClientModel.cpp
  2. 2
      mix/ClientModel.h
  3. 107
      mix/CodeModel.cpp
  4. 31
      mix/CodeModel.h
  5. 7
      mix/DebuggingStateWrapper.cpp
  6. 45
      mix/DebuggingStateWrapper.h
  7. 2
      mix/MixClient.cpp
  8. 74
      mix/qml/CallStack.qml
  9. 175
      mix/qml/Debugger.qml
  10. 4
      mix/qml/StatusPane.qml
  11. 69
      mix/qml/StorageView.qml
  12. 31
      mix/qml/js/Debugger.js
  13. 2
      mix/res.qrc

89
mix/ClientModel.cpp

@ -37,7 +37,6 @@
#include "QVariableDefinition.h" #include "QVariableDefinition.h"
#include "ContractCallDataEncoder.h" #include "ContractCallDataEncoder.h"
#include "CodeModel.h" #include "CodeModel.h"
#include "ClientModel.h"
#include "QEther.h" #include "QEther.h"
#include "Web3Server.h" #include "Web3Server.h"
#include "ClientModel.h" #include "ClientModel.h"
@ -318,19 +317,28 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
QDebugData* debugData = new QDebugData(); QDebugData* debugData = new QDebugData();
QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership);
QList<QCode*> codes; QList<QCode*> codes;
QList<QHash<int, int>> codeMaps;
QList<AssemblyItems> codeItems;
QList<CompiledContract const*> contracts;
for (MachineCode const& code: _t.executionCode) for (MachineCode const& code: _t.executionCode)
{ {
codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code)); QHash<int, int> codeMap;
codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code, codeMap));
codeMaps.push_back(std::move(codeMap));
//try to resolve contract for source level debugging //try to resolve contract for source level debugging
auto nameIter = m_contractNames.find(code.address); auto nameIter = m_contractNames.find(code.address);
if (nameIter != m_contractNames.end()) if (nameIter != m_contractNames.end())
{ {
CompiledContract const& compilerRes = m_context->codeModel()->contract(nameIter->second); CompiledContract const& compilerRes = m_context->codeModel()->contract(nameIter->second);
eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes.assemblyItems() : compilerRes.constructorAssemblyItems(); eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes.assemblyItems() : compilerRes.constructorAssemblyItems();
QVariantList locations; codes.back()->setDocument(compilerRes.documentId());
for (eth::AssemblyItem const& item: assemblyItems) codeItems.push_back(std::move(assemblyItems));
locations.push_back(QVariant::fromValue(new QSourceLocation(debugData, item.getLocation().start, item.getLocation().end))); contracts.push_back(&compilerRes);
codes.back()->setLocations(compilerRes.documentId(), std::move(locations)); }
else
{
codeItems.push_back(AssemblyItems());
contracts.push_back(nullptr);
} }
} }
@ -339,18 +347,77 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
data.push_back(QMachineState::getDebugCallData(debugData, d)); data.push_back(QMachineState::getDebugCallData(debugData, d));
QVariantList states; QVariantList states;
QStringList solCallStack;
std::map<int, SolidityDeclaration> solLocals; //<stack pos, declaration>
QList<int> returnStack;
unsigned prevInstructionIndex = 0;
for (MachineState const& s: _t.machineStates) for (MachineState const& s: _t.machineStates)
states.append(QVariant::fromValue(new QMachineState(debugData, s, codes[s.codeIndex], data[s.dataIndex]))); {
int instructionIndex = codeMaps[s.codeIndex][static_cast<unsigned>(s.curPC)];
QSolState* solState = nullptr;
if (!codeItems[s.codeIndex].empty() && contracts[s.codeIndex])
{
CompiledContract const* contract = contracts[s.codeIndex];
AssemblyItem const& instruction = codeItems[s.codeIndex][instructionIndex];
debugData->setStates(std::move(states)); if (instruction.type() == dev::eth::Push && !instruction.data())
{
//register new local variable initialization
auto localIter = contract->locals().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (localIter != contract->locals().end())
solLocals[s.stack.size()] = localIter.value();
}
//QList<QVariableDefinition*> returnParameters; if (instruction.type() == dev::eth::Tag) //TODO: use annotations
//returnParameters = encoder.decode(f->returnParameters(), debuggingContent.returnValue); {
//track calls into functions
auto functionIter = contract->functions().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (functionIter != contract->functions().end())
{
QString functionName = functionIter.value();
solCallStack.push_back(functionName);
returnStack.push_back(prevInstructionIndex + 1);
}
else if (!returnStack.empty() && instructionIndex == returnStack.back())
{
returnStack.pop_back();
solCallStack.pop_back();
}
}
//format solidity context values
QStringList locals;
for(auto l: solLocals)
if (l.first < (int)s.stack.size())
locals.push_back(l.second.name + "\t" + formatValue(l.second.type, s.stack[l.first]));
QStringList storage;
for(auto st: s.storage)
{
if (st.first < std::numeric_limits<unsigned>::max())
{
auto storageIter = contract->storage().find(static_cast<unsigned>(st.first));
if (storageIter != contract->storage().end())
storage.push_back(storageIter.value().name + "\t" + formatValue(storageIter.value().type, st.second));
}
}
prevInstructionIndex = instructionIndex;
solState = new QSolState(debugData, storage, solCallStack, locals, instruction.getLocation().start, instruction.getLocation().end);
}
states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState)));
}
//collect states for last transaction debugData->setStates(std::move(states));
debugDataReady(debugData); debugDataReady(debugData);
} }
QString ClientModel::formatValue(SolidityType const&, dev::u256 const& _value)
{
return QString::fromStdString(prettyU256(_value));
}
void ClientModel::emptyRecord() void ClientModel::emptyRecord()
{ {
debugDataReady(new QDebugData()); debugDataReady(new QDebugData());

2
mix/ClientModel.h

@ -41,6 +41,7 @@ class QEther;
class QDebugData; class QDebugData;
class MixClient; class MixClient;
class QVariableDefinition; class QVariableDefinition;
struct SolidityType;
/// Backend transaction config class /// Backend transaction config class
struct TransactionSettings struct TransactionSettings
@ -198,6 +199,7 @@ private:
void onNewTransaction(); void onNewTransaction();
void onStateReset(); void onStateReset();
void showDebuggerForTransaction(ExecutionResult const& _t); void showDebuggerForTransaction(ExecutionResult const& _t);
QString formatValue(SolidityType const& _type, dev::u256 const& _value);
AppContext* m_context; AppContext* m_context;
std::atomic<bool> m_running; std::atomic<bool> m_running;

107
mix/CodeModel.cpp

@ -25,7 +25,10 @@
#include <QDebug> #include <QDebug>
#include <QApplication> #include <QApplication>
#include <QtQml> #include <QtQml>
#include <libdevcore/Common.h>
#include <libevmcore/SourceLocation.h> #include <libevmcore/SourceLocation.h>
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
#include <libsolidity/InterfaceHandler.h> #include <libsolidity/InterfaceHandler.h>
@ -43,6 +46,91 @@ using namespace dev::mix;
const std::set<std::string> c_predefinedContracts = const std::set<std::string> c_predefinedContracts =
{ "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" }; { "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" };
namespace
{
using namespace dev::solidity;
class CollectDeclarationsVisitor: public ASTConstVisitor
{
public:
CollectDeclarationsVisitor(QHash<LocationPair, QString>* _functions, QHash<LocationPair, SolidityDeclaration>* _locals, QHash<unsigned, SolidityDeclaration>* _storage):
m_functions(_functions), m_locals(_locals), m_storage(_storage), m_functionScope(false), m_storageSlot(0) {}
private:
QHash<LocationPair, QString>* m_functions;
QHash<LocationPair, SolidityDeclaration>* m_locals;
QHash<unsigned, SolidityDeclaration>* m_storage;
bool m_functionScope;
uint m_storageSlot;
LocationPair nodeLocation(ASTNode const& _node)
{
return LocationPair(_node.getLocation().start, _node.getLocation().end);
}
SolidityType nodeType(Type const* _type)
{
if (!_type)
return SolidityType { SolidityType::Type::UnsignedInteger, 32 };
switch (_type->getCategory())
{
case Type::Category::Integer:
{
IntegerType const* it = dynamic_cast<IntegerType const*>(_type);
unsigned size = it->getNumBits() / 8;
SolidityType::Type typeCode = it->isAddress() ? SolidityType::Type::Address : it->isHash() ? SolidityType::Type::Hash : it->isSigned() ? SolidityType::Type::SignedInteger : SolidityType::Type::UnsignedInteger;
return SolidityType { typeCode, size };
}
case Type::Category::Bool:
return SolidityType { SolidityType::Type::Bool, _type->getSizeOnStack() * 32 };
case Type::Category::String:
{
StaticStringType const* s = dynamic_cast<StaticStringType const*>(_type);
return SolidityType { SolidityType::Type::String, static_cast<unsigned>(s->getNumBytes()) };
}
case Type::Category::Contract:
return SolidityType { SolidityType::Type::Address, _type->getSizeOnStack() * 32 };
case Type::Category::Array:
case Type::Category::Enum:
case Type::Category::Function:
case Type::Category::IntegerConstant:
case Type::Category::Magic:
case Type::Category::Mapping:
case Type::Category::Modifier:
case Type::Category::Real:
case Type::Category::Struct:
case Type::Category::TypeType:
case Type::Category::Void:
default:
return SolidityType { SolidityType::Type::UnsignedInteger, 32 };
}
}
virtual bool visit(FunctionDefinition const& _node)
{
m_functions->insert(nodeLocation(_node), QString::fromStdString(_node.getName()));
m_functionScope = true;
return true;
}
virtual void endVisit(FunctionDefinition const&)
{
m_functionScope = false;
}
virtual bool visit(VariableDeclaration const& _node)
{
SolidityDeclaration decl;
decl.type = nodeType(_node.getType().get());
decl.name = QString::fromStdString(_node.getName());
if (m_functionScope)
m_locals->insert(nodeLocation(_node), decl);
else
m_storage->insert(m_storageSlot++, decl);
return true;
}
};
}
void BackgroundWorker::queueCodeChange(int _jobId) void BackgroundWorker::queueCodeChange(int _jobId)
{ {
m_model->runCompilationJob(_jobId); m_model->runCompilationJob(_jobId);
@ -52,18 +140,23 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
QObject(nullptr), QObject(nullptr),
m_sourceHash(qHash(_source)) m_sourceHash(qHash(_source))
{ {
auto const& contractDefinition = _compiler.getContractDefinition(_contractName.toStdString()); std::string name = _contractName.toStdString();
auto const& contractDefinition = _compiler.getContractDefinition(name);
m_contract.reset(new QContractDefinition(&contractDefinition)); m_contract.reset(new QContractDefinition(&contractDefinition));
QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership);
m_bytes = _compiler.getBytecode(_contractName.toStdString()); m_bytes = _compiler.getBytecode(_contractName.toStdString());
m_assemblyItems = _compiler.getRuntimeAssemblyItems(_contractName.toStdString()); m_assemblyItems = _compiler.getRuntimeAssemblyItems(name);
m_constructorAssemblyItems = _compiler.getAssemblyItems(_contractName.toStdString()); m_constructorAssemblyItems = _compiler.getAssemblyItems(name);
dev::solidity::InterfaceHandler interfaceHandler; dev::solidity::InterfaceHandler interfaceHandler;
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition)); m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
if (m_contractInterface.isEmpty()) if (m_contractInterface.isEmpty())
m_contractInterface = "[]"; m_contractInterface = "[]";
if (contractDefinition.getLocation().sourceName.get()) if (contractDefinition.getLocation().sourceName.get())
m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName); m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName);
CollectDeclarationsVisitor visitor(&m_functions, &m_locals, &m_storage);
contractDefinition.accept(visitor);
} }
QString CompiledContract::codeHex() const QString CompiledContract::codeHex() const
@ -121,12 +214,11 @@ void CodeModel::reset(QVariantMap const& _documents)
void CodeModel::registerCodeChange(QString const& _documentId, QString const& _code) void CodeModel::registerCodeChange(QString const& _documentId, QString const& _code)
{ {
{ CompiledContract* contract = contractByDocumentId(_documentId);
Guard l(x_contractMap);
CompiledContract* contract = m_contractMap.value(_documentId);
if (contract != nullptr && contract->m_sourceHash == qHash(_code)) if (contract != nullptr && contract->m_sourceHash == qHash(_code))
return; return;
{
Guard pl(x_pendingContracts); Guard pl(x_pendingContracts);
m_pendingContracts[_documentId] = _code; m_pendingContracts[_documentId] = _code;
} }
@ -196,7 +288,8 @@ void CodeModel::runCompilationJob(int _jobId)
if (c_predefinedContracts.count(n) != 0) if (c_predefinedContracts.count(n) != 0)
continue; continue;
QString name = QString::fromStdString(n); QString name = QString::fromStdString(n);
auto sourceIter = m_pendingContracts.find(name); QString sourceName = QString::fromStdString(*cs.getContractDefinition(n).getLocation().sourceName);
auto sourceIter = m_pendingContracts.find(sourceName);
QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString(); QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString();
CompiledContract* contract = new CompiledContract(cs, name, source); CompiledContract* contract = new CompiledContract(cs, name, source);
QQmlEngine::setObjectOwnership(contract, QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(contract, QQmlEngine::CppOwnership);

31
mix/CodeModel.h

@ -64,6 +64,29 @@ private:
CodeModel* m_model; CodeModel* m_model;
}; };
using LocationPair = QPair<int, int>;
struct SolidityType
{
enum class Type //TODO: arrays and structs
{
SignedInteger,
UnsignedInteger,
Hash,
Bool,
Address,
String,
};
Type type;
unsigned size; //bytes
};
struct SolidityDeclaration
{
QString name;
SolidityType type;
};
///Compilation result model. Contains all the compiled contract data required by UI ///Compilation result model. Contains all the compiled contract data required by UI
class CompiledContract: public QObject class CompiledContract: public QObject
{ {
@ -93,6 +116,10 @@ public:
/// @returns contract source Id /// @returns contract source Id
QString documentId() const { return m_documentId; } QString documentId() const { return m_documentId; }
QHash<LocationPair, QString> const& functions() const { return m_functions; }
QHash<LocationPair, SolidityDeclaration> const& locals() const { return m_locals; }
QHash<unsigned, SolidityDeclaration> const& storage() const { return m_storage; }
private: private:
uint m_sourceHash; uint m_sourceHash;
std::shared_ptr<QContractDefinition> m_contract; std::shared_ptr<QContractDefinition> m_contract;
@ -102,11 +129,13 @@ private:
QString m_documentId; QString m_documentId;
eth::AssemblyItems m_assemblyItems; eth::AssemblyItems m_assemblyItems;
eth::AssemblyItems m_constructorAssemblyItems; eth::AssemblyItems m_constructorAssemblyItems;
QHash<LocationPair, QString> m_functions;
QHash<LocationPair, SolidityDeclaration> m_locals;
QHash<unsigned, SolidityDeclaration> m_storage;
friend class CodeModel; friend class CodeModel;
}; };
using ContractMap = QHash<QString, CompiledContract*>; using ContractMap = QHash<QString, CompiledContract*>;
/// Code compilation model. Compiles contracts in background an provides compiled contract data /// Code compilation model. Compiles contracts in background an provides compiled contract data

7
mix/DebuggingStateWrapper.cpp

@ -69,7 +69,7 @@ namespace
} }
} }
QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code) QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code, QHash<int, int>& o_codeMap)
{ {
QVariantList codeStr; QVariantList codeStr;
for (unsigned i = 0; i <= _code.size(); ++i) for (unsigned i = 0; i <= _code.size(); ++i)
@ -80,14 +80,15 @@ QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _addr
QString s = QString::fromStdString(instructionInfo((Instruction)b).name); QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out; std::ostringstream out;
out << std::hex << std::setw(4) << std::setfill('0') << i; out << std::hex << std::setw(4) << std::setfill('0') << i;
int line = i; int offset = i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32) if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{ {
unsigned bc = getPushNumber((Instruction)b); unsigned bc = getPushNumber((Instruction)b);
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc))); s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc)));
i += bc; i += bc;
} }
codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s, line))); o_codeMap[offset] = codeStr.size();
codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s)));
} }
catch (...) catch (...)
{ {

45
mix/DebuggingStateWrapper.h

@ -26,12 +26,12 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <QStringList> #include <QStringList>
#include <QMap> #include <QHash>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
#include "MachineStates.h"
#include "QVariableDefinition.h" #include "QVariableDefinition.h"
#include "MixClient.h"
#include "QBigInt.h" #include "QBigInt.h"
namespace dev namespace dev
@ -46,32 +46,39 @@ class QInstruction: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString line MEMBER m_line CONSTANT) Q_PROPERTY(QString line MEMBER m_line CONSTANT)
Q_PROPERTY(int processIndex MEMBER m_processIndex CONSTANT)
public: public:
QInstruction(QObject* _owner, QString _line, int _processIndex): QObject(_owner), m_line(_line), m_processIndex(_processIndex) {} QInstruction(QObject* _owner, QString _line): QObject(_owner), m_line(_line) {}
private: private:
QString m_line; QString m_line;
int m_processIndex;
}; };
/**
class QSourceLocation: public QObject * @brief Solidity state
*/
class QSolState: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QStringList storage MEMBER m_storage CONSTANT)
Q_PROPERTY(QStringList callStack MEMBER m_callStack CONSTANT)
Q_PROPERTY(QStringList locals MEMBER m_locals CONSTANT)
Q_PROPERTY(int start MEMBER m_start CONSTANT) Q_PROPERTY(int start MEMBER m_start CONSTANT)
Q_PROPERTY(int end MEMBER m_end CONSTANT) Q_PROPERTY(int end MEMBER m_end CONSTANT)
public: public:
QSourceLocation(QObject* _owner, int _start, int _end): QObject(_owner), m_start(_start), m_end(_end) {} QSolState(QObject* _parent, QStringList const& _storage, QStringList const& _callStack, QStringList const& _locals, int _start, int _end):
QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end)
{ }
private: private:
QStringList m_storage;
QStringList m_callStack;
QStringList m_locals;
int m_start; int m_start;
int m_end; int m_end;
}; };
/** /**
* @brief Shared container for lines * @brief Shared container for lines
*/ */
@ -79,19 +86,17 @@ class QCode: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QVariantList instructions MEMBER m_instructions CONSTANT) Q_PROPERTY(QVariantList instructions MEMBER m_instructions CONSTANT)
Q_PROPERTY(QVariantList locations MEMBER m_locations CONSTANT)
Q_PROPERTY(QString address MEMBER m_address CONSTANT) Q_PROPERTY(QString address MEMBER m_address CONSTANT)
Q_PROPERTY(QString documentId MEMBER m_document CONSTANT) Q_PROPERTY(QString documentId MEMBER m_document CONSTANT)
public: public:
QCode(QObject* _owner, QString const& _address, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions), m_address(_address) {} QCode(QObject* _owner, QString const& _address, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions), m_address(_address) {}
void setLocations(QString const& _document, QVariantList&& _locations) { m_document = _document; m_locations = _locations; } void setDocument(QString const& _documentId) { m_document = _documentId; }
private: private:
QVariantList m_instructions; QVariantList m_instructions;
QString m_address; QString m_address;
QString m_document; QString m_document;
QVariantList m_locations;
}; };
/** /**
@ -133,6 +138,7 @@ class QMachineState: public QObject
Q_OBJECT Q_OBJECT
Q_PROPERTY(int step READ step CONSTANT) Q_PROPERTY(int step READ step CONSTANT)
Q_PROPERTY(int curPC READ curPC CONSTANT) Q_PROPERTY(int curPC READ curPC CONSTANT)
Q_PROPERTY(int instructionIndex MEMBER m_instructionIndex CONSTANT)
Q_PROPERTY(QBigInt* gasCost READ gasCost CONSTANT) Q_PROPERTY(QBigInt* gasCost READ gasCost CONSTANT)
Q_PROPERTY(QBigInt* gas READ gas CONSTANT) Q_PROPERTY(QBigInt* gas READ gas CONSTANT)
Q_PROPERTY(QString instruction READ instruction CONSTANT) Q_PROPERTY(QString instruction READ instruction CONSTANT)
@ -146,10 +152,11 @@ class QMachineState: public QObject
Q_PROPERTY(QVariantList levels READ levels CONSTANT) Q_PROPERTY(QVariantList levels READ levels CONSTANT)
Q_PROPERTY(unsigned codeIndex READ codeIndex CONSTANT) Q_PROPERTY(unsigned codeIndex READ codeIndex CONSTANT)
Q_PROPERTY(unsigned dataIndex READ dataIndex CONSTANT) Q_PROPERTY(unsigned dataIndex READ dataIndex CONSTANT)
Q_PROPERTY(QObject* solidity MEMBER m_solState CONSTANT)
public: public:
QMachineState(QObject* _owner, MachineState const& _state, QCode* _code, QCallData* _callData): QMachineState(QObject* _owner, int _instructionIndex, MachineState const& _state, QCode* _code, QCallData* _callData, QSolState* _solState):
QObject(_owner), m_state(_state), m_code(_code), m_callData(_callData) {} QObject(_owner), m_instructionIndex(_instructionIndex), m_state(_state), m_code(_code), m_callData(_callData), m_solState(_solState) { }
/// Get the step of this machine states. /// Get the step of this machine states.
int step() { return (int)m_state.steps; } int step() { return (int)m_state.steps; }
/// Get the proccessed code index. /// Get the proccessed code index.
@ -168,7 +175,7 @@ public:
QStringList debugStorage(); QStringList debugStorage();
/// Get memory. /// Get memory.
QVariantList debugMemory(); QVariantList debugMemory();
/// get end of debug information. /// Get end of debug information.
QString endOfDebug(); QString endOfDebug();
/// Get the new memory size. /// Get the new memory size.
QBigInt* newMemSize(); QBigInt* newMemSize();
@ -177,18 +184,18 @@ public:
/// Get all previous steps. /// Get all previous steps.
QVariantList levels(); QVariantList levels();
/// Get the current processed machine state. /// Get the current processed machine state.
MachineState state() { return m_state; } MachineState const& state() const { return m_state; }
/// Set the current processed machine state.
void setState(MachineState _state) { m_state = _state; }
/// Convert all machine states in human readable code. /// Convert all machine states in human readable code.
static QCode* getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code); static QCode* getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code, QHash<int, int>& o_codeMap);
/// Convert call data into human readable form /// Convert call data into human readable form
static QCallData* getDebugCallData(QObject* _owner, bytes const& _data); static QCallData* getDebugCallData(QObject* _owner, bytes const& _data);
private: private:
int m_instructionIndex;
MachineState m_state; MachineState m_state;
QCode* m_code; QCode* m_code;
QCallData* m_callData; QCallData* m_callData;
QSolState* m_solState;
}; };
} }

2
mix/MixClient.cpp

@ -41,7 +41,7 @@ namespace mix
{ {
const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const u256 c_mixGenesisDifficulty = (u256) 1 << 4; const u256 c_mixGenesisDifficulty = c_minimumDifficulty; //TODO: make it lower for Mix somehow
class MixBlockChain: public dev::eth::BlockChain class MixBlockChain: public dev::eth::BlockChain
{ {

74
mix/qml/CallStack.qml

@ -0,0 +1,74 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import "."
DebugInfoList
{
id: callStack
collapsible: true
title : qsTr("Call Stack")
enableSelection: true
itemDelegate:
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#4A90E2"
visible: styleData.selected;
}
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: 30
Layout.maximumWidth: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width - 30
Layout.maximumWidth: parent.width - 30
Text {
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.NoWrap
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value;
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
}

175
mix/qml/Debugger.qml

@ -29,6 +29,7 @@ Rectangle {
onAssemblyModeChanged: onAssemblyModeChanged:
{ {
Debugger.updateMode(); Debugger.updateMode();
machineStates.updateHeight();
} }
function displayCompilationErrorIfAny() function displayCompilationErrorIfAny()
@ -90,6 +91,9 @@ Rectangle {
property alias memoryDumpHeightSettings: memoryRect.height property alias memoryDumpHeightSettings: memoryRect.height
property alias callDataHeightSettings: callDataRect.height property alias callDataHeightSettings: callDataRect.height
property alias transactionLogVisible: transactionLog.visible property alias transactionLogVisible: transactionLog.visible
property alias solCallStackHeightSettings: solStackRect.height
property alias solStorageHeightSettings: solStorageRect.height
property alias solLocalsHeightSettings: solLocalsRect.height
} }
Rectangle Rectangle
@ -183,8 +187,12 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
function updateHeight() { function updateHeight() {
statesLayout.height = buttonRow.childrenRect.height + assemblyCodeRow.childrenRect.height + var h = buttonRow.childrenRect.height;
callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height + 120; if (assemblyMode)
h += assemblyCodeRow.childrenRect.height + callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height;
else
h += solStackRect.childrenRect.height + solLocalsRect.childrenRect.height + solStorageRect.childrenRect.height;
statesLayout.height = h + 120;
} }
Component.onCompleted: updateHeight(); Component.onCompleted: updateHeight();
@ -546,153 +554,78 @@ Rectangle {
Rectangle Rectangle
{ {
id: callStackRect; id: solStackRect;
color: "transparent" color: "transparent"
Layout.minimumHeight: 25 Layout.minimumHeight: 25
Layout.maximumHeight: 800 Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight(); onHeightChanged: machineStates.updateHeight();
DebugInfoList visible: !assemblyMode
{ CallStack {
id: callStack
collapsible: true
anchors.fill: parent
title : qsTr("Call Stack")
enableSelection: true
onRowActivated: Debugger.displayFrame(index);
itemDelegate:
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#4A90E2" id: solCallStack
visible: styleData.selected; }
} }
RowLayout
{
id: row
anchors.fill: parent
Rectangle Rectangle
{ {
color: "#f7f7f7" id: solLocalsRect;
Layout.fillWidth: true color: "transparent"
Layout.minimumWidth: 30 Layout.minimumHeight: 25
Layout.maximumWidth: 30 Layout.maximumHeight: 800
Text { onHeightChanged: machineStates.updateHeight();
anchors.verticalCenter: parent.verticalCenter visible: !assemblyMode
anchors.left: parent.left StorageView {
font.family: "monospace" title : qsTr("Locals")
anchors.leftMargin: 5 anchors.fill: parent
color: "#4a4a4a" id: solLocals
text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
} }
} }
Rectangle Rectangle
{ {
id: solStorageRect;
color: "transparent" color: "transparent"
Layout.fillWidth: true Layout.minimumHeight: 25
Layout.minimumWidth: parent.width - 30 Layout.maximumHeight: 800
Layout.maximumWidth: parent.width - 30 onHeightChanged: machineStates.updateHeight();
Text { visible: !assemblyMode
anchors.leftMargin: 5 StorageView {
width: parent.width - 5 title : qsTr("Members")
wrapMode: Text.NoWrap anchors.fill: parent
anchors.left: parent.left id: solStorage
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value;
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
} }
} }
Rectangle Rectangle
{ {
id: storageRect id: callStackRect;
color: "transparent" color: "transparent"
width: parent.width
Layout.minimumHeight: 25 Layout.minimumHeight: 25
Layout.maximumHeight: 800 Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight(); onHeightChanged: machineStates.updateHeight();
DebugInfoList visible: assemblyMode
{ CallStack {
id: storage
anchors.fill: parent
collapsible: true
title : qsTr("Storage")
itemDelegate:
Item {
anchors.fill: parent
RowLayout
{
id: row
anchors.fill: parent anchors.fill: parent
Rectangle id: callStack
{ onRowActivated: Debugger.displayFrame(index);
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.value.split('\t')[0];
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
} }
} }
Rectangle Rectangle
{ {
id: storageRect
color: "transparent" color: "transparent"
Layout.fillWidth: true width: parent.width
Layout.minimumWidth: parent.width / 2 Layout.minimumHeight: 25
Layout.maximumWidth: parent.width / 2 Layout.maximumHeight: 800
Text { onHeightChanged: machineStates.updateHeight();
maximumLineCount: 1 visible: assemblyMode
clip: true StorageView {
anchors.leftMargin: 5 anchors.fill: parent
width: parent.width - 5 id: storage
wrapMode: Text.WrapAnywhere
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value.split('\t')[1];
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
} }
} }
@ -704,6 +637,7 @@ Rectangle {
Layout.minimumHeight: 25 Layout.minimumHeight: 25
Layout.maximumHeight: 800 Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight(); onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
DebugInfoList { DebugInfoList {
id: memoryDump id: memoryDump
anchors.fill: parent anchors.fill: parent
@ -726,6 +660,7 @@ Rectangle {
Layout.minimumHeight: 25 Layout.minimumHeight: 25
Layout.maximumHeight: 800 Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight(); onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
DebugInfoList { DebugInfoList {
id: callDataDump id: callDataDump
anchors.fill: parent anchors.fill: parent

4
mix/qml/StatusPane.qml

@ -258,8 +258,8 @@ Rectangle {
color: "transparent" color: "transparent"
width: 100 width: 100
height: parent.height height: parent.height
anchors.top: statusHeader.top anchors.top: parent.top
anchors.right: statusHeader.right anchors.right: parent.right
RowLayout RowLayout
{ {
anchors.fill: parent anchors.fill: parent

69
mix/qml/StorageView.qml

@ -0,0 +1,69 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import "."
DebugInfoList
{
id: storage
collapsible: true
title : qsTr("Storage")
itemDelegate:
Item {
anchors.fill: parent
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.value.split('\t')[0];
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
maximumLineCount: 1
clip: true
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.WrapAnywhere
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value.split('\t')[1];
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
}

31
mix/qml/js/Debugger.js

@ -4,7 +4,6 @@
var currentSelectedState = null; var currentSelectedState = null;
var currentDisplayedState = null; var currentDisplayedState = null;
var debugData = null; var debugData = null;
var codeMap = null;
var locations = []; var locations = [];
var locationMap = {}; var locationMap = {};
var breakpoints = {}; var breakpoints = {};
@ -56,7 +55,7 @@ function initLocations()
for (var i = 0; i < debugData.states.length - 1; i++) { for (var i = 0; i < debugData.states.length - 1; i++) {
var code = debugData.states[i].code; var code = debugData.states[i].code;
var location = code.documentId ? code.locations[codeStr(i)] : nullLocation; var location = code.documentId ? debugData.states[i].solidity : nullLocation;
if (location.start !== prevLocation.start || location.end !== prevLocation.end || code.documentId !== prevLocation.documentId) if (location.start !== prevLocation.start || location.end !== prevLocation.end || code.documentId !== prevLocation.documentId)
{ {
prevLocation = { start: location.start, end: location.end, documentId: code.documentId, state: i }; prevLocation = { start: location.start, end: location.end, documentId: code.documentId, state: i };
@ -65,6 +64,7 @@ function initLocations()
locationMap[i] = locations.length - 1; locationMap[i] = locations.length - 1;
} }
locations.push({ start: -1, end: -1, documentId: code.documentId, state: i }); locations.push({ start: -1, end: -1, documentId: code.documentId, state: i });
locationMap[debugData.states.length - 1] = locations.length - 1; locationMap[debugData.states.length - 1] = locations.length - 1;
} }
@ -93,12 +93,10 @@ function initSlider()
function setupInstructions(stateIndex) function setupInstructions(stateIndex)
{ {
var instructions = debugData.states[stateIndex].code.instructions; var instructions = debugData.states[stateIndex].code.instructions;
codeMap = {};
statesList.model.clear(); statesList.model.clear();
for (var i = 0; i < instructions.length; i++) { for (var i = 0; i < instructions.length; i++)
statesList.model.append(instructions[i]); statesList.model.append(instructions[i]);
codeMap[instructions[i].processIndex] = i;
}
callDataDump.listModel = debugData.states[stateIndex].callData.items; callDataDump.listModel = debugData.states[stateIndex].callData.items;
} }
@ -129,14 +127,14 @@ function display(stateIndex)
setupInstructions(stateIndex); setupInstructions(stateIndex);
if (debugData.states[stateIndex].dataIndex !== debugData.states[currentDisplayedState].dataIndex) if (debugData.states[stateIndex].dataIndex !== debugData.states[currentDisplayedState].dataIndex)
setupCallData(stateIndex); setupCallData(stateIndex);
var codeLine = codeStr(stateIndex);
var state = debugData.states[stateIndex]; var state = debugData.states[stateIndex];
var codeLine = state.instructionIndex;
highlightSelection(codeLine); highlightSelection(codeLine);
completeCtxInformation(state); completeCtxInformation(state);
currentDisplayedState = stateIndex; currentDisplayedState = stateIndex;
var docId = debugData.states[stateIndex].code.documentId; var docId = debugData.states[stateIndex].code.documentId;
if (docId) if (docId)
debugExecuteLocation(docId, locations[locationMap[stateIndex]]); debugExecuteLocation(docId, debugData.states[stateIndex].solidity);
} }
function displayFrame(frameIndex) function displayFrame(frameIndex)
@ -183,12 +181,6 @@ function selectState(stateIndex)
statesSlider.value = stateIndex; statesSlider.value = stateIndex;
} }
function codeStr(stateIndex)
{
var state = debugData.states[stateIndex];
return codeMap[state.curPC];
}
function highlightSelection(index) function highlightSelection(index)
{ {
statesList.positionViewAtRow(index, ListView.Center); statesList.positionViewAtRow(index, ListView.Center);
@ -206,6 +198,15 @@ function completeCtxInformation(state)
stack.listModel = state.debugStack; stack.listModel = state.debugStack;
storage.listModel = state.debugStorage; storage.listModel = state.debugStorage;
memoryDump.listModel = state.debugMemory; memoryDump.listModel = state.debugMemory;
if (state.solidity) {
solLocals.listModel = state.solidity.locals;
solStorage.listModel = state.solidity.storage;
solCallStack.listModel = state.solidity.callStack;
} else {
solLocals.listModel = [];
solStorage.listModel = [];
solCallStack.listModel = [];
}
} }
function isCallInstruction(index) function isCallInstruction(index)
@ -229,7 +230,7 @@ function breakpointHit(i)
{ {
var bpLocations = breakpoints[debugData.states[i].code.documentId]; var bpLocations = breakpoints[debugData.states[i].code.documentId];
if (bpLocations) { if (bpLocations) {
var location = locations[locationMap[i]]; var location = debugData.states[i].solidity;
if (location.start >= 0 && location.end >= location.start) if (location.start >= 0 && location.end >= location.start)
for (var b = 0; b < bpLocations.length; b++) for (var b = 0; b < bpLocations.length; b++)
if (locationsIntersect(location, bpLocations[b])) if (locationsIntersect(location, bpLocations[b]))

2
mix/res.qrc

@ -103,6 +103,8 @@
<file>qml/img/available_updates.png</file> <file>qml/img/available_updates.png</file>
<file>qml/DeploymentDialog.qml</file> <file>qml/DeploymentDialog.qml</file>
<file>qml/img/search_filled.png</file> <file>qml/img/search_filled.png</file>
<file>qml/StorageView.qml</file>
<file>qml/CallStack.qml</file>
<file>qml/img/help.png</file> <file>qml/img/help.png</file>
<file>qml/img/openedfolder.png</file> <file>qml/img/openedfolder.png</file>
<file>qml/img/b64.png</file> <file>qml/img/b64.png</file>

Loading…
Cancel
Save