From 8acd9b110732c8c690181c465011dc43a8f0427d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 9 Jan 2015 17:02:39 +0100 Subject: [PATCH 01/11] Work in prgress for creating natspec in alethzero at contract creation --- alethzero/MainWin.cpp | 30 ++++++++++++++- alethzero/MainWin.h | 5 ++- alethzero/NatspecHandler.cpp | 58 +++++++++++++++++++++++++++++ alethzero/NatspecHandler.h | 45 ++++++++++++++++++++++ alethzero/OurWebThreeStubServer.cpp | 12 +++--- alethzero/OurWebThreeStubServer.h | 6 ++- libethereum/Defaults.h | 1 + libsolidity/CompilerStack.cpp | 7 ++++ libsolidity/CompilerStack.h | 4 ++ 9 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 alethzero/NatspecHandler.cpp create mode 100644 alethzero/NatspecHandler.h diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 01b112b50..b05bcf1cc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -158,7 +158,7 @@ Main::Main(QWidget *parent) : m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir() + "/AlethZero", false, {"eth", "shh"})); m_qwebConnector.reset(new QWebThreeConnector()); - m_server.reset(new OurWebThreeStubServer(*m_qwebConnector, *web3(), keysAsVector(m_myKeys))); + m_server.reset(new OurWebThreeStubServer(*m_qwebConnector, *web3(), keysAsVector(m_myKeys), this)); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -1872,7 +1872,30 @@ void Main::on_send_clicked() debugFinished(); Secret s = i.secret(); if (isCreation()) + { ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); + + // LTODO: work in progress, recompile contract and get the hash of the code + // Also .. yeah improve the heuristic for Solidity and abstract to a function + string src = ui->data->toPlainText().toStdString(); + if (src.substr(0, 8) == "contract" || src.substr(0, 2) == "/*") // improve this heuristic + { + + dev::solidity::CompilerStack compiler; + try + { + m_data = compiler.compile(src, m_enableOptimizer); + for (std::string& s: compiler.getContractNames()) + m_natspecDB.add(compiler.getContractCodeHash(s), + compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER)); + + } + catch (...) + { + statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); + } + } + } else ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); return; @@ -2257,6 +2280,11 @@ void Main::on_post_clicked() whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); } +std::string Main::lookupNatSpec(dev::h256 const& _contractHash) const +{ + return m_natspecDB.retrieve(_contractHash); +} + void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 52a71102d..e20aac27d 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -37,6 +37,8 @@ #include #include +#include "NatspecHandler.h" + namespace Ui { class Main; } @@ -80,7 +82,7 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } - std::string lookupNatSpec(dev::h256 const& _contractCode) const { (void)_contractCode; return ""; } // TODO: actually implement with leveldb & a UI. + std::string lookupNatSpec(dev::h256 const& _contractHash) const; QList owned() const { return m_myIdentities + m_myKeys; } @@ -269,4 +271,5 @@ private: QWebThree* m_qweb = nullptr; static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr); + NatspecHandler m_natspecDB; }; diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp new file mode 100644 index 000000000..ae58208f1 --- /dev/null +++ b/alethzero/NatspecHandler.cpp @@ -0,0 +1,58 @@ +/* + 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 NatspecHandler.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "NatspecHandler.h" +#include +#include + +#include +#include + +using namespace dev; +using namespace dev::eth; + +NatspecHandler::NatspecHandler() +{ + std::string path = Defaults::dbPath(); + boost::filesystem::create_directories(path); + ldb::Options o; + o.create_if_missing = true; + ldb::DB::Open(o, path + "/natspec", &m_db); +} + + +void NatspecHandler::add(dev::h256 const& _contractHash, std::string const& _doc) +{ + bytes k = _contractHash.asBytes(); + std::string v = _doc; + m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); +} + +std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const +{ + bytes k = _contractHash.asBytes(); + std::string ret; + m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); + return ret; +} + + + diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h new file mode 100644 index 000000000..36554fc44 --- /dev/null +++ b/alethzero/NatspecHandler.h @@ -0,0 +1,45 @@ +/* + 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 NatspecHandler.h + * @author Lefteris Karapetsas + * @date 2015 + */ + +#pragma once + +#pragma warning(push) +#pragma warning(disable: 4100 4267) +#include +#pragma warning(pop) +#include + +namespace ldb = leveldb; + +class NatspecHandler +{ + public: + NatspecHandler(); + + void add(dev::h256 const& _contractHash, std::string const& _doc); + std::string retrieve(dev::h256 const& _contractHash) const; + + private: + ldb::ReadOptions m_readOptions; + ldb::WriteOptions m_writeOptions; + ldb::DB* m_db; +}; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 0d840e8d4..a156eeb1c 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -24,12 +24,14 @@ #include #include #include "MainWin.h" + using namespace std; using namespace dev; using namespace dev::eth; -OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts): - WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3) +OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, + std::vector const& _accounts, Main* main): + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main) {} std::string OurWebThreeStubServer::shh_newIdentity() @@ -41,13 +43,11 @@ std::string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const { - return true; + // return true; // To get the balance of the sender cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); - Main* main; // don't know this yet, should be a member and set at construction time by Main, who will construct us. - h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); if (contractCodeHash == EmptySHA3) @@ -57,7 +57,7 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con return true; // or whatever. } - std::string natspecJson = main->lookupNatSpec(contractCodeHash); + std::string natspecJson = m_main->lookupNatSpec(contractCodeHash); if (natspecJson.empty()) { diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 9ff973371..506a77884 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -24,12 +24,15 @@ #include #include +class Main; + class OurWebThreeStubServer: public QObject, public WebThreeStubServer { Q_OBJECT public: - OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector const& _accounts); + OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, + std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; virtual bool authenticate(dev::TransactionSkeleton const& _t) const; @@ -39,4 +42,5 @@ signals: private: dev::WebThreeDirect* m_web3; + Main* m_main; }; diff --git a/libethereum/Defaults.h b/libethereum/Defaults.h index 91d5872f7..3b19166b1 100644 --- a/libethereum/Defaults.h +++ b/libethereum/Defaults.h @@ -23,6 +23,7 @@ #include + namespace dev { namespace eth diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 174f9cd22..547e5fe21 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -200,6 +200,13 @@ bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimiz return stack.compile(_sourceCode, _optimize); } +dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) +{ + //LTODO + (void) _contractName; + return dev::h256(""); +} + void CompilerStack::reset(bool _keepSources) { m_parseSuccessful = false; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index afc9a5162..6b60f1dd3 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace dev { namespace solidity { @@ -104,6 +105,9 @@ public: /// scanning the source code - this is useful for printing exception information. static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false); + /// Get the runtime context's code hash for a contract. LTODO + dev::h256 getContractCodeHash(std::string const& _contractName); + private: /** * Information pertaining to one source unit, filled gradually during parsing and compilation. From 3b207c26e9745950c5d85f5852cf636480a73f00 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 12 Jan 2015 17:13:27 +0100 Subject: [PATCH 02/11] Alethzero: Showing a contract's function's hashes at creation --- alethzero/MainWin.cpp | 1 + libsolidity/CompilerStack.cpp | 18 ++++++++++++++++++ libsolidity/CompilerStack.h | 3 +++ 3 files changed, 22 insertions(+) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b05bcf1cc..5de05848e 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1657,6 +1657,7 @@ void Main::on_data_textChanged() solidity = "

