Browse Source

Merge pull request #798 from LefterisJP/natspec_OnContractCreation

Natspec Popup Authentication on transaction
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
7583637c39
  1. 16
      CodingStandards.txt
  2. 61
      alethzero/MainWin.cpp
  3. 13
      alethzero/MainWin.h
  4. 103
      alethzero/NatspecHandler.cpp
  5. 58
      alethzero/NatspecHandler.h
  6. 50
      alethzero/OurWebThreeStubServer.cpp
  7. 8
      alethzero/OurWebThreeStubServer.h
  8. 3
      libdevcore/CommonData.h
  9. 77
      libjsqrc/ethereumjs/example/natspec_contract.html
  10. 5
      libsolidity/Compiler.cpp
  11. 2
      libsolidity/Compiler.h
  12. 13
      libsolidity/CompilerStack.cpp
  13. 8
      libsolidity/CompilerStack.h
  14. 4
      libsolidity/InterfaceHandler.cpp
  15. 42
      test/SolidityNatspecJSON.cpp

16
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 <string>
#include <boost/filesystem.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include <libethereum/Defaults.h>
b. The only exception to the above rule is the top of a .cpp file where its corresponding header should be located.

61
alethzero/MainWin.cpp

@ -37,7 +37,7 @@
#include <liblll/Compiler.h>
#include <liblll/CodeFragment.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/AST.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
@ -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();
@ -1635,6 +1635,29 @@ 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, 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();
@ -1648,7 +1671,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
@ -1657,6 +1680,7 @@ void Main::on_data_textChanged()
solidity = "<h4>Solidity</h4>";
solidity += "<pre>" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + "</pre>";
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "</pre>";
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "</pre>";
}
catch (dev::Exception const& exception)
{
@ -1872,7 +1896,28 @@ void Main::on_send_clicked()
debugFinished();
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());
string src = ui->data->toPlainText().toStdString();
if (sourceIsSolidity(src))
try
{
dev::solidity::CompilerStack compiler;
m_data = compiler.compile(src, m_enableOptimizer);
for (std::string& s: compiler.getContractNames())
{
h256 contractHash = compiler.getContractCodeHash(s);
m_natspecDB.add(contractHash,
compiler.getMetadata(s, dev::solidity::DocumentationType::NATSPEC_USER));
}
}
catch (...)
{
statusBar()->showMessage("Couldn't compile Solidity Contract.");
}
}
else
ethereum()->transact(s, value(), fromString(ui->destination->currentText()), m_data, ui->gas->value(), gasPrice());
return;
@ -2257,6 +2302,16 @@ 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);
}
std::string Main::lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData)
{
return m_natspecDB.getUserNotice(_contractHash, _transactionData);
}
void Main::refreshWhispers()
{
ui->whispers->clear();

13
alethzero/MainWin.h

@ -36,6 +36,9 @@
#include <libethereum/Executive.h>
#include <libqwebthree/QWebThree.h>
#include <libwebthree/WebThree.h>
#include <libsolidity/CompilerStack.h>
#include "NatspecHandler.h"
namespace Ui {
class Main;
@ -80,7 +83,8 @@ public:
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
std::shared_ptr<dev::shh::WhisperHost> 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;
std::string lookupNatSpecUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData);
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
@ -227,6 +231,12 @@ private:
void refreshBlockCount();
void refreshBalances();
/// 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::Main> ui;
std::unique_ptr<dev::WebThreeDirect> m_webThree;
@ -269,4 +279,5 @@ private:
QWebThree* m_qweb = nullptr;
static QString fromRaw(dev::h256 _n, unsigned* _inc = nullptr);
NatspecHandler m_natspecDB;
};

103
alethzero/NatspecHandler.cpp

@ -0,0 +1,103 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file NatspecHandler.cpp
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#include "NatspecHandler.h"
#include <string>
#include <boost/filesystem.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include <libethereum/Defaults.h>
using namespace dev;
using namespace dev::eth;
using namespace std;
NatspecHandler::NatspecHandler()
{
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);
}
NatspecHandler::~NatspecHandler()
{
delete m_db;
}
void NatspecHandler::add(dev::h256 const& _contractHash, string const& _doc)
{
bytes k = _contractHash.asBytes();
string v = _doc;
m_db->Put(m_writeOptions, ldb::Slice((char const*)k.data(), k.size()), ldb::Slice((char const*)v.data(), v.size()));
}
string NatspecHandler::retrieve(dev::h256 const& _contractHash) const
{
bytes k = _contractHash.asBytes();
string ret;
m_db->Get(m_readOptions, ldb::Slice((char const*)k.data(), k.size()), &ret);
return ret;
}
string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _transactionData)
{
Json::Value natspec;
Json::Value userNotice;
string retStr;
m_reader.parse(json, natspec);
bytes transactionFunctionPart(_transactionData.begin(), _transactionData.begin() + 4);
FixedHash<4> transactionFunctionHash(transactionFunctionPart);
Json::Value methods = natspec["methods"];
for (Json::ValueIterator it = methods.begin(); it != methods.end(); ++it)
{
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)
{
Json::Value val = (*it)["notice"];
if (!val.isString())
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Illegal Natspec JSON detected"));
return val.asString();
}
}
// not found
return string();
}
string NatspecHandler::getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionData)
{
return getUserNotice(retrieve(_contractHash), _transactionData);
}

58
alethzero/NatspecHandler.h

