diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index a41b7c083..731a5cb7e 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -43,6 +43,7 @@ using namespace dev; using namespace dev::eth; +using namespace std; namespace dev { @@ -54,7 +55,7 @@ class RpcConnector: public jsonrpc::AbstractServerConnector public: virtual bool StartListening() override { return true; } virtual bool StopListening() override { return true; } - virtual bool SendResponse(std::string const& _response, void*) override + virtual bool SendResponse(string const& _response, void*) override { m_response = QString::fromStdString(_response); return true; @@ -102,7 +103,7 @@ QString ClientModel::apiCall(QString const& _message) } catch (...) { - std::cerr << boost::current_exception_diagnostic_information(); + cerr << boost::current_exception_diagnostic_information(); return QString(); } } @@ -126,7 +127,7 @@ void ClientModel::mine() catch (...) { m_mining = false; - std::cerr << boost::current_exception_diagnostic_information(); + cerr << boost::current_exception_diagnostic_information(); emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } emit miningStateChanged(); @@ -149,7 +150,7 @@ QVariantMap ClientModel::contractAddresses() const { QVariantMap res; for (auto const& c: m_contractAddresses) - res.insert(c.first, QString::fromStdString(dev::toJS(c.second))); + res.insert(c.first, QString::fromStdString(toJS(c.second))); return res; } @@ -158,14 +159,14 @@ void ClientModel::setupState(QVariantMap _state) QVariantList balances = _state.value("accounts").toList(); QVariantList transactions = _state.value("transactions").toList(); - std::map accounts; + map accounts; for (auto const& b: balances) { QVariantMap address = b.toMap(); - accounts.insert(std::make_pair(Secret(address.value("secret").toString().toStdString()), (qvariant_cast(address.value("balance")))->toU256Wei())); + accounts.insert(make_pair(Secret(address.value("secret").toString().toStdString()), (qvariant_cast(address.value("balance")))->toU256Wei())); } - std::vector transactionSequence; + vector transactionSequence; for (auto const& t: transactions) { QVariantMap transaction = t.toMap(); @@ -203,7 +204,7 @@ void ClientModel::setupState(QVariantMap _state) executeSequence(transactionSequence, accounts); } -void ClientModel::executeSequence(std::vector const& _sequence, std::map const& _balances) +void ClientModel::executeSequence(vector const& _sequence, map const& _balances) { if (m_running) BOOST_THROW_EXCEPTION(ExecutionStateException()); @@ -225,7 +226,7 @@ void ClientModel::executeSequence(std::vector const& _seque if (!transaction.stdContractUrl.isEmpty()) { //std contract - dev::bytes const& stdContractCode = m_codeModel->getStdContractCode(transaction.contractId, transaction.stdContractUrl); + bytes const& stdContractCode = m_codeModel->getStdContractCode(transaction.contractId, transaction.stdContractUrl); TransactionSettings stdTransaction = transaction; stdTransaction.gas = 500000;// TODO: get this from std contracts library Address address = deployContract(stdContractCode, stdTransaction); @@ -238,7 +239,7 @@ void ClientModel::executeSequence(std::vector const& _seque CompiledContract const& compilerRes = m_codeModel->contract(transaction.contractId); QFunctionDefinition const* f = nullptr; bytes contractCode = compilerRes.bytes(); - std::shared_ptr contractDef = compilerRes.sharedContract(); + shared_ptr contractDef = compilerRes.sharedContract(); if (transaction.functionId.isEmpty()) f = contractDef->constructor(); else @@ -297,12 +298,12 @@ void ClientModel::executeSequence(std::vector const& _seque } catch(boost::exception const&) { - std::cerr << boost::current_exception_diagnostic_information(); + cerr << boost::current_exception_diagnostic_information(); emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); } - catch(std::exception const& e) + catch(exception const& e) { - std::cerr << boost::current_exception_diagnostic_information(); + cerr << boost::current_exception_diagnostic_information(); emit runFailed(e.what()); } m_running = false; @@ -329,16 +330,16 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) { QHash codeMap; codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code, codeMap)); - codeMaps.push_back(std::move(codeMap)); + codeMaps.push_back(move(codeMap)); //try to resolve contract for source level debugging auto nameIter = m_contractNames.find(code.address); - if (nameIter != m_contractNames.end()) + CompiledContract const* compilerRes = nullptr; + if (nameIter != m_contractNames.end() && (compilerRes = m_codeModel->tryGetContract(nameIter->second))) { - CompiledContract const& compilerRes = m_codeModel->contract(nameIter->second); - eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes.assemblyItems() : compilerRes.constructorAssemblyItems(); - codes.back()->setDocument(compilerRes.documentId()); - codeItems.push_back(std::move(assemblyItems)); - contracts.push_back(&compilerRes); + eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes->assemblyItems() : compilerRes->constructorAssemblyItems(); + codes.back()->setDocument(compilerRes->documentId()); + codeItems.push_back(move(assemblyItems)); + contracts.push_back(compilerRes); } else { @@ -353,8 +354,8 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) QVariantList states; QVariantList solCallStack; - std::map solLocals; // - std::map storageDeclarations; // + map solLocals; // + map storageDeclarations; // unsigned prevInstructionIndex = 0; for (MachineState const& s: _t.machineStates) @@ -366,7 +367,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) CompiledContract const* contract = contracts[s.codeIndex]; AssemblyItem const& instruction = codeItems[s.codeIndex][instructionIndex]; - if (instruction.type() == dev::eth::Push && !instruction.data()) + if (instruction.type() == eth::Push && !instruction.data()) { //register new local variable initialization auto localIter = contract->locals().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end)); @@ -374,7 +375,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) solLocals[s.stack.size()] = new QVariableDeclaration(debugData, localIter.value().name.toStdString(), localIter.value().type); } - if (instruction.type() == dev::eth::Tag) + if (instruction.type() == eth::Tag) { //track calls into functions AssemblyItem const& prevInstruction = codeItems[s.codeIndex][prevInstructionIndex]; @@ -389,7 +390,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) QVariantMap locals; QVariantList localDeclarations; QVariantMap localValues; - for(auto l: solLocals) + for (auto l: solLocals) if (l.first < (int)s.stack.size()) { if (l.second->type()->name().startsWith("mapping")) @@ -403,42 +404,50 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) QVariantMap storage; QVariantList storageDeclarationList; QVariantMap storageValues; - for(auto st: s.storage) - if (st.first < std::numeric_limits::max()) + for (auto st: s.storage) + if (st.first < numeric_limits::max()) { auto storageIter = contract->storage().find(static_cast(st.first)); if (storageIter != contract->storage().end()) { QVariableDeclaration* storageDec = nullptr; - auto decIter = storageDeclarations.find(storageIter.value().name); - if (decIter != storageDeclarations.end()) - storageDec = decIter->second; - else + for (SolidityDeclaration const& codeDec : storageIter.value()) { - storageDec = new QVariableDeclaration(debugData, storageIter.value().name.toStdString(), storageIter.value().type); - storageDeclarations[storageDec->name()] = storageDec; + if (codeDec.type.name.startsWith("mapping")) + continue; //mapping type not yet managed + auto decIter = storageDeclarations.find(codeDec.name); + if (decIter != storageDeclarations.end()) + storageDec = decIter->second; + else + { + storageDec = new QVariableDeclaration(debugData, codeDec.name.toStdString(), codeDec.type); + storageDeclarations[storageDec->name()] = storageDec; + } + storageDeclarationList.push_back(QVariant::fromValue(storageDec)); + storageValues[storageDec->name()] = formatStorageValue(storageDec->type()->type(), s.storage, codeDec.offset, codeDec.slot); } - if (storageDec->type()->name().startsWith("mapping")) - break; //mapping type not yet managed - storageDeclarationList.push_back(QVariant::fromValue(storageDec)); - storageValues[storageDec->name()] = formatValue(storageDec->type()->type(), st.second); } } storage["variables"] = storageDeclarationList; storage["values"] = storageValues; prevInstructionIndex = instructionIndex; - solState = new QSolState(debugData, std::move(storage), std::move(solCallStack), std::move(locals), instruction.getLocation().start, instruction.getLocation().end, QString::fromUtf8(instruction.getLocation().sourceName->c_str())); + + SourceLocation location = instruction.getLocation(); + if (contract->contract()->location() == location || contract->functions().contains(LocationPair(location.start, location.end))) + location = dev::SourceLocation(-1, -1, location.sourceName); + + solState = new QSolState(debugData, move(storage), move(solCallStack), move(locals), location.start, location.end, QString::fromUtf8(location.sourceName->c_str())); } states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState))); } - debugData->setStates(std::move(states)); + debugData->setStates(move(states)); debugDataReady(debugData); } -QVariant ClientModel::formatValue(SolidityType const& _type, dev::u256 const& _value) +QVariant ClientModel::formatValue(SolidityType const& _type, u256 const& _value) { ContractCallDataEncoder decoder; bytes val = toBigEndian(_value); @@ -446,6 +455,45 @@ QVariant ClientModel::formatValue(SolidityType const& _type, dev::u256 const& _v return res; } +QVariant ClientModel::formatStorageValue(SolidityType const& _type, map const& _storage, unsigned _offset, u256 const& _slot) +{ + u256 slot = _slot; + QVariantList values; + ContractCallDataEncoder decoder; + u256 count = 1; + if (_type.dynamicSize) + { + count = _storage.at(slot); + slot = fromBigEndian(sha3(toBigEndian(slot)).asBytes()); + } + else if (_type.array) + count = _type.count; + + unsigned offset = _offset; + while (count--) + { + + auto slotIter = _storage.find(slot); + u256 slotValue = slotIter != _storage.end() ? slotIter->second : u256(); + bytes slotBytes = toBigEndian(slotValue); + auto start = slotBytes.end() - _type.size - offset; + bytes val(32 - _type.size); //prepend with zeroes + val.insert(val.end(), start, start + _type.size); + values.append(decoder.decode(_type, val)); + offset += _type.size; + if ((offset + _type.size) > 32) + { + slot++; + offset = 0; + } + } + + if (!_type.array) + return values[0]; + + return QVariant::fromValue(values); +} + void ClientModel::emptyRecord() { debugDataReady(new QDebugData()); @@ -471,9 +519,9 @@ void ClientModel::callContract(Address const& _contract, bytes const& _data, Tra RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); - std::stringstream strGas; + stringstream strGas; strGas << blockInfo.gasUsed; - std::stringstream strNumber; + stringstream strNumber; strNumber << blockInfo.number; RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(toHex(blockInfo.hash().ref()))), tr("Gas Used: ") + QString::fromStdString(strGas.str()), QString(), QString(), false, RecordLogEntry::RecordType::Block); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); @@ -496,7 +544,7 @@ void ClientModel::onNewTransaction() unsigned recordIndex = tr.executonIndex; QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex); QString address = QString::fromStdString(toJS(tr.address)); - QString value = QString::fromStdString(dev::toString(tr.value)); + QString value = QString::fromStdString(toString(tr.value)); QString contract = address; QString function; QString returned; diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 0d7fc2df2..4b597a1ea 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -204,6 +204,7 @@ private: void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); + QVariant formatStorageValue(SolidityType const& _type, std::map const& _storage, unsigned _offset, dev::u256 const& _slot); std::atomic m_running; std::atomic m_mining; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 53ec34e2b..3c4972fcf 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -54,8 +54,8 @@ using namespace dev::solidity; class CollectDeclarationsVisitor: public ASTConstVisitor { public: - CollectDeclarationsVisitor(QHash* _functions, QHash* _locals, QHash* _storage): - m_functions(_functions), m_locals(_locals), m_storage(_storage), m_functionScope(false), m_storageSlot(0) {} + CollectDeclarationsVisitor(QHash* _functions, QHash* _locals): + m_functions(_functions), m_locals(_locals), m_functionScope(false) {} private: LocationPair nodeLocation(ASTNode const& _node) { @@ -79,31 +79,30 @@ private: SolidityDeclaration decl; decl.type = CodeModel::nodeType(_node.getType().get()); decl.name = QString::fromStdString(_node.getName()); + decl.slot = 0; + decl.offset = 0; if (m_functionScope) m_locals->insert(nodeLocation(_node), decl); - else - m_storage->insert(m_storageSlot++, decl); return true; } private: QHash* m_functions; QHash* m_locals; - QHash* m_storage; bool m_functionScope; - uint m_storageSlot; }; -dev::eth::AssemblyItems filterLocations(dev::eth::AssemblyItems const& _locations, dev::solidity::ContractDefinition const& _contract, QHash _functions) +QHash collectStorage(dev::solidity::ContractDefinition const& _contract) { - dev::eth::AssemblyItems result; - result.reserve(_locations.size()); - for (dev::eth::AssemblyItem item : _locations) + QHash result; + dev::solidity::ContractType contractType(_contract); + + for (auto v : contractType.getStateVariables()) { - dev::SourceLocation const& l = item.getLocation(); - if (_contract.getLocation() == l || _functions.contains(LocationPair(l.start, l.end))) - item.setLocation(dev::SourceLocation(-1, -1, l.sourceName)); - result.push_back(item); + dev::solidity::VariableDeclaration const* declaration = std::get<0>(v); + dev::u256 slot = std::get<1>(v); + unsigned offset = std::get<2>(v); + result[static_cast(slot)].push_back(SolidityDeclaration { QString::fromStdString(declaration->getName()), CodeModel::nodeType(declaration->getType().get()), slot, offset }); } return result; } @@ -133,10 +132,11 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler if (contractDefinition.getLocation().sourceName.get()) m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName); - CollectDeclarationsVisitor visitor(&m_functions, &m_locals, &m_storage); + CollectDeclarationsVisitor visitor(&m_functions, &m_locals); + m_storage = collectStorage(contractDefinition); contractDefinition.accept(visitor); - m_assemblyItems = filterLocations(_compiler.getRuntimeAssemblyItems(name), contractDefinition, m_functions); - m_constructorAssemblyItems = filterLocations(_compiler.getAssemblyItems(name), contractDefinition, m_functions); + m_assemblyItems = _compiler.getRuntimeAssemblyItems(name); + m_constructorAssemblyItems = _compiler.getAssemblyItems(name); } QString CompiledContract::codeHex() const @@ -220,7 +220,7 @@ QVariantMap CodeModel::contracts() const return result; } -CompiledContract* CodeModel::contractByDocumentId(QString _documentId) const +CompiledContract* CodeModel::contractByDocumentId(QString const& _documentId) const { Guard l(x_contractMap); for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); ++c) @@ -229,7 +229,7 @@ CompiledContract* CodeModel::contractByDocumentId(QString _documentId) const return nullptr; } -CompiledContract const& CodeModel::contract(QString _name) const +CompiledContract const& CodeModel::contract(QString const& _name) const { Guard l(x_contractMap); CompiledContract* res = m_contractMap.value(_name); @@ -238,6 +238,13 @@ CompiledContract const& CodeModel::contract(QString _name) const return *res; } +CompiledContract const* CodeModel::tryGetContract(QString const& _name) const +{ + Guard l(x_contractMap); + CompiledContract* res = m_contractMap.value(_name); + return res; +} + void CodeModel::releaseContracts() { for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); ++c) @@ -335,10 +342,9 @@ dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, co SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) { - SolidityType r { SolidityType::Type::UnsignedInteger, 32, false, false, QString::fromStdString(_type->toString()), std::vector(), std::vector() }; + SolidityType r { SolidityType::Type::UnsignedInteger, 32, 1, 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: @@ -367,7 +373,13 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) if (array->isByteArray()) r.type = SolidityType::Type::Bytes; else - r = nodeType(array->getBaseType().get()); + { + SolidityType elementType = nodeType(array->getBaseType().get()); + elementType.name = r.name; + r = elementType; + } + r.count = static_cast(array->getLength()); + r.dynamicSize = _type->isDynamicallySized(); r.array = true; } break; @@ -384,7 +396,10 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) r.type = SolidityType::Type::Struct; StructType const* s = dynamic_cast(_type); for(auto const& structMember: s->getMembers()) - r.members.push_back(SolidityDeclaration { QString::fromStdString(structMember.first), nodeType(structMember.second.get()) }); + { + auto slotAndOffset = s->getStorageOffsetsOfMember(structMember.first); + r.members.push_back(SolidityDeclaration { QString::fromStdString(structMember.first), nodeType(structMember.second.get()), slotAndOffset.first, slotAndOffset.second }); + } } break; case Type::Category::Function: diff --git a/mix/CodeModel.h b/mix/CodeModel.h index a4ca31e08..ea3694642 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -99,7 +99,7 @@ public: QHash const& functions() const { return m_functions; } QHash const& locals() const { return m_locals; } - QHash const& storage() const { return m_storage; } + QHash const& storage() const { return m_storage; } private: uint m_sourceHash; @@ -112,7 +112,7 @@ private: eth::AssemblyItems m_constructorAssemblyItems; QHash m_functions; QHash m_locals; - QHash m_storage; + QHash m_storage; friend class CodeModel; }; @@ -141,10 +141,14 @@ public: /// Get contract code by url. Contract is compiled on first access and cached dev::bytes const& getStdContractCode(QString const& _contractName, QString const& _url); /// Get contract by name - CompiledContract const& contract(QString _name) const; + /// Throws if not found + CompiledContract const& contract(QString const& _name) const; + /// Get contract by name + /// @returns nullptr if not found + CompiledContract const* tryGetContract(QString const& _name) const; /// Find a contract by document id /// @returns CompiledContract object or null if not found - Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const; + Q_INVOKABLE CompiledContract* contractByDocumentId(QString const& _documentId) const; /// Reset code model Q_INVOKABLE void reset() { reset(QVariantMap()); } /// Convert solidity type info to mix type diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index f991cd36e..56aeb1d34 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -48,33 +48,57 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function) void ContractCallDataEncoder::encode(QVariant const& _data, SolidityType const& _type) { + u256 count = 1; + QStringList strList; + if (_type.array) + { + if (_data.type() == QVariant::String) + strList = _data.toString().split(",", QString::SkipEmptyParts); //TODO: proper parsing + else + strList = _data.toStringList(); + count = strList.count(); + + } + else + strList.append(_data.toString()); + if (_type.dynamicSize) { - u256 count = 0; if (_type.type == SolidityType::Type::Bytes) - count = encodeSingleItem(_data, _type, m_dynamicData); + count = encodeSingleItem(_data.toString(), _type, m_dynamicData); else { - QVariantList list = qvariant_cast(_data); - for (auto const& item: list) + count = strList.count(); + for (auto const& item: strList) 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); + { + if (_type.array) + count = _type.count; + int c = static_cast(count); + if (strList.size() > c) + strList.erase(strList.begin() + c, strList.end()); + else + while (strList.size() < c) + strList.append(QString()); + + for (auto const& item: strList) + encodeSingleItem(item, _type, m_encodedData); + } } -unsigned ContractCallDataEncoder::encodeSingleItem(QVariant const& _data, SolidityType const& _type, bytes& _dest) +unsigned ContractCallDataEncoder::encodeSingleItem(QString 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(); + QString src = _data; bytes result; if ((src.startsWith("\"") && src.endsWith("\"")) || (src.startsWith("\'") && src.endsWith("\'"))) @@ -104,9 +128,9 @@ unsigned ContractCallDataEncoder::encodeSingleItem(QVariant const& _data, Solidi } unsigned dataSize = _type.dynamicSize ? result.size() : alignSize; + if (result.size() % alignSize != 0) + result.resize((result.size() & ~(alignSize - 1)) + alignSize); _dest.insert(_dest.end(), result.begin(), result.end()); - if ((_dest.size() - 4) % alignSize != 0) - _dest.resize((_dest.size() & ~(alignSize - 1)) + alignSize); return dataSize; } diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 50c28ea3b..805f26691 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -58,7 +58,7 @@ public: dev::bytes decodeBytes(dev::bytes const& _rawValue); private: - unsigned encodeSingleItem(QVariant const& _data, SolidityType const& _type, bytes& _dest); + unsigned encodeSingleItem(QString 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); diff --git a/mix/MixApplication.cpp b/mix/MixApplication.cpp index b11b825fb..54c860a8d 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -20,6 +20,7 @@ */ #include "MixApplication.h" +#include #include #include #include @@ -101,3 +102,16 @@ void MixApplication::initialize() MixApplication::~MixApplication() { } + +bool MixApplication::notify(QObject * receiver, QEvent * event) +{ + try + { + return QApplication::notify(receiver, event); + } + catch (...) + { + std::cerr << boost::current_exception_diagnostic_information(); + } + return false; +} diff --git a/mix/MixApplication.h b/mix/MixApplication.h index 9756f1b89..c1fd73d66 100644 --- a/mix/MixApplication.h +++ b/mix/MixApplication.h @@ -62,6 +62,7 @@ public: static void initialize(); virtual ~MixApplication(); QQmlApplicationEngine* engine() { return m_engine.get(); } + bool notify(QObject* _receiver, QEvent* _event) override; private: std::unique_ptr m_engine; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index cc200e62c..58cab151d 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -185,7 +185,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c // execute on a state if (!_call) { - _state.execute(lastHashes, _t); + dev::eth::ExecutionResult er =_state.execute(lastHashes, _t); if (_t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); // collect watches diff --git a/mix/QBasicNodeDefinition.cpp b/mix/QBasicNodeDefinition.cpp index 8905caef6..a38fc3c8c 100644 --- a/mix/QBasicNodeDefinition.cpp +++ b/mix/QBasicNodeDefinition.cpp @@ -28,7 +28,7 @@ namespace mix { QBasicNodeDefinition::QBasicNodeDefinition(QObject* _parent, solidity::Declaration const* _d): - QObject(_parent), m_name(QString::fromStdString(_d->getName())) + QObject(_parent), m_name(QString::fromStdString(_d->getName())), m_location(_d->getLocation()) { } diff --git a/mix/QBasicNodeDefinition.h b/mix/QBasicNodeDefinition.h index eb81d4f85..9179905eb 100644 --- a/mix/QBasicNodeDefinition.h +++ b/mix/QBasicNodeDefinition.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -47,9 +48,11 @@ public: QBasicNodeDefinition(QObject* _parent, std::string const& _name); /// Get the name of the node. QString name() const { return m_name; } + dev::SourceLocation const& location() { return m_location; } private: QString m_name; + dev::SourceLocation m_location; }; } diff --git a/mix/SolidityType.h b/mix/SolidityType.h index 9990e2e7f..accdb14b4 100644 --- a/mix/SolidityType.h +++ b/mix/SolidityType.h @@ -25,6 +25,7 @@ along with cpp-ethereum. If not, see . #include #include +#include namespace dev { @@ -49,6 +50,7 @@ struct SolidityType }; Type type; unsigned size; //in bytes, + unsigned count; bool array; bool dynamicSize; QString name; @@ -60,7 +62,11 @@ struct SolidityDeclaration { QString name; SolidityType type; + dev::u256 slot; + unsigned offset; }; +using SolidityDeclarations = std::vector; + } } diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index ad03f1456..e5c7e576d 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -12,6 +12,10 @@ Rectangle { id: debugPanel property alias transactionLog: transactionLog + property alias debugSlider: statesSlider + property alias solLocals: solLocals + property alias solStorage: solStorage + property alias solCallStack: solCallStack signal debugExecuteLocation(string documentId, var location) property string compilationErrorMessage property bool assemblyMode: false diff --git a/mix/qml/StepActionImage.qml b/mix/qml/StepActionImage.qml index e5129e379..262c99def 100644 --- a/mix/qml/StepActionImage.qml +++ b/mix/qml/StepActionImage.qml @@ -6,6 +6,7 @@ import QtQuick.Controls.Styles 1.1 Rectangle { id: buttonActionContainer + color: "transparent" property string disableStateImg property string enabledStateImg property string buttonTooltip diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 045b2eabc..2a0c5c68a 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -79,11 +79,14 @@ Column function getValue() { + var r = ""; if (value && value[modelData.name] !== undefined) - return value[modelData.name]; + r = value[modelData.name]; else if (modelData.type.category === QSolidityType.Struct) - return {}; - return ""; + r = {}; + if (Array.isArray(r)) + r = r.join(", "); + return r; } } } diff --git a/mix/qml/VariablesView.qml b/mix/qml/VariablesView.qml index 191ec52af..2670a5cb0 100644 --- a/mix/qml/VariablesView.qml +++ b/mix/qml/VariablesView.qml @@ -2,7 +2,6 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 import QtQuick.Layouts 1.1 -import "." DebugInfoList { diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 26324c89a..5fc2533aa 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -13,7 +13,10 @@ Item { property string pendingPageUrl: "" property bool initialized: false property alias urlInput: urlInput + property alias webView: webView + property string webContent; //for testing signal javaScriptMessage(var _level, string _sourceId, var _lineNb, string _content) + signal webContentReady function setPreviewUrl(url) { if (!initialized) @@ -57,6 +60,13 @@ Item { action(i); } + function getContent() { + webView.runJavaScript("getContent()", function(result) { + webContent = result; + webContentReady(); + }); + } + function changePage() { setPreviewUrl(urlInput.text); } diff --git a/mix/qml/html/WebContainer.html b/mix/qml/html/WebContainer.html index 9776f7633..30e203bed 100644 --- a/mix/qml/html/WebContainer.html +++ b/mix/qml/html/WebContainer.html @@ -46,6 +46,13 @@ executeJavaScript = function(script) { return ansi2html(printed); } +getContent = function() { + var preview = document.getElementById('preview'); + var doc = preview.contentDocument? preview.contentDocument: preview.contentWindow.document; + var body = doc.getElementsByTagName('body')[0]; + return body.innerHTML; +} +