Solidity

"; solidity += "
" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "
"; solidity += "
" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
"; + solidity += "
" + QString::fromStdString(compiler.getFunctionHashes()).toHtmlEscaped() + "
"; } catch (dev::Exception const& exception) { diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index 547e5fe21..f0d2e7f75 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -179,6 +179,24 @@ string const& CompilerStack::getMetadata(string const& _contractName, Documentat return *(*doc); } +std::string const CompilerStack::getFunctionHashes(std::string const& _contractName) +{ + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + std::string ret = ""; + Contract const& contract = getContract(_contractName); + auto interfaceFunctions = contract.contract->getInterfaceFunctions(); + + for (auto const& it: interfaceFunctions) + { + ret += it.first.abridged(); + ret += " :"; + ret += it.second->getName() + "\n"; + } + return ret; +} + Scanner const& CompilerStack::getScanner(string const& _sourceName) const { return *getSource(_sourceName).scanner; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 6b60f1dd3..da0adf57e 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -93,6 +93,9 @@ public: /// Can be one of 4 types defined at @c DocumentationType std::string const& getMetadata(std::string const& _contractName, DocumentationType _type) const; + /// Convenience function to return all contract method hashes in a string + std::string const getFunctionHashes(std::string const& _contractName = ""); + /// @returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner(std::string const& _sourceName = "") const; /// @returns the parsed source unit with the supplied name. From 18dd4515bd0c32e79275f4ebd98e3f505f684954 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 13 Jan 2015 15:59:42 +0100 Subject: [PATCH 03/11] A first version of Natspec warning popup - Runtime Contract code hash can now be retrieved from the Compiler - Using the hash the Natspec handler stores and later retrieves Natspec JSON for a given contract. --- alethzero/MainWin.cpp | 10 ++- alethzero/MainWin.h | 1 + alethzero/NatspecHandler.cpp | 17 +++++ alethzero/NatspecHandler.h | 11 +++ alethzero/OurWebThreeStubServer.cpp | 33 +++++--- libdevcore/CommonData.h | 3 + .../ethereumjs/example/natspec_contract.html | 76 +++++++++++++++++++ libsolidity/Compiler.cpp | 5 +- libsolidity/Compiler.h | 2 + libsolidity/CompilerStack.cpp | 20 +++-- libsolidity/CompilerStack.h | 10 ++- 11 files changed, 163 insertions(+), 25 deletions(-) create mode 100644 libjsqrc/ethereumjs/example/natspec_contract.html diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 5de05848e..ae24e4af0 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1887,8 +1887,11 @@ void Main::on_send_clicked() { m_data = compiler.compile(src, m_enableOptimizer); for (std::string& s: compiler.getContractNames()) - m_natspecDB.add(compiler.getContractCodeHash(s), + { + h256 contractHash = compiler.getContractCodeHash(s); + m_natspecDB.add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER)); + } } catch (...) @@ -2286,6 +2289,11 @@ std::string Main::lookupNatSpec(dev::h256 const& _contractHash) const return m_natspecDB.retrieve(_contractHash); } +std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) +{ + return m_natspecDB.getUserNotice(_contractHash, _methodName); +} + void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index e20aac27d..a7922287f 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -83,6 +83,7 @@ public: std::shared_ptr whisper() const { return m_webThree->whisper(); } std::string lookupNatSpec(dev::h256 const& _contractHash) const; + std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); QList owned() const { return m_myIdentities + m_myKeys; } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index ae58208f1..415f8ca2a 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -25,6 +25,8 @@ #include #include +#include + using namespace dev; using namespace dev::eth; @@ -55,4 +57,19 @@ std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const } +std::string NatspecHandler::getUserNotice(std::string const& json, std::string const& _methodName) +{ + Json::Value natspec, userNotice; + std::string retStr; + m_reader.parse(json, natspec); + retStr = natspec["methods"][_methodName]["notice"].toStyledString(); + + return (retStr == "null\n") ? "" : retStr; +} + +std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) +{ + return getUserNotice(retrieve(_contractHash), _methodName); +} + diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 36554fc44..9ea1103af 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -26,6 +26,7 @@ #pragma warning(disable: 4100 4267) #include #pragma warning(pop) +#include #include namespace ldb = leveldb; @@ -35,11 +36,21 @@ class NatspecHandler public: NatspecHandler(); + /// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation void add(dev::h256 const& _contractHash, std::string const& _doc); + /// Retrieves the natspec documentation as a string given a contract code hash std::string retrieve(dev::h256 const& _contractHash) const; + + /// Given a json natspec string, retrieve the user notice string + std::string getUserNotice(std::string const& json, std::string const& _methodName); + /// Given a contract code hash, retrieve the natspec documentation's user notice for that contract + /// @returns The user notice or an empty string if no natspec for the contract exists + /// or if the existing natspec does not document the @c _methodName + std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); private: ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; ldb::DB* m_db; + Json::Reader m_reader; }; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index a156eeb1c..6d771f219 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -43,8 +43,6 @@ std::string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const { - // return true; - // To get the balance of the sender cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); @@ -57,18 +55,31 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con return true; // or whatever. } - std::string natspecJson = m_main->lookupNatSpec(contractCodeHash); + //LTODO: Just for debugging here + cnote << "Contract hash:\n" << contractCodeHash; + cnote << "Transaction Value:\n" << "0x" + toHex(_t.value); + cnote << "Transaction Data:\n" << "0x" + toHex(_t.data); + - if (natspecJson.empty()) + //LTODO: Actually find and use the method name here + std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); + if (userNotice.empty()) { - // TODO: HUGE warning - we don't know what this will do! - return false; // or whatever. + QMessageBox userInput; + userInput.setText("Unverified Pending Transaction"); + userInput.setInformativeText("An undocumented transaction is about to be executed." + "Are you really sure you want to go through with it?"); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; } - // otherwise it's a transaction to contract for which we have the natspec: - // determine the actual message (embellish with real data) and ask user. - -// QMessageBox::question(); + // otherwise it's a transaction to a contract for which we have the natspec + QMessageBox userInput; + userInput.setText("Pending Transaction"); + userInput.setInformativeText(QString::fromStdString(userNotice)); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; - return true; } diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 6fab67452..2573995c5 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -110,6 +110,9 @@ inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toB inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } +/// Convenience function for conversion of a u256 to hex +inline std::string toHex(u256 val) { return toHex(toBigEndian(val)); } + /// Convenience function for toBigEndian. /// @returns a byte array just big enough to represent @a _val. template diff --git a/libjsqrc/ethereumjs/example/natspec_contract.html b/libjsqrc/ethereumjs/example/natspec_contract.html new file mode 100644 index 000000000..b8e3bc617 --- /dev/null +++ b/libjsqrc/ethereumjs/example/natspec_contract.html @@ -0,0 +1,76 @@ + + + + + + + + + +