@ -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 <http://www.gnu.org/licenses/>.
*/
/** @file NatspecHandler.h
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#pragma once
#pragma warning(push)
#pragma warning(disable: 4100 4267)
#include <leveldb/db.h>
#pragma warning(pop)
#include <jsoncpp/json/json.h>
#include <libdevcore/FixedHash.h>
namespace ldb = leveldb;
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);
/// 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 and the transaction data return the user notice
std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData);
/// 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, dev::bytes const& _transactionDacta);
private:
ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions;
ldb::DB* m_db;
Json::Reader m_reader;
};

50
alethzero/OurWebThreeStubServer.cpp

@ -22,14 +22,17 @@
#include "OurWebThreeStubServer.h"
#include <QMessageBox>
#include <QAbstractButton>
#include <libwebthree/WebThree.h>
#include "MainWin.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3)
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3,
std::vector<dev::KeyPair> const& _accounts, Main* main):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main)
{}
std::string OurWebThreeStubServer::shh_newIdentity()
@ -39,36 +42,31 @@ 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
{
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.
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; // or whatever.
}
std::string natspecJson = main->lookupNatSpec(contractCodeHash);
if (natspecJson.empty())
{
// TODO: HUGE warning - we don't know what this will do!
return false; // or whatever.
}
// otherwise it's a transaction to contract for which we have the natspec:
// determine the actual message (embellish with real data) and ask user.
return true;
// QMessageBox::question();
std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data);
if (userNotice.empty())
return showAuthenticationPopup("Unverified Pending Transaction",
"An undocumented transaction is about to be executed.");
return true;
// otherwise it's a transaction to a contract for which we have the natspec
return showAuthenticationPopup("Pending Transaction", userNotice);
}

8
alethzero/OurWebThreeStubServer.h

@ -24,12 +24,15 @@
#include <libdevcrypto/Common.h>
#include <libweb3jsonrpc/WebThreeStubServer.h>
class Main;
class OurWebThreeStubServer: public QObject, public WebThreeStubServer
{
Q_OBJECT
public:
OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3,
std::vector<dev::KeyPair> const& _accounts, Main* main);
virtual std::string shh_newIdentity() override;
virtual bool authenticate(dev::TransactionSkeleton const& _t) const;
@ -38,5 +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;
};

3
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 <class _T>

77
libjsqrc/ethereumjs/example/natspec_contract.html

@ -0,0 +1,77 @@
<!doctype>
<html>
<head>
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.AutoProvider());
// solidity source code
var source = "" +
"contract test {\n" +
" /// @notice Will multiplty `a` by 7. \n" +
" function multiply(uint a) returns(uint d) {\n" +
" return a * 7;\n" +
" }\n" +
"}\n";
// contract description, this will be autogenerated somehow
var desc = [{
"name": "multiply",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
var contract;
function createExampleContract() {
// hide create button
document.getElementById('create').style.visibility = 'hidden';
document.getElementById('source').innerText = source;
// create contract
web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
contract = web3.contract(address, desc);
document.getElementById('call').style.visibility = 'visible';
});
}
function callExampleContract() {
// this should be generated by ethereum
var param = parseInt(document.getElementById('value').value);
// call the contract
contract.multiply(param).transact().then(function(res) {
document.getElementById('result').innerText = res[0];
});
}
</script>
</head>
<body>
<h1>contract</h1>
<div id="source"></div>
<div id='create'>
<button type="button" onClick="createExampleContract();">create example contract</button>
</div>
<div id='call' style='visibility: hidden;'>
<input type="number" id="value"></input>
<button type="button" onClick="callExampleContract()">Call Contract</button>
</div>
<div id="result"></div>
</body>
</html>

5
libsolidity/Compiler.cpp

@ -50,10 +50,9 @@ void Compiler::compileContract(ContractDefinition const& _contract, vector<Magic
function->accept(*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<MagicVariableDeclaration const*> const& _magicGlobals,

2
libsolidity/Compiler.h

@ -35,6 +35,7 @@ public:
void compileContract(ContractDefinition const& _contract, std::vector<MagicVariableDeclaration const*> const& _magicGlobals,
std::map<ContractDefinition const*, bytes const*> 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<eth::AssemblyItem> m_breakTags; ///< tag to jump to for a "break" statement
std::vector<eth::AssemblyItem> m_continueTags; ///< tag to jump to for a "continue" statement
eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement

13
libsolidity/CompilerStack.cpp

@ -30,6 +30,8 @@
#include <libsolidity/CompilerStack.h>
#include <libsolidity/InterfaceHandler.h>
#include <libdevcrypto/SHA3.h>
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(string const& _contractName) const
{
return getContract(_contractName).runtimeBytecode;
}
dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const
{
return dev::sha3(getRuntimeBytecode(_contractName));
}
void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName) const
{
getContract(_contractName).compiler->streamAssembly(_outStream);

8
libsolidity/CompilerStack.h

@ -28,6 +28,7 @@
#include <memory>
#include <boost/noncopyable.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev {
namespace solidity {
@ -75,7 +76,13 @@ public:
/// @returns the compiled bytecode
bytes const& compile(std::string const& _sourceCode, bool _optimize = false);
/// @returns the assembled bytecode for a contract.
bytes const& getBytecode(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.
/// Prerequisite: Successful compilation.
void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "") const;
@ -121,6 +128,7 @@ private:
ContractDefinition const* contract = nullptr;
std::shared_ptr<Compiler> compiler;
bytes bytecode;
bytes runtimeBytecode;
std::shared_ptr<InterfaceHandler> interfaceHandler;
mutable std::unique_ptr<std::string const> interface;
mutable std::unique_ptr<std::string const> solidityInterface;

4
libsolidity/InterfaceHandler.cpp

@ -106,7 +106,7 @@ std::unique_ptr<std::string> 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<std::string> 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;

42
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"

Loading…
Cancel
Save