From f994da400f57c945e328c67b40fe89d9c6d177f4 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 16 Mar 2015 15:21:38 +0100 Subject: [PATCH] debug formatting for structs and arrays --- mix/ClientModel.cpp | 82 ++++++++++------- mix/ClientModel.h | 4 +- mix/CodeModel.cpp | 8 +- mix/ContractCallDataEncoder.cpp | 103 ++++++++++++++++----- mix/ContractCallDataEncoder.h | 7 ++ mix/DebuggingStateWrapper.h | 14 +-- mix/QContractDefinition.cpp | 7 +- mix/QVariableDeclaration.cpp | 21 +++-- mix/QVariableDeclaration.h | 18 ++-- mix/QVariableDefinition.cpp | 132 --------------------------- mix/qml/DebugInfoList.qml | 69 ++++++++------ mix/qml/Debugger.qml | 4 +- mix/qml/SolidityTypeConverter.qml | 10 --- mix/qml/StructView.qml | 144 +++++++++++++++--------------- mix/qml/TransactionDialog.qml | 35 ++------ mix/qml/VariablesView.qml | 39 ++++++++ mix/qml/js/Debugger.js | 8 +- mix/res.qrc | 2 +- 18 files changed, 342 insertions(+), 365 deletions(-) delete mode 100644 mix/QVariableDefinition.cpp delete mode 100644 mix/qml/SolidityTypeConverter.qml create mode 100644 mix/qml/VariablesView.qml diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 2523a0d91..450f28433 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -186,14 +186,8 @@ void ClientModel::setupState(QVariantMap _state) { if (contractId.isEmpty() && m_context->codeModel()->hasContract()) //TODO: This is to support old project files, remove later contractId = m_context->codeModel()->contracts().keys()[0]; - QVariantList qParams = transaction.value("parameters").toList(); TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice, Secret(sender.toStdString())); - - for (QVariant const& variant: qParams) - { - QVariableDefinition* param = qvariant_cast(variant); - transactionSettings.parameterValues.push_back(param); - } + transactionSettings.parameterValues = transaction.value("parameters").toMap(); if (contractId == functionId || functionId == "Constructor") transactionSettings.functionId.clear(); @@ -251,11 +245,11 @@ void ClientModel::executeSequence(std::vector const& _seque BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString())); if (!transaction.functionId.isEmpty()) encoder.encode(f); - for (int p = 0; p < transaction.parameterValues.size(); p++) + for (QVariableDeclaration const* p: f->parametersList()) { - if (f->parametersList().size() <= p || f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type()) - BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(transaction.functionId.toStdString())); - encoder.push(transaction.parameterValues.at(p)->encodeValue()); + QSolidityType const* type = p->type(); + QVariant value = transaction.parameterValues.value(p->name()); + encoder.encode(value, type->type()); } if (transaction.functionId.isEmpty() || transaction.functionId == transaction.contractId) @@ -342,9 +336,9 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) data.push_back(QMachineState::getDebugCallData(debugData, d)); QVariantList states; - QStringList solCallStack; - std::map solLocals; // - QList returnStack; + QVariantList solCallStack; + std::map solLocals; // + std::map storageDeclarations; // unsigned prevInstructionIndex = 0; for (MachineState const& s: _t.machineStates) @@ -361,43 +355,62 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) //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(); + { + solLocals[s.stack.size()] = new QVariableDeclaration(debugData, localIter.value().name.toStdString(), localIter.value().type); + } } - if (instruction.type() == dev::eth::Tag) //TODO: use annotations + if (instruction.type() == dev::eth::Tag) { //track calls into functions + AssemblyItem const& prevInstruction = codeItems[s.codeIndex][prevInstructionIndex]; 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(); + if (functionIter != contract->functions().end() && ((prevInstruction.getJumpType() == AssemblyItem::JumpType::IntoFunction) || solCallStack.empty())) + solCallStack.push_back(QVariant::fromValue(functionIter.value())); + else if (prevInstruction.getJumpType() == AssemblyItem::JumpType::OutOfFunction && !solCallStack.empty()) solCallStack.pop_back(); - } } //format solidity context values - QStringList locals; + QVariantMap locals; + QVariantList localDeclarations; + QVariantMap localValues; 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])); + { + localDeclarations.push_back(QVariant::fromValue(l.second)); + localValues[l.second->name()] = formatValue(l.second->type()->type(), s.stack[l.first]); + } + locals["variables"] = localDeclarations; + locals["values"] = localValues; - QStringList storage; + QVariantMap storage; + QVariantList storageDeclarationList; + QVariantMap storageValues; for(auto st: s.storage) if (st.first < std::numeric_limits::max()) { auto storageIter = contract->storage().find(static_cast(st.first)); if (storageIter != contract->storage().end()) - storage.push_back(storageIter.value().name + "\t" + formatValue(storageIter.value().type, st.second)); + { + QVariableDeclaration* storageDec = nullptr; + auto decIter = storageDeclarations.find(storageIter.value().name); + if (decIter != storageDeclarations.end()) + storageDec = decIter->second; + else + { + storageDec = new QVariableDeclaration(debugData, storageIter.value().name.toStdString(), storageIter.value().type); + storageDeclarations[storageDec->name()] = storageDec; + } + storageDeclarationList.push_back(QVariant::fromValue(storageDec)); + storageValues[storageDec->name()] = formatValue(storageDec->type()->type(), st.second); + } } + storage["variables"] = storageDeclarationList; + storage["values"] = storageValues; prevInstructionIndex = instructionIndex; - solState = new QSolState(debugData, storage, solCallStack, locals, instruction.getLocation().start, instruction.getLocation().end); + solState = new QSolState(debugData, std::move(storage), std::move(solCallStack), std::move(locals), instruction.getLocation().start, instruction.getLocation().end); } states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState))); @@ -407,9 +420,12 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) debugDataReady(debugData); } -QString ClientModel::formatValue(SolidityType const&, dev::u256 const& _value) +QVariant ClientModel::formatValue(SolidityType const& _type, dev::u256 const& _value) { - return QString::fromStdString(prettyU256(_value)); + ContractCallDataEncoder decoder; + bytes val = toBigEndian(_value); + QVariant res = decoder.decode(_type, val); + return res; } void ClientModel::emptyRecord() diff --git a/mix/ClientModel.h b/mix/ClientModel.h index a12fe22e6..5c3615a2b 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -63,7 +63,7 @@ struct TransactionSettings /// Gas price u256 gasPrice; /// Mapping from contract function parameter name to value - QList parameterValues; + QVariantMap parameterValues; /// Standard contract url QString stdContractUrl; /// Sender @@ -199,7 +199,7 @@ private: void onNewTransaction(); void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); - QString formatValue(SolidityType const& _type, dev::u256 const& _value); + QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); AppContext* m_context; std::atomic m_running; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 72359c130..8af9e465c 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -107,6 +107,7 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler auto const& contractDefinition = _compiler.getContractDefinition(name); m_contract.reset(new QContractDefinition(nullptr, &contractDefinition)); QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership); + m_contract->moveToThread(QApplication::instance()->thread()); m_bytes = _compiler.getBytecode(_contractName.toStdString()); m_assemblyItems = _compiler.getRuntimeAssemblyItems(name); m_constructorAssemblyItems = _compiler.getAssemblyItems(name); @@ -312,6 +313,7 @@ SolidityType CodeModel::nodeType(solidity::Type const* _type) SolidityType r { SolidityType::Type::UnsignedInteger, 32, false, false, QString::fromStdString(_type->toString()), std::vector(), std::vector() }; if (!_type) return r; + r.dynamicSize = _type->isDynamicallySized(); switch (_type->getCategory()) { case Type::Category::Integer: @@ -336,8 +338,10 @@ SolidityType CodeModel::nodeType(solidity::Type const* _type) case Type::Category::Array: { ArrayType const* array = dynamic_cast(_type); - SolidityType elementType = nodeType(array->getBaseType().get()); - r = elementType; + if (array->isByteArray()) + r.type = SolidityType::Type::Bytes; + else + r = nodeType(array->getBaseType().get()); r.array = true; } break; diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 4e8b808b1..fc5dcee03 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -35,7 +35,9 @@ using namespace dev::mix; bytes ContractCallDataEncoder::encodedData() { - return m_encodedData; + bytes r(m_encodedData); + r.insert(r.end(), m_dynamicData.begin(), m_dynamicData.end()); + return r; } void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) @@ -44,6 +46,62 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end()); } +void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& _type) +{ + if (_type.dynamicSize) + { + u256 count = 0; + if (_type.type == SolidityType::Type::Bytes) + count = encodeSingleItem(_data, _type, m_dynamicData); + else + { + QVariantList list = qvariant_cast(_data); + for (auto const& item: list) + encodeSingleItem(item, _type, m_dynamicData); + count = list.size(); + } + bytes sizeEnc(32); + toBigEndian(count, sizeEnc); + m_encodedData.insert(m_encodedData.end(), sizeEnc.begin(), sizeEnc.end()); + } + else + encodeSingleItem(_data, _type, m_encodedData); +} + +unsigned ContractCallDataEncoder::encodeSingleItem(QVariant const& _data, SolidityType const& _type, bytes& _dest) +{ + if (_type.type == SolidityType::Type::Struct) + BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Struct parameters are not supported yet")); + + unsigned const alignSize = 32; + QString src = _data.toString(); + bytes result; + if (src.length() >= 2 && ((src.startsWith("\"") && src.endsWith("\"")) || (src.startsWith("\'") && src.endsWith("\'")))) + { + src = src.remove(src.length() - 1, 1).remove(0, 1); + QByteArray bytesAr = src.toLocal8Bit(); + result = bytes(bytesAr.begin(), bytesAr.end()); + } + else if (src.startsWith("0x")) + { + result = fromHex(src.toStdString().substr(2)); + if (_type.type != SolidityType::Type::Bytes) + result = padded(result, alignSize); + } + else + { + bigint i(src.toStdString()); + result = bytes(alignSize); + toBigEndian((u256)i, result); + } + + unsigned dataSize = _type.dynamicSize ? result.size() : alignSize; + _dest.insert(_dest.end(), result.begin(), result.end()); + if (_dest.size() % alignSize != 0) + _dest.resize((_dest.size() & ~(alignSize - 1)) + alignSize); + return dataSize; +} + void ContractCallDataEncoder::push(bytes const& _b) { m_encodedData.insert(m_encodedData.end(), _b.begin(), _b.end()); @@ -57,14 +115,6 @@ bigint ContractCallDataEncoder::decodeInt(dev::bytes const& _rawValue) return un; } -dev::bytes ContractCallDataEncoder::encodeInt(QString const& _str) -{ - dev::bigint i(_str.toStdString()); - bytes ret(32); - toBigEndian((u256)i, ret); - return ret; -} - QString ContractCallDataEncoder::toString(dev::bigint const& _int) { std::stringstream str; @@ -107,27 +157,38 @@ QString ContractCallDataEncoder::toString(dev::bytes const& _b) return QString::fromStdString(dev::toJS(_b)); } + +QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& _value) +{ + bytesConstRef value(&_value); + bytes rawParam(32); + value.populate(&rawParam); + QSolidityType::Type type = _type.type; + if (type == QSolidityType::Type::SignedInteger || type == QSolidityType::Type::UnsignedInteger || type == QSolidityType::Type::Address) + return QVariant::fromValue(toString(decodeInt(rawParam))); + else if (type == QSolidityType::Type::Bool) + return QVariant::fromValue(toString(decodeBool(rawParam))); + else if (type == QSolidityType::Type::Bytes || type == QSolidityType::Type::Hash) + return QVariant::fromValue(toString(decodeBytes(rawParam))); + else if (type == QSolidityType::Type::Struct) + return QVariant::fromValue(QString("struct")); //TODO + else + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found")); +} + QStringList ContractCallDataEncoder::decode(QList const& _returnParameters, bytes _value) { bytesConstRef value(&_value); bytes rawParam(32); QStringList r; + for (int k = 0; k <_returnParameters.length(); k++) { value.populate(&rawParam); - value = value.cropped(32); + value = value.cropped(32); QVariableDeclaration* dec = static_cast(_returnParameters.at(k)); - QSolidityType::Type type = dec->type()->type(); - if (type == QSolidityType::Type::SignedInteger || type == QSolidityType::Type::UnsignedInteger) - r.append(toString(decodeInt(rawParam))); - else if (type == QSolidityType::Type::Bool) - r.append(toString(decodeBool(rawParam))); - else if (type == QSolidityType::Type::Bytes || type == QSolidityType::Type::Hash) - r.append(toString(decodeBytes(rawParam))); - else if (type == QSolidityType::Type::Struct) - r.append("struct"); //TODO - else - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found")); + SolidityType const& type = dec->type()->type(); + r.append(decode(type, rawParam).toString()); } return r; } diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 9b5f8355b..3fa165d3f 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -33,6 +33,7 @@ namespace mix class QFunctionDefinition; class QVariableDeclaration; class QVariableDefinition; +class QSolidityType; /** * @brief Encode/Decode data to be sent to a transaction or to be displayed in a view. @@ -43,14 +44,19 @@ public: ContractCallDataEncoder() {} /// Encode hash of the function to call. void encode(QFunctionDefinition const* _function); + /// Encode data for corresponding type + void encode(QVariant const& _data, SolidityType const& _type); /// Decode variable in order to be sent to QML view. QStringList decode(QList const& _dec, bytes _value); + /// Decode single variable + QVariant decode(SolidityType const& _type, bytes const& _value); /// Get all encoded data encoded by encode function. bytes encodedData(); /// Push the given @a _b to the current param context. void push(bytes const& _b); private: + unsigned encodeSingleItem(QVariant const& _data, SolidityType const& _type, bytes& _dest); bigint decodeInt(dev::bytes const& _rawValue); dev::bytes encodeInt(QString const& _str); QString toString(dev::bigint const& _int); @@ -63,6 +69,7 @@ private: private: bytes m_encodedData; + bytes m_dynamicData; }; } diff --git a/mix/DebuggingStateWrapper.h b/mix/DebuggingStateWrapper.h index 7eb8c932c..b9eea9365 100644 --- a/mix/DebuggingStateWrapper.h +++ b/mix/DebuggingStateWrapper.h @@ -60,21 +60,21 @@ private: class QSolState: public QObject { 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(QVariantMap storage MEMBER m_storage CONSTANT) + Q_PROPERTY(QVariantList callStack MEMBER m_callStack CONSTANT) + Q_PROPERTY(QVariantMap locals MEMBER m_locals CONSTANT) Q_PROPERTY(int start MEMBER m_start CONSTANT) Q_PROPERTY(int end MEMBER m_end CONSTANT) public: - QSolState(QObject* _parent, QStringList const& _storage, QStringList const& _callStack, QStringList const& _locals, int _start, int _end): + QSolState(QObject* _parent, QVariantMap&& _storage, QVariantList&& _callStack, QVariantMap&& _locals, int _start, int _end): QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end) { } private: - QStringList m_storage; - QStringList m_callStack; - QStringList m_locals; + QVariantMap m_storage; + QVariantList m_callStack; + QVariantMap m_locals; int m_start; int m_end; }; diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index b08979ae4..899e804c5 100644 --- a/mix/QContractDefinition.cpp +++ b/mix/QContractDefinition.cpp @@ -34,13 +34,14 @@ using namespace dev::mix; QContractDefinition::QContractDefinition(QObject* _parent, dev::solidity::ContractDefinition const* _contract): QBasicNodeDefinition(_parent, _contract) { + QObject* parent = _parent ? _parent : this; if (_contract->getConstructor() != nullptr) - m_constructor = new QFunctionDefinition(_parent, ContractType(*_contract).getConstructorType()); + m_constructor = new QFunctionDefinition(parent, ContractType(*_contract).getConstructorType()); else - m_constructor = new QFunctionDefinition(_parent); + m_constructor = new QFunctionDefinition(parent); for (auto const& it: _contract->getInterfaceFunctions()) - m_functions.append(new QFunctionDefinition(_parent, it.second)); + m_functions.append(new QFunctionDefinition(parent, it.second)); } QFunctionDefinition const* QContractDefinition::getFunction(dev::FixedHash<4> _hash) const diff --git a/mix/QVariableDeclaration.cpp b/mix/QVariableDeclaration.cpp index b2245e295..7a08da116 100644 --- a/mix/QVariableDeclaration.cpp +++ b/mix/QVariableDeclaration.cpp @@ -47,17 +47,20 @@ QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& QSolidityType::QSolidityType(QObject* _parent, SolidityType const& _type): QObject(_parent), - m_type(_type.type), - m_size(_type.size), - m_name(_type.name) + m_type(_type) { - if (_type.type == Type::Struct) - for (auto const& structMember: _type.members) - m_members.push_back(QVariant::fromValue(new QVariableDeclaration(_parent, structMember.name.toStdString(), structMember.type))); +} - if (_type.type == Type::Enum) - for (auto const& enumName: _type.enumNames) - m_members.push_back(QVariant::fromValue(enumName)); +QVariantList QSolidityType::members() const +{ + QVariantList members; + if (m_type.type == Type::Struct) + for (auto const& structMember: m_type.members) + members.push_back(QVariant::fromValue(new QVariableDeclaration(parent(), structMember.name.toStdString(), structMember.type))); + if (m_type.type == Type::Enum) + for (auto const& enumName: m_type.enumNames) + members.push_back(QVariant::fromValue(enumName)); + return members; } } diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index e50832e52..3fcc00dcc 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -40,7 +40,7 @@ namespace mix class QSolidityType: public QObject { Q_OBJECT - Q_PROPERTY(int type READ type CONSTANT) //qml does not support enum properties + Q_PROPERTY(int category READ category CONSTANT) //qml does not support enum properties Q_PROPERTY(int size READ size CONSTANT) Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QVariantList members READ members CONSTANT) @@ -56,22 +56,20 @@ public: Hash, Bool, Address, - String, + Bytes, Enum, Struct }; Q_ENUMS(QmlType) - Type type() const { return m_type; } - int size() const { return m_size; } - QString name() const { return m_name; } - QVariantList members() const { return m_members; } + SolidityType const& type() const { return m_type; } + Type category() const { return m_type.type; } + int size() const { return m_type.size; } + QString name() const { return m_type.name; } + QVariantList members() const; private: - Type m_type; - int m_size; - QString m_name; - QVariantList m_members; + SolidityType m_type; }; class QVariableDeclaration: public QBasicNodeDefinition diff --git a/mix/QVariableDefinition.cpp b/mix/QVariableDefinition.cpp deleted file mode 100644 index 471fdd280..000000000 --- a/mix/QVariableDefinition.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - 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 . -*/ -/** @file QVariableDefinition.h - * @author Yann yann@ethdev.com - * @date 2014 - */ - -#include -#include -#include "QVariableDefinition.h" - -using namespace dev::mix; -/* -int QVariableDefinitionList::rowCount(const QModelIndex& _parent) const -{ - Q_UNUSED(_parent); - return m_def.size(); -} - -QVariant QVariableDefinitionList::data(const QModelIndex& _index, int _role) const -{ - if (_role != Qt::DisplayRole) - return QVariant(); - - int i = _index.row(); - if (i < 0 || i >= m_def.size()) - return QVariant(QVariant::Invalid); - - return QVariant::fromValue(m_def.at(i)); -} - -QHash QVariableDefinitionList::roleNames() const -{ - QHash roles; - roles[Qt::DisplayRole] = "variable"; - return roles; -} - -QVariableDefinition* QVariableDefinitionList::val(int _idx) -{ - if (_idx < 0 || _idx >= m_def.size()) - return nullptr; - return m_def.at(_idx); -} - -void QIntType::setValue(dev::bigint _value) -{ - m_bigIntvalue = _value; - std::stringstream str; - str << std::dec << m_bigIntvalue; - m_value = QString::fromStdString(str.str()); -} - -dev::bytes QIntType::encodeValue() -{ - dev::bigint i(value().toStdString()); - bytes ret(32); - toBigEndian((u256)i, ret); - return ret; -} - -void QIntType::decodeValue(dev::bytes const& _rawValue) -{ - dev::u256 un = dev::fromBigEndian(_rawValue); - if (un >> 255) - setValue(-s256(~un + 1)); - else - setValue(un); -} - -dev::bytes QHashType::encodeValue() -{ - QByteArray bytesAr = value().toLocal8Bit(); - bytes r = bytes(bytesAr.begin(), bytesAr.end()); - return padded(r, 32); -} - -void QHashType::decodeValue(dev::bytes const& _rawValue) -{ - std::string _ret = asString(unpadLeft(_rawValue)); - setValue(QString::fromStdString(_ret)); -} - -dev::bytes QRealType::encodeValue() -{ - return bytes(); -} - -void QRealType::decodeValue(dev::bytes const& _rawValue) -{ - Q_UNUSED(_rawValue); -} - -dev::bytes QStringType::encodeValue() -{ - QByteArray b = value().toUtf8(); - bytes r = bytes(b.begin(), b.end()); - return paddedRight(r, 32); -} - -void QStringType::decodeValue(dev::bytes const& _rawValue) -{ - setValue(QString::fromUtf8((char*)_rawValue.data())); -} - -dev::bytes QBoolType::encodeValue() -{ - return padded(jsToBytes(value().toStdString()), 32); -} - -void QBoolType::decodeValue(dev::bytes const& _rawValue) -{ - byte ret = _rawValue.at(_rawValue.size() - 1); - bool boolRet = (ret == byte(1)); - m_boolValue = boolRet; - m_value = m_boolValue ? "1" : "0"; -} -*/ diff --git a/mix/qml/DebugInfoList.qml b/mix/qml/DebugInfoList.qml index ae7e6fabe..721d5540b 100644 --- a/mix/qml/DebugInfoList.qml +++ b/mix/qml/DebugInfoList.qml @@ -11,6 +11,8 @@ ColumnLayout { property bool enableSelection: false; property real storedHeight: 0; property Component itemDelegate + property Component componentDelegate + property alias item: loader.item signal rowActivated(int index) spacing: 0 @@ -91,43 +93,54 @@ ColumnLayout { } } ] - TableView { - clip: true; - alternatingRowColors: false + Loader + { + id: loader anchors.top: parent.top anchors.left: parent.left anchors.topMargin: 3 anchors.leftMargin: 3 width: parent.width - 3 height: parent.height - 6 - model: listModel - selectionMode: enableSelection ? SelectionMode.SingleSelection : SelectionMode.NoSelection - headerDelegate: null - itemDelegate: root.itemDelegate - onHeightChanged: { - if (height <= 0 && collapsible) { - if (storedHeight <= 0) - storedHeight = 200; - storageContainer.state = "collapsed"; - } - else if (height > 0 && storageContainer.state == "collapsed") { - //TODO: fix increasing size - //storageContainer.state = ""; + sourceComponent: componentDelegate ? componentDelegate : table + } + Component + { + id: table + TableView + { + clip: true; + alternatingRowColors: false + anchors.fill: parent + model: listModel + selectionMode: enableSelection ? SelectionMode.SingleSelection : SelectionMode.NoSelection + headerDelegate: null + itemDelegate: root.itemDelegate + onHeightChanged: { + if (height <= 0 && collapsible) { + if (storedHeight <= 0) + storedHeight = 200; + storageContainer.state = "collapsed"; + } + else if (height > 0 && storageContainer.state == "collapsed") { + //TODO: fix increasing size + //storageContainer.state = ""; + } } - } - onActivated: rowActivated(row); - Keys.onPressed: { - if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < listModel.length) { - var str = ""; - for (var i = 0; i < listModel.length; i++) - str += listModel[i] + "\n"; - appContext.toClipboard(str); + onActivated: rowActivated(row); + Keys.onPressed: { + if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < listModel.length) { + var str = ""; + for (var i = 0; i < listModel.length; i++) + str += listModel[i] + "\n"; + appContext.toClipboard(str); + } } - } - TableViewColumn { - role: "modelData" - width: parent.width + TableViewColumn { + role: "modelData" + width: parent.width + } } } } diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 732d02f75..e73f8d668 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -574,7 +574,7 @@ Rectangle { Layout.maximumHeight: 800 onHeightChanged: machineStates.updateHeight(); visible: !assemblyMode - StorageView { + VariablesView { title : qsTr("Locals") anchors.fill: parent id: solLocals @@ -589,7 +589,7 @@ Rectangle { Layout.maximumHeight: 800 onHeightChanged: machineStates.updateHeight(); visible: !assemblyMode - StorageView { + VariablesView { title : qsTr("Members") anchors.fill: parent id: solStorage diff --git a/mix/qml/SolidityTypeConverter.qml b/mix/qml/SolidityTypeConverter.qml deleted file mode 100644 index e70c7c201..000000000 --- a/mix/qml/SolidityTypeConverter.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.0 - -Item -{ - function toJson(value) - { - if ( - } -} - diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index ba3c1847f..cbd457947 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -3,92 +3,88 @@ import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import org.ethereum.qml.QSolidityType 1.0 -Item +Column { - id: editRoot - property alias membersModel: repeater.model //js array - property var value + id: root + property alias members: repeater.model //js array + property var value : { x: "333" } property int level: 0 - Column + Layout.fillWidth: true + + Repeater { - id: paramRepeater + id: repeater + visible: model.length > 0 Layout.fillWidth: true - Layout.fillHeight: true - spacing: 3 - - Repeater + RowLayout { - id: repeater - height: 20 * model.length - visible: model.length > 0 - RowLayout - { - id: row - Layout.fillWidth: true - DefaultLabel { - id: typeLabel - text: modelData.type.name - Layout.preferredWidth: 50 - } + id: row + height: 20 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0) + Layout.fillWidth: true + DefaultLabel { + height: 20 + id: typeLabel + text: modelData.type.name + Layout.preferredWidth: 50 + } - DefaultLabel { - id: nameLabel - text: modelData.name - Layout.preferredWidth: 80 - } + DefaultLabel { + id: nameLabel + text: modelData.name + Layout.preferredWidth: 80 + } - DefaultLabel { - id: equalLabel - text: "=" - Layout.preferredWidth: 15 + DefaultLabel { + id: equalLabel + text: "=" + Layout.preferredWidth: 15 + } + Loader + { + id: typeLoader + Layout.preferredWidth: 150 + sourceComponent: + { + var t = modelData.type.category; + if (t === QSolidityType.SignedInteger || t === QSolidityType.UnsignedInteger) + return Qt.createComponent("qrc:/qml/QIntTypeView.qml"); + else if (t === QSolidityType.Bool) + return Qt.createComponent("qrc:/qml/QBoolTypeView.qml"); + else if (t === QSolidityType.Bytes) + return Qt.createComponent("qrc:/qml/QStringTypeView.qml"); + else if (t === QSolidityType.Hash || t === QSolidityType.Address) + return Qt.createComponent("qrc:/qml/QHashTypeView.qml"); + else if (t === QSolidityType.Struct) + return Qt.createComponent("qrc:/qml/StructView.qml"); + else + return undefined; } - Loader + onLoaded: { - id: typeLoader - Layout.preferredWidth: 150 - sourceComponent: - { - var t = modelData.type.type; - if (t === QSolidityType.SignedInteger || t === QSolidityType.UnsignedInteger) - return Qt.createComponent("qrc:/qml/QIntTypeView.qml"); - else if (t === QSolidityType.Bool) - return Qt.createComponent("qrc:/qml/QBoolTypeView.qml"); - else if (t === QSolidityType.Bytes) - return Qt.createComponent("qrc:/qml/QStringTypeView.qml"); - else if (t === QSolidityType.Hash || t === QSolidityType.Address) - return Qt.createComponent("qrc:/qml/QHashTypeView.qml"); - else if (t === QSolidityType.Struct) - return Qt.createComponent("qrc:/qml/StructView.qml"); - else - return undefined; + var ptype = members[index].type; + var pname = members[index].name; + var vals = value; + if (ptype.category === QSolidityType.Struct && !item.members) { + item.level = level + 1; + item.value = getValue(); + item.members = ptype.members; } - onLoaded: - { - var ptype = membersModel[index].type; - var pname = membersModel[index].name; - var vals = value; - if (ptype.type === QSolidityType.Struct && !item.membersModel) { - item.level = level + 1; - item.value = getValue(); - item.membersModel = ptype.members; - } - else - item.value = getValue(); - item.onValueChanged.connect(function() { - vals[pname] = item.value; - valueChanged(); - }); + else + item.value = getValue(); - } + item.onValueChanged.connect(function() { + vals[pname] = item.value; + valueChanged(); + }); + } - function getValue() - { - if (value && value[modelData.name]) - return value[modelData.name]; - else if (modelData.type.type === QSolidityType.Struct) - return {}; - return ""; - } + function getValue() + { + if (value && value[modelData.name] !== undefined) + return value[modelData.name]; + else if (modelData.type.category === QSolidityType.Struct) + return {}; + return ""; } } } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 0686cf201..64d62de69 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -77,7 +77,7 @@ Window { else { var contract = codeModel.contracts[contractId]; if (contract) { - var params = contract.contract.constructor.params; + var params = contract.contract.constructor.parameters; for (var p = 0; p < params.length; p++) loadParameter(params[p]); } @@ -125,23 +125,12 @@ Window { } } typeLoader.value = {} - typeLoader.membersModel = [] + typeLoader.members = [] typeLoader.value = paramValues; - typeLoader.membersModel = paramsModel; + typeLoader.members = paramsModel; } - /* - function param(name) - { - for (var k = 0; k < paramsModel.length; k++) - { - if (paramsModel[k].name === name) - return paramsModel[k]; - } - } - */ - function close() { visible = false; @@ -344,22 +333,14 @@ Window { { anchors.top: paramLabel.bottom anchors.topMargin: 10 - Layout.preferredWidth: 350 + Layout.fillWidth: true Layout.fillHeight: true visible: true;//paramsModel.length > 0 - Column + StructView { - id: paramRepeater - Layout.fillWidth: true - Layout.fillHeight: true - spacing: 3 - - StructView - { - id: typeLoader - Layout.preferredWidth: 150 - membersModel: paramsModel; - } + id: typeLoader + Layout.preferredWidth: 150 + members: paramsModel; } } diff --git a/mix/qml/VariablesView.qml b/mix/qml/VariablesView.qml new file mode 100644 index 000000000..36105da9e --- /dev/null +++ b/mix/qml/VariablesView.qml @@ -0,0 +1,39 @@ +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") + componentDelegate: structComp + + Component + { + id: structComp + ScrollView + { + property alias members: typeLoader.members; + property alias value: typeLoader.value; + anchors.fill: parent + StructView + { + id: typeLoader + members: [] + value: {} + Layout.preferredWidth: parent.width + } + } + } + + function setData(members, values) { + storage.item.value = {}; + storage.item.members = []; + storage.item.value = values; + storage.item.members = members; + } +} + diff --git a/mix/qml/js/Debugger.js b/mix/qml/js/Debugger.js index 23aa81844..3f5742fde 100644 --- a/mix/qml/js/Debugger.js +++ b/mix/qml/js/Debugger.js @@ -199,12 +199,12 @@ function completeCtxInformation(state) storage.listModel = state.debugStorage; memoryDump.listModel = state.debugMemory; if (state.solidity) { - solLocals.listModel = state.solidity.locals; - solStorage.listModel = state.solidity.storage; + solLocals.setData(state.solidity.locals.variables, state.solidity.locals.values); + solStorage.setData(state.solidity.storage.variables, state.solidity.storage.values); solCallStack.listModel = state.solidity.callStack; } else { - solLocals.listModel = []; - solStorage.listModel = []; + solLocals.setData([], {}); + solStorage.setData([], {}); solCallStack.listModel = []; } } diff --git a/mix/res.qrc b/mix/res.qrc index f20332eec..fa50d6dd8 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -110,8 +110,8 @@ qml/img/copy.png qml/img/broom.png qml/LogsPaneStyle.qml - qml/SolidityTypeConverter.qml qml/StructView.qml qml/img/console.png + qml/VariablesView.qml