contract

+
+
+ +
+ +
+ + + diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 782a7efe2..bd6571b9a 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -50,10 +50,9 @@ void Compiler::compileContract(ContractDefinition const& _contract, vectoraccept(*this); // Swap the runtime context with the creation-time context - CompilerContext runtimeContext; - swap(m_context, runtimeContext); + swap(m_context, m_runtimeContext); initializeContext(_contract, _magicGlobals, _contracts); - packIntoContractCreator(_contract, runtimeContext); + packIntoContractCreator(_contract, m_runtimeContext); } void Compiler::initializeContext(ContractDefinition const& _contract, vector const& _magicGlobals, diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index e83d1ed3a..c229a7a8a 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -35,6 +35,7 @@ public: void compileContract(ContractDefinition const& _contract, std::vector const& _magicGlobals, std::map const& _contracts); bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } + bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } private: @@ -70,6 +71,7 @@ private: bool const m_optimize; CompilerContext m_context; + CompilerContext m_runtimeContext; std::vector m_breakTags; ///< tag to jump to for a "break" statement std::vector m_continueTags; ///< tag to jump to for a "continue" statement eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index f0d2e7f75..b06423497 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace std; namespace dev @@ -117,6 +119,7 @@ void CompilerStack::compile(bool _optimize) contractBytecode); Contract& compiledContract = m_contracts[contract->getName()]; compiledContract.bytecode = compiler->getAssembledBytecode(); + compiledContract.runtimeBytecode = compiler->getRuntimeBytecode(); compiledContract.compiler = move(compiler); contractBytecode[compiledContract.contract] = &compiledContract.bytecode; } @@ -134,6 +137,16 @@ bytes const& CompilerStack::getBytecode(string const& _contractName) const return getContract(_contractName).bytecode; } +bytes const& CompilerStack::getRuntimeBytecode(std::string const& _contractName) const +{ + return getContract(_contractName).runtimeBytecode; +} + +dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) const +{ + return dev::sha3(getRuntimeBytecode(_contractName)); +} + void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName) const { getContract(_contractName).compiler->streamAssembly(_outStream); @@ -218,13 +231,6 @@ bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimiz return stack.compile(_sourceCode, _optimize); } -dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) -{ - //LTODO - (void) _contractName; - return dev::h256(""); -} - void CompilerStack::reset(bool _keepSources) { m_parseSuccessful = false; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index da0adf57e..202f1b321 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -76,7 +76,13 @@ public: /// @returns the compiled bytecode bytes const& compile(std::string const& _sourceCode, bool _optimize = false); + /// Gets the assembled bytecode for a contract bytes const& getBytecode(std::string const& _contractName = "") const; + /// Get the runtime context's bytecode for a contract + bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; + /// Get the runtime context's code hash for a contract + dev::h256 getContractCodeHash(std::string const& _contractName = "") const; + /// Streams a verbose version of the assembly to @a _outStream. /// Prerequisite: Successful compilation. void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "") const; @@ -108,9 +114,6 @@ public: /// scanning the source code - this is useful for printing exception information. static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false); - /// Get the runtime context's code hash for a contract. LTODO - dev::h256 getContractCodeHash(std::string const& _contractName); - private: /** * Information pertaining to one source unit, filled gradually during parsing and compilation. @@ -128,6 +131,7 @@ private: ContractDefinition const* contract = nullptr; std::shared_ptr compiler; bytes bytecode; + bytes runtimeBytecode; std::shared_ptr interfaceHandler; mutable std::unique_ptr interface; mutable std::unique_ptr solidityInterface; From 5b36d3c163bf11424a5fcfad04c5ec9090cff33e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 13 Jan 2015 16:15:32 +0100 Subject: [PATCH 04/11] Natspec method key is now the Canonical Signature --- libsolidity/InterfaceHandler.cpp | 4 +-- test/SolidityNatspecJSON.cpp | 42 ++++++++++++++++---------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index a5c6f4a1d..4c7ae5f45 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -106,7 +106,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi if (!m_notice.empty()) {// since @notice is the only user tag if missing function should not appear user["notice"] = Json::Value(m_notice); - methods[it.second->getName()] = user; + methods[it.second->getCanonicalSignature()] = user; } } } @@ -162,7 +162,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin method["return"] = m_return; if (!method.empty()) // add the function, only if we have any documentation to add - methods[it.second->getName()] = method; + methods[it.second->getCanonicalSignature()] = method; } } doc["methods"] = methods; diff --git a/test/SolidityNatspecJSON.cpp b/test/SolidityNatspecJSON.cpp index 7edb97a7b..d43aebc2b 100644 --- a/test/SolidityNatspecJSON.cpp +++ b/test/SolidityNatspecJSON.cpp @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(user_basic_test) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" + " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* devNatspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256)\":{ \n" " \"details\": \"Multiplies a number by 7\"\n" " }\n" " }\n" @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* userNatspec = "{" "\"methods\":{" - " \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}" + " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" "}}"; checkNatspec(sourceCode, devNatspec, false); @@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(user_multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" + " \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -157,9 +157,9 @@ BOOST_AUTO_TEST_CASE(user_multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," - " \"divide\":{ \"notice\": \"Divides `input` by `div`\"}," - " \"sub\":{ \"notice\": \"Subtracts 3 from `input`\"}" + " \"mul_and_add(uint256,uint256)\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}," + " \"divide(uint256,uint256)\":{ \"notice\": \"Divides `input` by `div`\"}," + " \"sub(int256)\":{ \"notice\": \"Subtracts 3 from `input`\"}" "}}"; checkNatspec(sourceCode, natspec, true); @@ -205,7 +205,7 @@ BOOST_AUTO_TEST_CASE(dev_desc_after_nl) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \" Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" @@ -228,7 +228,7 @@ BOOST_AUTO_TEST_CASE(dev_multiple_params) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" @@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(dev_mutiline_param_description) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -289,21 +289,21 @@ BOOST_AUTO_TEST_CASE(dev_multiple_functions) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter\",\n" " \"second\": \"Documentation for the second parameter\"\n" " }\n" " },\n" - " \"divide\":{ \n" + " \"divide(uint256,uint256)\":{ \n" " \"details\": \"Divides 2 numbers\",\n" " \"params\": {\n" " \"input\": \"Documentation for the input parameter\",\n" " \"div\": \"Documentation for the div parameter\"\n" " }\n" " },\n" - " \"sub\":{ \n" + " \"sub(int256)\":{ \n" " \"details\": \"Subtracts 3 from `input`\",\n" " \"params\": {\n" " \"input\": \"Documentation for the input parameter\"\n" @@ -327,7 +327,7 @@ BOOST_AUTO_TEST_CASE(dev_return) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -353,7 +353,7 @@ BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(dev_multiline_comment) char const* natspec = "{" "\"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" " \"params\": {\n" " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" @@ -432,7 +432,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_no_doc) char const* natspec = "{" " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE(dev_contract_doc) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" @@ -477,7 +477,7 @@ BOOST_AUTO_TEST_CASE(dev_author_at_function) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\",\n" " \"author\": \"John Doe\",\n" " }\n" @@ -501,7 +501,7 @@ BOOST_AUTO_TEST_CASE(dev_title_at_function_error) " \"author\": \"Lefteris\"," " \"title\": \"Just a test contract\"," " \"methods\":{" - " \"mul\":{ \n" + " \"mul(uint256,uint256)\":{ \n" " \"details\": \"Mul function\"\n" " }\n" " }\n" From e7ac3ba8697f49e22290c6033d9693b8c8efc703 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 13 Jan 2015 17:54:09 +0100 Subject: [PATCH 05/11] Natspechandler: Get function hash from transaction data --- alethzero/MainWin.cpp | 5 +++ alethzero/MainWin.h | 1 + alethzero/NatspecHandler.cpp | 33 ++++++++++++++++++- alethzero/NatspecHandler.h | 6 +++- alethzero/OurWebThreeStubServer.cpp | 8 +++-- .../ethereumjs/example/natspec_contract.html | 2 +- 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ae24e4af0..50a362150 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2294,6 +2294,11 @@ std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::s return m_natspecDB.getUserNotice(_contractHash, _methodName); } +std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +{ + return m_natspecDB.getUserNotice(_contractHash, _transactionData); +} + void Main::refreshWhispers() { ui->whispers->clear(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index a7922287f..64de6a9e9 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -84,6 +84,7 @@ public: std::string lookupNatSpec(dev::h256 const& _contractHash) const; std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); + std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData); QList owned() const { return m_myIdentities + m_myKeys; } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 415f8ca2a..2a99e69ef 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -25,7 +25,9 @@ #include #include +#include #include +#include using namespace dev; @@ -62,14 +64,43 @@ std::string NatspecHandler::getUserNotice(std::string const& json, std::string c Json::Value natspec, userNotice; std::string retStr; m_reader.parse(json, natspec); - retStr = natspec["methods"][_methodName]["notice"].toStyledString(); + retStr = natspec["methods"][_methodName]["notice"].asString(); return (retStr == "null\n") ? "" : retStr; } +std::string NatspecHandler::getUserNotice(std::string const& json, const dev::bytes& _transactionData) +{ + Json::Value natspec, userNotice; + std::string retStr; + m_reader.parse(json, natspec); + bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4); + FixedHash<4> transactionFunctionHash(transactionFunctionPart); + + // for (auto const& it: natspec["methods"]) + Json::Value methods = natspec["methods"]; + for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it ) + { + std::string functionSig = it.key().asString(); + FixedHash<4> functionHash(dev::sha3(functionSig)); + + if (functionHash == transactionFunctionHash) { + return (*it)["notice"].asString(); + } + } + + // not found + return ""; +} + std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) { return getUserNotice(retrieve(_contractHash), _methodName); } +std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +{ + return getUserNotice(retrieve(_contractHash), _transactionData); +} + diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 9ea1103af..23e05fa51 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -43,10 +43,14 @@ class NatspecHandler /// Given a json natspec string, retrieve the user notice string std::string getUserNotice(std::string const& json, std::string const& _methodName); + std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData); /// Given a contract code hash, retrieve the natspec documentation's user notice for that contract + std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); + /// Given a contract code hash and the transaction's data retrieve the natspec documention's + /// user notice for that transaction. /// @returns The user notice or an empty string if no natspec for the contract exists /// or if the existing natspec does not document the @c _methodName - std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); + std::string getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionDacta); private: ldb::ReadOptions m_readOptions; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 6d771f219..b5be016ea 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -22,6 +22,7 @@ #include "OurWebThreeStubServer.h" #include +#include #include #include "MainWin.h" @@ -62,7 +63,8 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con //LTODO: Actually find and use the method name here - std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); + // std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); + std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data); if (userNotice.empty()) { QMessageBox userInput; @@ -77,8 +79,10 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con // otherwise it's a transaction to a contract for which we have the natspec QMessageBox userInput; userInput.setText("Pending Transaction"); - userInput.setInformativeText(QString::fromStdString(userNotice)); + userInput.setInformativeText(QString::fromStdString(userNotice + "\n Do you wish to allow this?")); userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.button(QMessageBox::Ok)->setText("Allow"); + userInput.button(QMessageBox::Cancel)->setText("Reject"); userInput.setDefaultButton(QMessageBox::Cancel); return userInput.exec() == QMessageBox::Ok; diff --git a/libjsqrc/ethereumjs/example/natspec_contract.html b/libjsqrc/ethereumjs/example/natspec_contract.html index b8e3bc617..94edda68d 100644 --- a/libjsqrc/ethereumjs/example/natspec_contract.html +++ b/libjsqrc/ethereumjs/example/natspec_contract.html @@ -12,7 +12,7 @@ // solidity source code var source = "" + "contract test {\n" + - " /// @notice This is an awesome function for multiplication. \n" + + " /// @notice Will multiplty `a` by 7. \n" + " function multiply(uint a) returns(uint d) {\n" + " return a * 7;\n" + " }\n" + From 08a1566b85dc42d0e5beab4819447b2c6d61ca11 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 09:28:52 +0100 Subject: [PATCH 06/11] Cleaned up some unused functions --- alethzero/MainWin.cpp | 5 ----- alethzero/MainWin.h | 1 - alethzero/NatspecHandler.cpp | 20 +------------------ alethzero/NatspecHandler.h | 5 +---- alethzero/OurWebThreeStubServer.cpp | 2 +- .../ethereumjs/example/natspec_contract.html | 3 ++- 6 files changed, 5 insertions(+), 31 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 50a362150..2e23c8dc7 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2289,11 +2289,6 @@ std::string Main::lookupNatSpec(dev::h256 const& _contractHash) const return m_natspecDB.retrieve(_contractHash); } -std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) -{ - return m_natspecDB.getUserNotice(_contractHash, _methodName); -} - std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) { return m_natspecDB.getUserNotice(_contractHash, _transactionData); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 64de6a9e9..7a8df3bdf 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -83,7 +83,6 @@ public: std::shared_ptr whisper() const { return m_webThree->whisper(); } std::string lookupNatSpec(dev::h256 const& _contractHash) const; - std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData); QList owned() const { return m_myIdentities + m_myKeys; } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 2a99e69ef..3449d0aec 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -42,7 +42,6 @@ NatspecHandler::NatspecHandler() ldb::DB::Open(o, path + "/natspec", &m_db); } - void NatspecHandler::add(dev::h256 const& _contractHash, std::string const& _doc) { bytes k = _contractHash.asBytes(); @@ -58,17 +57,6 @@ std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const return ret; } - -std::string NatspecHandler::getUserNotice(std::string const& json, std::string const& _methodName) -{ - Json::Value natspec, userNotice; - std::string retStr; - m_reader.parse(json, natspec); - retStr = natspec["methods"][_methodName]["notice"].asString(); - - return (retStr == "null\n") ? "" : retStr; -} - std::string NatspecHandler::getUserNotice(std::string const& json, const dev::bytes& _transactionData) { Json::Value natspec, userNotice; @@ -77,9 +65,8 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4); FixedHash<4> transactionFunctionHash(transactionFunctionPart); - // for (auto const& it: natspec["methods"]) Json::Value methods = natspec["methods"]; - for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it ) + for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it) { std::string functionSig = it.key().asString(); FixedHash<4> functionHash(dev::sha3(functionSig)); @@ -93,11 +80,6 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by return ""; } -std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName) -{ - return getUserNotice(retrieve(_contractHash), _methodName); -} - std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) { return getUserNotice(retrieve(_contractHash), _transactionData); diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 23e05fa51..e9b2f50f0 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -41,11 +41,8 @@ class NatspecHandler /// Retrieves the natspec documentation as a string given a contract code hash std::string retrieve(dev::h256 const& _contractHash) const; - /// Given a json natspec string, retrieve the user notice string - std::string getUserNotice(std::string const& json, std::string const& _methodName); + /// Given a json natspec string and the transaction data return the user notice std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData); - /// Given a contract code hash, retrieve the natspec documentation's user notice for that contract - std::string getUserNotice(dev::h256 const& _contractHash, std::string const& _methodName); /// Given a contract code hash and the transaction's data retrieve the natspec documention's /// user notice for that transaction. /// @returns The user notice or an empty string if no natspec for the contract exists diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index b5be016ea..1b8023ade 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -53,7 +53,7 @@ bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) con { // recipient has no code - nothing special about this transaction. // TODO: show basic message for value transfer. - return true; // or whatever. + return true; } //LTODO: Just for debugging here diff --git a/libjsqrc/ethereumjs/example/natspec_contract.html b/libjsqrc/ethereumjs/example/natspec_contract.html index 94edda68d..8d12b4a81 100644 --- a/libjsqrc/ethereumjs/example/natspec_contract.html +++ b/libjsqrc/ethereumjs/example/natspec_contract.html @@ -68,7 +68,8 @@
From ee682f19492c3a981475451859d8ca7216d65520 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 10:03:09 +0100 Subject: [PATCH 07/11] Cleaning up debug messages and abstracting some functionality --- alethzero/MainWin.cpp | 17 ++++++---- alethzero/MainWin.h | 3 ++ alethzero/OurWebThreeStubServer.cpp | 48 ++++++++++------------------- alethzero/OurWebThreeStubServer.h | 2 ++ 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2e23c8dc7..41a1b1b62 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1635,6 +1635,13 @@ static shh::Topic topicFromText(QString _s) return ret; } + +bool Main::sourceIsSolidity(std::string const& _source) +{ + // TODO: Improve this heuristic + return (_source.substr(0, 8) == "contract" || _source.substr(0, 2) == "/*"); +} + void Main::on_data_textChanged() { m_pcWarp.clear(); @@ -1648,7 +1655,7 @@ void Main::on_data_textChanged() { m_data = fromHex(src); } - else if (src.substr(0, 8) == "contract" || src.substr(0, 5) == "//sol") // improve this heuristic + else if (sourceIsSolidity(src)) { dev::solidity::CompilerStack compiler; try @@ -1874,12 +1881,11 @@ void Main::on_send_clicked() Secret s = i.secret(); if (isCreation()) { + // If execution is a contract creation, add Natspec to + // a local Natspec LEVELDB ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); - - // LTODO: work in progress, recompile contract and get the hash of the code - // Also .. yeah improve the heuristic for Solidity and abstract to a function string src = ui->data->toPlainText().toStdString(); - if (src.substr(0, 8) == "contract" || src.substr(0, 2) == "/*") // improve this heuristic + if (sourceIsSolidity(src)) { dev::solidity::CompilerStack compiler; @@ -1892,7 +1898,6 @@ void Main::on_send_clicked() m_natspecDB.add(contractHash, compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER)); } - } catch (...) { diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 7a8df3bdf..23280eec4 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -230,6 +230,9 @@ private: void refreshBlockCount(); void refreshBalances(); + /// Attempts to infer that @c _source contains Solidity code + bool sourceIsSolidity(std::string const& _source); + std::unique_ptr ui; std::unique_ptr m_webThree; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 1b8023ade..ff477dd29 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -42,48 +42,32 @@ std::string OurWebThreeStubServer::shh_newIdentity() return toJS(kp.pub()); } -bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, std::string const& _text) const { - // To get the balance of the sender - cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from); + // otherwise it's a transaction to a contract for which we have the natspec + QMessageBox userInput; + userInput.setText(QString::fromStdString(_title)); + userInput.setInformativeText(QString::fromStdString(_text + "\n Do you wish to allow this?")); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.button(QMessageBox::Ok)->setText("Allow"); + userInput.button(QMessageBox::Cancel)->setText("Reject"); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; +} +bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const +{ h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); - if (contractCodeHash == EmptySHA3) - { // recipient has no code - nothing special about this transaction. // TODO: show basic message for value transfer. return true; - } - - //LTODO: Just for debugging here - cnote << "Contract hash:\n" << contractCodeHash; - cnote << "Transaction Value:\n" << "0x" + toHex(_t.value); - cnote << "Transaction Data:\n" << "0x" + toHex(_t.data); - - //LTODO: Actually find and use the method name here - // std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, "multiply"); std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data); if (userNotice.empty()) - { - QMessageBox userInput; - userInput.setText("Unverified Pending Transaction"); - userInput.setInformativeText("An undocumented transaction is about to be executed." - "Are you really sure you want to go through with it?"); - userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - userInput.setDefaultButton(QMessageBox::Cancel); - return userInput.exec() == QMessageBox::Ok; - } + return showAuthenticationPopup("Unverified Pending Transaction", + "An undocumented transaction is about to be executed."); // otherwise it's a transaction to a contract for which we have the natspec - QMessageBox userInput; - userInput.setText("Pending Transaction"); - userInput.setInformativeText(QString::fromStdString(userNotice + "\n Do you wish to allow this?")); - userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - userInput.button(QMessageBox::Ok)->setText("Allow"); - userInput.button(QMessageBox::Cancel)->setText("Reject"); - userInput.setDefaultButton(QMessageBox::Cancel); - return userInput.exec() == QMessageBox::Ok; - + return showAuthenticationPopup("Pending Transaction", userNotice); } diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 506a77884..a67af0827 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -41,6 +41,8 @@ signals: void onNewId(QString _s); private: + bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; + dev::WebThreeDirect* m_web3; Main* m_main; }; From 396fe954b6044f1da7c31f76def8fc508e5d969d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 14:30:52 +0100 Subject: [PATCH 08/11] Small fixes AZ MainWin.cpp --- alethzero/MainWin.cpp | 4 ++-- alethzero/NatspecHandler.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 41a1b1b62..ae239d412 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1639,7 +1639,7 @@ static shh::Topic topicFromText(QString _s) bool Main::sourceIsSolidity(std::string const& _source) { // TODO: Improve this heuristic - return (_source.substr(0, 8) == "contract" || _source.substr(0, 2) == "/*"); + return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol"); } void Main::on_data_textChanged() @@ -1901,7 +1901,7 @@ void Main::on_send_clicked() } catch (...) { - statusBar()->showMessage("Couldn't make transaction: no single account contains at least the required amount."); + statusBar()->showMessage("Couldn't compile Solidity Contract."); } } } diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 3449d0aec..a6255a3e7 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -15,7 +15,7 @@ along with cpp-ethereum. If not, see . */ -/** @file NatspecHandler.h +/** @file NatspecHandler.cpp * @author Lefteris Karapetsas * @date 2015 */ From 4ad3ab21741c610e1b34b7d181a9bca86e27af54 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 16:49:09 +0100 Subject: [PATCH 09/11] Fixes and additional checks for Natspec Popup authentication --- alethzero/MainWin.cpp | 20 +++++++++++++-- alethzero/MainWin.h | 4 +++ alethzero/NatspecHandler.cpp | 40 ++++++++++++++++++++--------- alethzero/NatspecHandler.h | 1 + alethzero/OurWebThreeStubServer.cpp | 1 - libethereum/Defaults.h | 1 - libsolidity/CompilerStack.cpp | 22 ++-------------- libsolidity/CompilerStack.h | 9 +++---- 8 files changed, 56 insertions(+), 42 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ae239d412..e281fda94 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -1642,6 +1642,22 @@ bool Main::sourceIsSolidity(std::string const& _source) return (_source.substr(0, 8) == "contract" || _source.substr(0, 5) == "//sol"); } +string const Main::getFunctionHashes(dev::solidity::CompilerStack const &_compiler, + string const& _contractName) +{ + string ret = ""; + auto const& contract = _compiler.getContractDefinition(_contractName); + auto interfaceFunctions = contract.getInterfaceFunctions(); + + for (auto const& it: interfaceFunctions) + { + ret += it.first.abridged(); + ret += " :"; + ret += it.second->getName() + "\n"; + } + return ret; +} + void Main::on_data_textChanged() { m_pcWarp.clear(); @@ -1664,7 +1680,7 @@ void Main::on_data_textChanged() solidity = "

Solidity

"; solidity += "
" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "
"; solidity += "
" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "
"; - solidity += "
" + QString::fromStdString(compiler.getFunctionHashes()).toHtmlEscaped() + "
"; + solidity += "
" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "
"; } catch (dev::Exception const& exception) { diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 23280eec4..96a4b1128 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "NatspecHandler.h" @@ -232,6 +233,9 @@ private: /// Attempts to infer that @c _source contains Solidity code bool sourceIsSolidity(std::string const& _source); + /// @eturns all method hashes of a Solidity contract in a string + std::string const getFunctionHashes(dev::solidity::CompilerStack const &_compiler, + std::string const& _contractName = ""); std::unique_ptr ui; diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index a6255a3e7..5cccb608a 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -26,41 +26,49 @@ #include #include #include +#include #include #include using namespace dev; using namespace dev::eth; +using namespace std; NatspecHandler::NatspecHandler() { - std::string path = Defaults::dbPath(); + string path = Defaults::dbPath(); boost::filesystem::create_directories(path); ldb::Options o; o.create_if_missing = true; ldb::DB::Open(o, path + "/natspec", &m_db); } -void NatspecHandler::add(dev::h256 const& _contractHash, std::string const& _doc) +NatspecHandler::~NatspecHandler() +{ + delete m_db; +} + +void NatspecHandler::add(dev::h256 const& _contractHash, string const& _doc) { bytes k = _contractHash.asBytes(); - std::string v = _doc; + string v = _doc; m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size())); } -std::string NatspecHandler::retrieve(dev::h256 const& _contractHash) const +string NatspecHandler::retrieve(dev::h256 const& _contractHash) const { bytes k = _contractHash.asBytes(); - std::string ret; + string ret; m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret); return ret; } -std::string NatspecHandler::getUserNotice(std::string const& json, const dev::bytes& _transactionData) +string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _transactionData) { - Json::Value natspec, userNotice; - std::string retStr; + Json::Value natspec; + Json::Value userNotice; + string retStr; m_reader.parse(json, natspec); bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4); FixedHash<4> transactionFunctionHash(transactionFunctionPart); @@ -68,11 +76,19 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by Json::Value methods = natspec["methods"]; for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it) { - std::string functionSig = it.key().asString(); + Json::Value keyValue = it.key(); + if (!keyValue.isString()) + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Illegal Natspec JSON detected")); + + string functionSig = keyValue.asString(); FixedHash<4> functionHash(dev::sha3(functionSig)); - if (functionHash == transactionFunctionHash) { - return (*it)["notice"].asString(); + if (functionHash == transactionFunctionHash) + { + Json::Value val = (*it)["notice"]; + if (!val.isString()) + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Illegal Natspec JSON detected")); + return val.asString(); } } @@ -80,7 +96,7 @@ std::string NatspecHandler::getUserNotice(std::string const& json, const dev::by return ""; } -std::string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) +string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData) { return getUserNotice(retrieve(_contractHash), _transactionData); } diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index e9b2f50f0..edd9281d7 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -35,6 +35,7 @@ class NatspecHandler { public: NatspecHandler(); + ~NatspecHandler(); /// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation void add(dev::h256 const& _contractHash, std::string const& _doc); diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index ff477dd29..ce1f28507 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -44,7 +44,6 @@ std::string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, std::string const& _text) const { - // otherwise it's a transaction to a contract for which we have the natspec QMessageBox userInput; userInput.setText(QString::fromStdString(_title)); userInput.setInformativeText(QString::fromStdString(_text + "\n Do you wish to allow this?")); diff --git a/libethereum/Defaults.h b/libethereum/Defaults.h index 3b19166b1..91d5872f7 100644 --- a/libethereum/Defaults.h +++ b/libethereum/Defaults.h @@ -23,7 +23,6 @@ #include - namespace dev { namespace eth diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index b06423497..11d90d08b 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -137,12 +137,12 @@ bytes const& CompilerStack::getBytecode(string const& _contractName) const return getContract(_contractName).bytecode; } -bytes const& CompilerStack::getRuntimeBytecode(std::string const& _contractName) const +bytes const& CompilerStack::getRuntimeBytecode(string const& _contractName) const { return getContract(_contractName).runtimeBytecode; } -dev::h256 CompilerStack::getContractCodeHash(std::string const& _contractName) const +dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const { return dev::sha3(getRuntimeBytecode(_contractName)); } @@ -192,24 +192,6 @@ string const& CompilerStack::getMetadata(string const& _contractName, Documentat return *(*doc); } -std::string const CompilerStack::getFunctionHashes(std::string const& _contractName) -{ - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - - std::string ret = ""; - Contract const& contract = getContract(_contractName); - auto interfaceFunctions = contract.contract->getInterfaceFunctions(); - - for (auto const& it: interfaceFunctions) - { - ret += it.first.abridged(); - ret += " :"; - ret += it.second->getName() + "\n"; - } - return ret; -} - Scanner const& CompilerStack::getScanner(string const& _sourceName) const { return *getSource(_sourceName).scanner; diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 202f1b321..29de69d59 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -76,11 +76,11 @@ public: /// @returns the compiled bytecode bytes const& compile(std::string const& _sourceCode, bool _optimize = false); - /// Gets the assembled bytecode for a contract + /// @returns the assembled bytecode for a contract. bytes const& getBytecode(std::string const& _contractName = "") const; - /// Get the runtime context's bytecode for a contract + /// @returns the runtime context's bytecode for a contract. bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; - /// Get the runtime context's code hash for a contract + /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. dev::h256 getContractCodeHash(std::string const& _contractName = "") const; /// Streams a verbose version of the assembly to @a _outStream. @@ -99,9 +99,6 @@ public: /// Can be one of 4 types defined at @c DocumentationType std::string const& getMetadata(std::string const& _contractName, DocumentationType _type) const; - /// Convenience function to return all contract method hashes in a string - std::string const getFunctionHashes(std::string const& _contractName = ""); - /// @returns the previously used scanner, useful for counting lines during error reporting. Scanner const& getScanner(std::string const& _sourceName = "") const; /// @returns the parsed source unit with the supplied name. From 79b953d9e5ac86d26b603c0e5a0270c9747ad997 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 14 Jan 2015 17:14:46 +0100 Subject: [PATCH 10/11] Minor style fixes --- alethzero/NatspecHandler.cpp | 2 +- libsolidity/CompilerStack.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 5cccb608a..98d2879c7 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -74,7 +74,7 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran FixedHash<4> transactionFunctionHash(transactionFunctionPart); Json::Value methods = natspec["methods"]; - for (Json::ValueIterator it= methods.begin(); it != methods.end(); ++it) + for (Json::ValueIterator it = methods.begin(); it != methods.end(); ++it) { Json::Value keyValue = it.key(); if (!keyValue.isString()) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 29de69d59..aa55abe50 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -78,9 +78,9 @@ public: /// @returns the assembled bytecode for a contract. bytes const& getBytecode(std::string const& _contractName = "") const; - /// @returns the runtime context's bytecode for a contract. - bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. + bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; + /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. dev::h256 getContractCodeHash(std::string const& _contractName = "") const; /// Streams a verbose version of the assembly to @a _outStream. From 6ee8be71bac498b90f59100bf33cf5ad046eb809 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 15 Jan 2015 01:36:18 +0100 Subject: [PATCH 11/11] more style fixes and an addition to the coding style --- CodingStandards.txt | 16 ++++++++++++++++ alethzero/MainWin.cpp | 5 +---- alethzero/NatspecHandler.cpp | 7 +++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CodingStandards.txt b/CodingStandards.txt index 672a20958..9d4b5f9d0 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -162,3 +162,19 @@ d. In general expressions should be roughly as important/semantically meaningful a. Comments should be doxygen-compilable, using @notation rather than \notation. +12. Include Headers + +a. Includes should go in order of lower level (STL -> boost -> libdevcore -> libdevcrypto -> libethcore -> libethereum) to higher level. Lower levels are basically dependencies to the higher levels. For example: + +#include +#include + +#include +#include +#include +#include +#include +#include + +b. The only exception to the above rule is the top of a .cpp file where its corresponding header should be located. + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e281fda94..117d500cc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1902,11 +1902,9 @@ void Main::on_send_clicked() ethereum()->transact(s, value(), m_data, ui->gas->value(), gasPrice()); string src = ui->data->toPlainText().toStdString(); if (sourceIsSolidity(src)) - { - - dev::solidity::CompilerStack compiler; try { + dev::solidity::CompilerStack compiler; m_data = compiler.compile(src, m_enableOptimizer); for (std::string& s: compiler.getContractNames()) { @@ -1919,7 +1917,6 @@ void Main::on_send_clicked() { statusBar()->showMessage("Couldn't compile Solidity Contract."); } - } } else ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice()); diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index 98d2879c7..25cc13d4a 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -20,16 +20,15 @@ * @date 2015 */ #include "NatspecHandler.h" -#include #include +#include -#include #include #include #include #include #include - +#include using namespace dev; using namespace dev::eth; @@ -93,7 +92,7 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran } // not found - return ""; + return string(); } string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData)