From b98ef3b354ab44c71d706dc60c49b67db6eb7fc3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 2 Apr 2015 14:15:29 +0200 Subject: [PATCH 1/9] array formatting fixes --- mix/ClientModel.cpp | 115 +++++++++++++++++++++++++------------ mix/ClientModel.h | 1 + mix/CodeModel.cpp | 45 +++++++++++---- mix/CodeModel.h | 4 +- mix/MixClient.cpp | 2 +- mix/QVariableDeclaration.h | 5 +- mix/SolidityType.h | 6 ++ 7 files changed, 125 insertions(+), 53 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 6ba7e54f9..2e1ffaf8a 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; @@ -101,7 +102,7 @@ QString ClientModel::apiCall(QString const& _message) } catch (...) { - std::cerr << boost::current_exception_diagnostic_information(); + cerr << boost::current_exception_diagnostic_information(); return QString(); } } @@ -125,7 +126,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(); @@ -142,7 +143,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; } @@ -151,14 +152,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(); @@ -196,7 +197,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()); @@ -218,7 +219,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); @@ -231,7 +232,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 @@ -290,12 +291,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; @@ -322,7 +323,7 @@ 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()) @@ -330,7 +331,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) 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)); + codeItems.push_back(move(assemblyItems)); contracts.push_back(&compilerRes); } else @@ -346,8 +347,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) @@ -359,7 +360,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)); @@ -367,7 +368,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]; @@ -382,7 +383,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")) @@ -396,42 +397,45 @@ 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())); + solState = new QSolState(debugData, move(storage), move(solCallStack), move(locals), instruction.getLocation().start, instruction.getLocation().end, QString::fromUtf8(instruction.getLocation().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); @@ -439,6 +443,41 @@ 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--) + { + + bytes slotBytes = toBigEndian(_storage.at(slot)); + bytes val(slotBytes.begin() + offset, slotBytes.begin() + offset + _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()); @@ -464,9 +503,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); @@ -489,7 +528,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 a5d89d859..8c090f355 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -200,6 +200,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..5685d8ed8 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,19 +79,17 @@ 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) @@ -108,6 +106,24 @@ dev::eth::AssemblyItems filterLocations(dev::eth::AssemblyItems const& _location return result; } +QHash collectStorage(dev::solidity::ContractDefinition const& _contract) +{ + QHash result; + dev::solidity::ContractType const* contractType = dynamic_cast(_contract.getType(nullptr).get()); + if (!contractType) + return result; + + for (auto v : contractType->getStateVariables()) + { + 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; +} + + } //namespace void BackgroundWorker::queueCodeChange(int _jobId) @@ -133,7 +149,8 @@ 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); @@ -335,7 +352,7 @@ 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(); @@ -367,7 +384,12 @@ 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.array = true; } break; @@ -384,7 +406,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..8fd0606f4 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; }; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 7729c0ffe..fadc8a45a 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/QVariableDeclaration.h b/mix/QVariableDeclaration.h index cf9345061..4309550b2 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -26,14 +26,15 @@ #pragma once +namespace dev +{ + namespace solidity { class Type; class VariableDeclaration; } -namespace dev -{ namespace mix { 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; + } } From 7d341bd253b1056a68e1815eb48be202b6cf5561 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 5 Apr 2015 15:49:53 +0200 Subject: [PATCH 2/9] Improve addNode functionality when addNode is called during network startup. --- libp2p/Host.cpp | 16 +++++++++------- libp2p/Host.h | 7 +++++-- libwebthree/WebThree.cpp | 2 +- libwebthree/WebThree.h | 2 +- test/peer.cpp | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index e49baa1be..98efeb843 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -383,11 +383,12 @@ string Host::pocHost() void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short _udpNodePort, unsigned short _tcpPeerPort) { - // TODO: p2p clean this up (bring tested acceptor code over from network branch) - while (isWorking() && !m_run) - this_thread::sleep_for(chrono::milliseconds(50)); - if (!m_run) - return; + // return if network is stopped while waiting on Host::run() or nodeTable to start + while (!haveNetwork()) + if(isWorking()) + this_thread::sleep_for(chrono::milliseconds(50)); + else + return; if (_tcpPeerPort < 30300 || _tcpPeerPort > 30305) cwarn << "Non-standard port being recorded: " << _tcpPeerPort; @@ -636,8 +637,9 @@ void Host::startedWorking() else clog(NetNote) << "p2p.start.notice id:" << id().abridged() << "TCP Listen port is invalid or unavailable."; - m_nodeTable.reset(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort())); - m_nodeTable->setEventHandler(new HostNodeTableHandler(*this)); + shared_ptr nodeTable(new NodeTable(m_ioService, m_alias, bi::address::from_string(listenAddress()), listenPort())); + nodeTable->setEventHandler(new HostNodeTableHandler(*this)); + m_nodeTable = nodeTable; restoreNetwork(&m_restoreNetwork); clog(NetNote) << "p2p.started id:" << id().abridged(); diff --git a/libp2p/Host.h b/libp2p/Host.h index 753be3150..e4d43f233 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -141,9 +141,12 @@ public: /// Resets acceptor, socket, and IO service. Called by deallocator. void stop(); - /// @returns if network is running. - bool isStarted() const { return m_run; } + /// @returns if network has been started. + bool isStarted() const { return isWorking(); } + /// @returns if network is started and interactive. + bool haveNetwork() const { return m_run && !!m_nodeTable; } + NodeId id() const { return m_alias.pub(); } /// Validates and starts peer session, taking ownership of _io. Disconnects and returns false upon error. diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index a74d7fa55..8ea2133f0 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -74,7 +74,7 @@ WebThreeDirect::~WebThreeDirect() void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) { - auto had = haveNetwork(); + auto had = isNetworkStarted(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n, _dropPeers); diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index 92feb8d40..87cf62d4a 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -163,7 +163,7 @@ public: /// Sets the ideal number of peers. void setIdealPeerCount(size_t _n) override; - bool haveNetwork() const override { return m_net.isStarted(); } + bool haveNetwork() const override { return m_net.haveNetwork(); } void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers = false) override; diff --git a/test/peer.cpp b/test/peer.cpp index 904de0e9d..2aeb99469 100644 --- a/test/peer.cpp +++ b/test/peer.cpp @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(save_nodes) h->setIdealPeerCount(10); // starting host is required so listenport is available h->start(); - while (!h->isStarted()) + while (!h->haveNetwork()) this_thread::sleep_for(chrono::milliseconds(2)); hosts.push_back(h); } From 4f1f8560af917308f767139b2563cfa1a50f3f10 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 6 Apr 2015 14:29:11 +0200 Subject: [PATCH 3/9] coding standards --- libp2p/Host.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 98efeb843..5704f4727 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -385,7 +385,7 @@ void Host::addNode(NodeId const& _node, bi::address const& _addr, unsigned short { // return if network is stopped while waiting on Host::run() or nodeTable to start while (!haveNetwork()) - if(isWorking()) + if (isWorking()) this_thread::sleep_for(chrono::milliseconds(50)); else return; From a28b86c0380c6f5f2c836c994e6f051feee1b27e Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 6 Apr 2015 16:04:39 +0200 Subject: [PATCH 4/9] improved array parameters/variables debugging --- mix/ClientModel.cpp | 9 +++++-- mix/CodeModel.cpp | 8 +++--- mix/ContractCallDataEncoder.cpp | 44 +++++++++++++++++++++++++-------- mix/ContractCallDataEncoder.h | 2 +- mix/MixApplication.cpp | 14 +++++++++++ mix/MixApplication.h | 1 + mix/qml/StepActionImage.qml | 1 + mix/qml/StructView.qml | 9 ++++--- 8 files changed, 67 insertions(+), 21 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 2e1ffaf8a..b6139d949 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -453,6 +453,7 @@ QVariant ClientModel::formatStorageValue(SolidityType const& _type, map(sha3(toBigEndian(slot)).asBytes()); + cout << std::hex << slot; } else if (_type.array) count = _type.count; @@ -461,8 +462,12 @@ QVariant ClientModel::formatStorageValue(SolidityType const& _type, mapsecond : 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) diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 5685d8ed8..dc4253fb3 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -109,11 +109,9 @@ dev::eth::AssemblyItems filterLocations(dev::eth::AssemblyItems const& _location QHash collectStorage(dev::solidity::ContractDefinition const& _contract) { QHash result; - dev::solidity::ContractType const* contractType = dynamic_cast(_contract.getType(nullptr).get()); - if (!contractType) - return result; + dev::solidity::ContractType contractType(_contract); - for (auto v : contractType->getStateVariables()) + for (auto v : contractType.getStateVariables()) { dev::solidity::VariableDeclaration const* declaration = std::get<0>(v); dev::u256 slot = std::get<1>(v); @@ -355,7 +353,6 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) 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: @@ -390,6 +387,7 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) r = elementType; } r.count = static_cast(array->getLength()); + r.dynamicSize = _type->isDynamicallySized(); r.array = true; } break; diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index f1283f433..2b673a53b 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 e225158c7..6c27f9c57 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -56,7 +56,7 @@ public: void push(bytes const& _b); 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 028f1cb0b..d1e7fdb86 100644 --- a/mix/MixApplication.cpp +++ b/mix/MixApplication.cpp @@ -20,6 +20,7 @@ */ #include "MixApplication.h" +#include #include #include #include @@ -72,3 +73,16 @@ MixApplication::MixApplication(int& _argc, char* _argv[]): 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 49a6e0047..136cd8cf0 100644 --- a/mix/MixApplication.h +++ b/mix/MixApplication.h @@ -41,6 +41,7 @@ public: MixApplication(int& _argc, char* _argv[]); 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/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; } } } From 830da0c2cdec99966e1e91d3bd613cdcee2deebb Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 6 Apr 2015 20:07:37 +0200 Subject: [PATCH 5/9] Tests and test-related fixes --- mix/ClientModel.cpp | 18 ++-- mix/CodeModel.cpp | 26 ++---- mix/CodeModel.h | 4 + mix/QBasicNodeDefinition.cpp | 2 +- mix/QBasicNodeDefinition.h | 3 + mix/qml/Debugger.qml | 4 + mix/qml/VariablesView.qml | 1 - mix/qml/WebPreview.qml | 10 +++ mix/qml/html/WebContainer.html | 7 ++ mix/test/TestService.cpp | 6 ++ mix/test/TestService.h | 1 + mix/test/qml/TestMain.qml | 106 ++++-------------------- mix/test/qml/js/TestDebugger.js | 140 ++++++++++++++++++++++++++++++++ mix/test/qml/js/TestTutorial.js | 71 ++++++++++++++++ 14 files changed, 285 insertions(+), 114 deletions(-) create mode 100644 mix/test/qml/js/TestDebugger.js create mode 100644 mix/test/qml/js/TestTutorial.js diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index cf573965e..731a5cb7e 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -333,13 +333,13 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) 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()); + eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes->assemblyItems() : compilerRes->constructorAssemblyItems(); + codes.back()->setDocument(compilerRes->documentId()); codeItems.push_back(move(assemblyItems)); - contracts.push_back(&compilerRes); + contracts.push_back(compilerRes); } else { @@ -432,7 +432,12 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) storage["values"] = storageValues; prevInstructionIndex = instructionIndex; - solState = new QSolState(debugData, move(storage), move(solCallStack), 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))); @@ -460,7 +465,6 @@ QVariant ClientModel::formatStorageValue(SolidityType const& _type, map(sha3(toBigEndian(slot)).asBytes()); - cout << std::hex << slot; } else if (_type.array) count = _type.count; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index dc4253fb3..5fc4663d5 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -92,20 +92,6 @@ private: bool m_functionScope; }; -dev::eth::AssemblyItems filterLocations(dev::eth::AssemblyItems const& _locations, dev::solidity::ContractDefinition const& _contract, QHash _functions) -{ - dev::eth::AssemblyItems result; - result.reserve(_locations.size()); - for (dev::eth::AssemblyItem item : _locations) - { - 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); - } - return result; -} - QHash collectStorage(dev::solidity::ContractDefinition const& _contract) { QHash result; @@ -121,7 +107,6 @@ QHash collectStorage(dev::solidity::ContractDefi return result; } - } //namespace void BackgroundWorker::queueCodeChange(int _jobId) @@ -150,8 +135,8 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler 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 @@ -253,6 +238,13 @@ CompiledContract const& CodeModel::contract(QString _name) const return *res; } +CompiledContract const* CodeModel::tryGetContract(QString _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) diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 8fd0606f4..f790e3ac3 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -141,7 +141,11 @@ 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 + /// Throws if not found CompiledContract const& contract(QString _name) const; + /// Get contract by name + /// @returns nullptr if not found + CompiledContract const* tryGetContract(QString _name) const; /// Find a contract by document id /// @returns CompiledContract object or null if not found Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const; 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/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/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 d2b52be65..098b6b3fe 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 dfce64979..0a1f3a37c 100644 --- a/mix/qml/html/WebContainer.html +++ b/mix/qml/html/WebContainer.html @@ -43,6 +43,13 @@ executeJavaScript = function(script) { return JSON.stringify(obj, null, 2); } +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; +} +