Browse Source

Merge remote-tracking branch 'ethereum/develop' into sol_import

Conflicts:
	libsolidity/CompilerStack.cpp
	libsolidity/CompilerStack.h
	solc/main.cpp
cl-refactor
Christian 10 years ago
parent
commit
f0fde6886b
  1. 1
      alethzero/MainWin.cpp
  2. 2
      libethcore/CommonEth.cpp
  3. 11
      libevm/ExtVMFace.h
  4. 27
      libp2p/Host.cpp
  5. 6
      libp2p/Host.h
  6. 2
      libsolidity/AST.h
  7. 4
      libsolidity/CMakeLists.txt
  8. 66
      libsolidity/CompilerStack.cpp
  9. 26
      libsolidity/CompilerStack.h
  10. 1
      libsolidity/Exceptions.h
  11. 278
      libsolidity/InterfaceHandler.cpp
  12. 110
      libsolidity/InterfaceHandler.h
  13. 2
      libwhisper/WhisperHost.cpp
  14. 34
      libwhisper/WhisperPeer.cpp
  15. 2
      mix/CMakeLists.txt
  16. 1
      mix/CodeEditorExtensionManager.cpp
  17. 38
      mix/EthereumMacOSXBundleInfo.plist.in
  18. 4
      mix/qml/BasicContent.qml
  19. 6
      mix/qml/MainContent.qml
  20. 6
      mix/qml/TabStyle.qml
  21. 6
      mix/qml/main.qml
  22. 4
      solc/main.cpp
  23. 35
      test/solidityJSONInterfaceTest.cpp
  24. 400
      test/solidityNatspecJSON.cpp
  25. 12
      test/stSystemOperationsTestFiller.json

1
alethzero/MainWin.cpp

@ -1285,6 +1285,7 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>" << sha3(i.data()).abridged();// << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]"; s << "<br/>" << sha3(i.data()).abridged();// << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]";
s << "<br/>Post: <b>" << info.stateRoot << "</b>"; s << "<br/>Post: <b>" << info.stateRoot << "</b>";
s << "<br/>Dump: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[0].data()) << "</span>"; s << "<br/>Dump: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[0].data()) << "</span>";
s << "<div>Receipts-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(ethereum()->blockChain().receipts(h).rlp()) << "</span></div>";
} }
else else
{ {

2
libethcore/CommonEth.cpp

@ -33,7 +33,7 @@ namespace dev
namespace eth namespace eth
{ {
const unsigned c_protocolVersion = 46; const unsigned c_protocolVersion = 48;
const unsigned c_databaseVersion = 5; const unsigned c_databaseVersion = 5;
static const vector<pair<u256, string>> g_units = static const vector<pair<u256, string>> g_units =

11
libevm/ExtVMFace.h

@ -36,20 +36,12 @@ namespace dev
namespace eth namespace eth
{ {
template <class T> inline std::set<T> toSet(std::vector<T> const& _ts)
{
std::set<T> ret;
for (auto const& t: _ts)
ret.insert(t);
return ret;
}
using LogBloom = h512; using LogBloom = h512;
struct LogEntry struct LogEntry
{ {
LogEntry() {} LogEntry() {}
LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256s)_r[1]; data = _r[2].toBytes(); } LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = _r[1].toVector<h256>(); data = _r[2].toBytes(); }
LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(_ts), data(std::move(_d)) {} LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(_ts), data(std::move(_d)) {}
void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; } void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; }
@ -88,6 +80,7 @@ struct SubState
{ {
suicides += _s.suicides; suicides += _s.suicides;
refunds += _s.refunds; refunds += _s.refunds;
logs += _s.logs;
return *this; return *this;
} }
}; };

27
libp2p/Host.cpp

@ -34,6 +34,7 @@
#include <set> #include <set>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <mutex>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
@ -199,7 +200,7 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
m_clientVersion(_clientVersion), m_clientVersion(_clientVersion),
m_netPrefs(_n), m_netPrefs(_n),
m_ifAddresses(getInterfaceAddresses()), m_ifAddresses(getInterfaceAddresses()),
m_ioService(new ba::io_service), m_ioService(new ba::io_service(2)),
m_acceptor(new bi::tcp::acceptor(*m_ioService)), m_acceptor(new bi::tcp::acceptor(*m_ioService)),
m_socket(new bi::tcp::socket(*m_ioService)), m_socket(new bi::tcp::socket(*m_ioService)),
m_key(KeyPair::create()) m_key(KeyPair::create())
@ -227,7 +228,7 @@ void Host::stop()
{ {
{ {
// prevent m_run from being set to false at same time as set to true by start() // prevent m_run from being set to false at same time as set to true by start()
lock_guard<mutex> l(x_runtimer); Guard l(x_runTimer);
// once m_run is false the scheduler will shutdown network and stopWorking() // once m_run is false the scheduler will shutdown network and stopWorking()
m_run = false; m_run = false;
} }
@ -537,6 +538,15 @@ void Host::connect(std::shared_ptr<Node> const& _n)
if (!m_ioService) if (!m_ioService)
return; return;
// prevent concurrently connecting to a node; todo: better abstraction
Node *nptr = _n.get();
{
Guard l(x_pendingNodeConns);
if (m_pendingNodeConns.count(nptr))
return;
m_pendingNodeConns.insert(nptr);
}
clog(NetConnect) << "Attempting connection to node" << _n->id.abridged() << "@" << _n->address << "from" << id().abridged(); clog(NetConnect) << "Attempting connection to node" << _n->id.abridged() << "@" << _n->address << "from" << id().abridged();
_n->lastAttempted = std::chrono::system_clock::now(); _n->lastAttempted = std::chrono::system_clock::now();
_n->failedAttempts++; _n->failedAttempts++;
@ -559,6 +569,8 @@ void Host::connect(std::shared_ptr<Node> const& _n)
p->start(); p->start();
} }
delete s; delete s;
Guard l(x_pendingNodeConns);
m_pendingNodeConns.erase(nptr);
}); });
} }
@ -688,8 +700,7 @@ PeerInfos Host::peers(bool _updatePing) const
void Host::run(boost::system::error_code const& error) void Host::run(boost::system::error_code const& error)
{ {
static unsigned s_lasttick = 0; m_lastTick += c_timerInterval;
s_lasttick += c_timerInterval;
if (error || !m_ioService) if (error || !m_ioService)
{ {
@ -701,11 +712,11 @@ void Host::run(boost::system::error_code const& error)
// network running // network running
if (m_run) if (m_run)
{ {
if (s_lasttick >= c_timerInterval * 50) if (m_lastTick >= c_timerInterval * 10)
{ {
growPeers(); growPeers();
prunePeers(); prunePeers();
s_lasttick = 0; m_lastTick = 0;
} }
if (m_hadNewNodes) if (m_hadNewNodes)
@ -771,7 +782,7 @@ void Host::run(boost::system::error_code const& error)
m_socket->close(); m_socket->close();
// m_run is false, so we're stopping; kill timer // m_run is false, so we're stopping; kill timer
s_lasttick = 0; m_lastTick = 0;
// causes parent thread's stop() to continue which calls stopWorking() // causes parent thread's stop() to continue which calls stopWorking()
m_timer.reset(); m_timer.reset();
@ -794,7 +805,7 @@ void Host::startedWorking()
// prevent m_run from being set to true at same time as set to false by stop() // prevent m_run from being set to true at same time as set to false by stop()
// don't release mutex until m_timer is set so in case stop() is called at same // don't release mutex until m_timer is set so in case stop() is called at same
// time, stop will wait on m_timer and graceful network shutdown. // time, stop will wait on m_timer and graceful network shutdown.
lock_guard<mutex> l(x_runtimer); Guard l(x_runTimer);
// reset io service and create deadline timer // reset io service and create deadline timer
m_timer.reset(new boost::asio::deadline_timer(*m_ioService)); m_timer.reset(new boost::asio::deadline_timer(*m_ioService));
m_run = true; m_run = true;

6
libp2p/Host.h

@ -224,7 +224,7 @@ private:
Nodes potentialPeers(RangeMask<unsigned> const& _known); Nodes potentialPeers(RangeMask<unsigned> const& _known);
bool m_run = false; ///< Whether network is running. bool m_run = false; ///< Whether network is running.
std::mutex x_runtimer; ///< Start/stop mutex. std::mutex x_runTimer; ///< Start/stop mutex.
std::string m_clientVersion; ///< Our version string. std::string m_clientVersion; ///< Our version string.
@ -241,6 +241,10 @@ private:
std::unique_ptr<boost::asio::deadline_timer> m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms. std::unique_ptr<boost::asio::deadline_timer> m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms.
static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected. static const unsigned c_timerInterval = 100; ///< Interval which m_timer is run when network is connected.
unsigned m_lastTick = 0; ///< Used by run() for scheduling; must not be mutated outside of run().
std::set<Node*> m_pendingNodeConns; /// Used only by connect(Node&) to limit concurrently connecting to same node. See connect(shared_ptr<Node>const&).
Mutex x_pendingNodeConns;
bi::tcp::endpoint m_public; ///< Our public listening endpoint. bi::tcp::endpoint m_public; ///< Our public listening endpoint.
KeyPair m_key; ///< Our unique ID. KeyPair m_key; ///< Our unique ID.

2
libsolidity/AST.h

@ -238,7 +238,7 @@ public:
Block& getBody() { return *m_body; } Block& getBody() { return *m_body; }
/// @return A shared pointer of an ASTString. /// @return A shared pointer of an ASTString.
/// Can contain a nullptr in which case indicates absence of documentation /// Can contain a nullptr in which case indicates absence of documentation
ASTPointer<ASTString> const& getDocumentation() { return m_documentation; } ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); }
std::vector<VariableDeclaration const*> const& getLocalVariables() const { return m_localVariables; } std::vector<VariableDeclaration const*> const& getLocalVariables() const { return m_localVariables; }

4
libsolidity/CMakeLists.txt

@ -16,6 +16,10 @@ endif()
include_directories(..) include_directories(..)
target_link_libraries(${EXECUTABLE} evmcore devcore) target_link_libraries(${EXECUTABLE} evmcore devcore)
# TODO: Temporary until PR 532 https://github.com/ethereum/cpp-ethereum/pull/532
# gets accepted. Then we can simply add jsoncpp as a dependency and not the
# whole of JSONRPC as we are doing right here
target_link_libraries(${EXECUTABLE} ${JSONRPC_LS})
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

66
libsolidity/CompilerStack.cpp

@ -27,6 +27,7 @@
#include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h> #include <libsolidity/Compiler.h>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/InterfaceHandler.h>
using namespace std; using namespace std;
@ -127,45 +128,34 @@ void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractN
string const& CompilerStack::getInterface(std::string const& _contractName) string const& CompilerStack::getInterface(std::string const& _contractName)
{ {
return getJsonDocumentation(_contractName, ABI_INTERFACE);
}
std::string const& CompilerStack::getJsonDocumentation(std::string const& _contractName, enum DocumentationType _type)
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
Contract& contract = getContract(_contractName); Contract& contract = getContract(_contractName);
if (contract.interface.empty())
std::unique_ptr<string>* doc;
switch (_type)
{ {
stringstream interface; case NATSPEC_USER:
interface << '['; doc = &contract.userDocumentation;
vector<FunctionDefinition const*> exportedFunctions = contract.contract->getInterfaceFunctions(); break;
unsigned functionsCount = exportedFunctions.size(); case NATSPEC_DEV:
for (FunctionDefinition const* f: exportedFunctions) doc = &contract.devDocumentation;
{ break;
auto streamVariables = [&](vector<ASTPointer<VariableDeclaration>> const& _vars) case ABI_INTERFACE:
{ doc = &contract.interface;
unsigned varCount = _vars.size(); break;
for (ASTPointer<VariableDeclaration> const& var: _vars) default:
{ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type."));
interface << "{"
<< "\"name\":" << escaped(var->getName(), false) << ","
<< "\"type\":" << escaped(var->getType()->toString(), false)
<< "}";
if (--varCount > 0)
interface << ",";
}
};
interface << '{'
<< "\"name\":" << escaped(f->getName(), false) << ","
<< "\"inputs\":[";
streamVariables(f->getParameters());
interface << "],"
<< "\"outputs\":[";
streamVariables(f->getReturnParameters());
interface << "]"
<< "}";
if (--functionsCount > 0)
interface << ",";
}
interface << ']';
contract.interface = interface.str();
} }
return contract.interface; if (!*doc)
*doc = contract.interfaceHandler->getDocumentation(*contract.contract, _type);
return *(*doc);
} }
Scanner const& CompilerStack::getScanner(string const& _sourceName) Scanner const& CompilerStack::getScanner(string const& _sourceName)
@ -193,7 +183,6 @@ void CompilerStack::reset(bool _keepSources)
else else
m_sources.clear(); m_sources.clear();
m_globalContext.reset(); m_globalContext.reset();
m_compiler.reset();
m_sourceOrder.clear(); m_sourceOrder.clear();
m_contracts.clear(); m_contracts.clear();
} }
@ -247,5 +236,8 @@ CompilerStack::Source& CompilerStack::getSource(string const& _sourceName)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found.")); BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found."));
return it->second; return it->second;
} }
CompilerStack::Contract::Contract(): interfaceHandler(make_shared<InterfaceHandler>()) {}
} }
} }

26
libsolidity/CompilerStack.h

@ -33,10 +33,18 @@ namespace solidity {
// forward declarations // forward declarations
class Scanner; class Scanner;
class ContractDefinition;
class SourceUnit; class SourceUnit;
class Compiler; class Compiler;
class GlobalContext; class GlobalContext;
class ContractDefinition; class InterfaceHandler;
enum DocumentationType: unsigned short
{
NATSPEC_USER = 1,
NATSPEC_DEV,
ABI_INTERFACE
};
/** /**
* Easy to use and self-contained Solidity compiler with as few header dependencies as possible. * Easy to use and self-contained Solidity compiler with as few header dependencies as possible.
@ -47,6 +55,7 @@ class CompilerStack: boost::noncopyable
{ {
public: public:
CompilerStack(): m_parseSuccessful(false) {} CompilerStack(): m_parseSuccessful(false) {}
/// Adds a source object (e.g. file) to the parser. After this, parse has to be called again. /// Adds a source object (e.g. file) to the parser. After this, parse has to be called again.
void addSource(std::string const& _name, std::string const& _content); void addSource(std::string const& _name, std::string const& _content);
void setSource(std::string const& _sourceCode); void setSource(std::string const& _sourceCode);
@ -71,6 +80,11 @@ public:
/// Returns a string representing the contract interface in JSON. /// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile. /// Prerequisite: Successful call to parse or compile.
std::string const& getInterface(std::string const& _contractName = ""); std::string const& getInterface(std::string const& _contractName = "");
/// Returns a string representing the contract's documentation in JSON.
/// Prerequisite: Successful call to parse or compile.
/// @param type The type of the documentation to get.
/// Can be one of 3 types defined at @c DocumentationType
std::string const& getJsonDocumentation(std::string const& _contractName, enum DocumentationType _type);
/// Returns the previously used scanner, useful for counting lines during error reporting. /// Returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& getScanner(std::string const& _sourceName = ""); Scanner const& getScanner(std::string const& _sourceName = "");
@ -94,10 +108,15 @@ private:
struct Contract struct Contract
{ {
ContractDefinition const* contract; ContractDefinition* contract;
std::string interface;
std::shared_ptr<Compiler> compiler; std::shared_ptr<Compiler> compiler;
bytes bytecode; bytes bytecode;
std::shared_ptr<InterfaceHandler> interfaceHandler;
std::unique_ptr<std::string> interface;
std::unique_ptr<std::string> userDocumentation;
std::unique_ptr<std::string> devDocumentation;
Contract();
}; };
void reset(bool _keepSources = false); void reset(bool _keepSources = false);
@ -109,7 +128,6 @@ private:
bool m_parseSuccessful; bool m_parseSuccessful;
std::map<std::string, Source> m_sources; std::map<std::string, Source> m_sources;
std::shared_ptr<GlobalContext> m_globalContext; std::shared_ptr<GlobalContext> m_globalContext;
std::shared_ptr<Compiler> m_compiler;
std::vector<Source const*> m_sourceOrder; std::vector<Source const*> m_sourceOrder;
std::map<std::string, Contract> m_contracts; std::map<std::string, Contract> m_contracts;
}; };

1
libsolidity/Exceptions.h

@ -36,6 +36,7 @@ struct TypeError: virtual Exception {};
struct DeclarationError: virtual Exception {}; struct DeclarationError: virtual Exception {};
struct CompilerError: virtual Exception {}; struct CompilerError: virtual Exception {};
struct InternalCompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {};
struct DocstringParsingError: virtual Exception {};
typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation; typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation;

278
libsolidity/InterfaceHandler.cpp

@ -0,0 +1,278 @@
#include <libsolidity/InterfaceHandler.h>
#include <libsolidity/AST.h>
#include <libsolidity/CompilerStack.h>
namespace dev
{
namespace solidity
{
/* -- public -- */
InterfaceHandler::InterfaceHandler()
{
m_lastTag = DOCTAG_NONE;
}
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefinition& _contractDef,
enum DocumentationType _type)
{
switch(_type)
{
case NATSPEC_USER:
return getUserDocumentation(_contractDef);
case NATSPEC_DEV:
return getDevDocumentation(_contractDef);
case ABI_INTERFACE:
return getABIInterface(_contractDef);
}
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type"));
return nullptr;
}
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinition& _contractDef)
{
Json::Value methods(Json::arrayValue);
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
{
Json::Value method;
Json::Value inputs(Json::arrayValue);
Json::Value outputs(Json::arrayValue);
auto populateParameters = [](std::vector<ASTPointer<VariableDeclaration>> const& _vars)
{
Json::Value params(Json::arrayValue);
for (ASTPointer<VariableDeclaration> const& var: _vars)
{
Json::Value input;
input["name"] = var->getName();
input["type"] = var->getType()->toString();
params.append(input);
}
return params;
};
method["name"] = f->getName();
method["inputs"] = populateParameters(f->getParameters());
method["outputs"] = populateParameters(f->getReturnParameters());
methods.append(method);
}
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods)));
}
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefinition& _contractDef)
{
Json::Value doc;
Json::Value methods(Json::objectValue);
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
{
Json::Value user;
auto strPtr = f->getDocumentation();
if (strPtr)
{
resetUser();
parseDocString(*strPtr);
if (!m_notice.empty())
{// since @notice is the only user tag if missing function should not appear
user["notice"] = Json::Value(m_notice);
methods[f->getName()] = user;
}
}
}
doc["methods"] = methods;
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc)));
}
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefinition& _contractDef)
{
// LTODO: Somewhere in this function warnings for mismatch of param names
// should be thrown
Json::Value doc;
Json::Value methods(Json::objectValue);
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
{
Json::Value method;
auto strPtr = f->getDocumentation();
if (strPtr)
{
resetDev();
parseDocString(*strPtr);
if (!m_dev.empty())
method["details"] = Json::Value(m_dev);
Json::Value params(Json::objectValue);
for (auto const& pair: m_params)
params[pair.first] = pair.second;
if (!m_params.empty())
method["params"] = params;
if (!m_return.empty())
method["return"] = m_return;
if (!method.empty()) // add the function, only if we have any documentation to add
methods[f->getName()] = method;
}
}
doc["methods"] = methods;
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc)));
}
/* -- private -- */
void InterfaceHandler::resetUser()
{
m_notice.clear();
}
void InterfaceHandler::resetDev()
{
m_dev.clear();
m_return.clear();
m_params.clear();
}
static inline std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos,
std::string::const_iterator _end)
{
return (_nlPos == _end) ? _end : ++_nlPos;
}
std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string& _tagString,
enum DocTagType _tagType)
{
auto nlPos = std::find(_pos, _end, '\n');
std::copy(_pos, nlPos, back_inserter(_tagString));
m_lastTag = _tagType;
return skipLineOrEOS(nlPos, _end);
}
std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end)
{
// find param name
auto currPos = std::find(_pos, _end, ' ');
if (currPos == _end)
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + std::string(_pos, _end)));
auto paramName = std::string(_pos, currPos);
currPos += 1;
auto nlPos = std::find(currPos, _end, '\n');
auto paramDesc = std::string(currPos, nlPos);
m_params.push_back(std::make_pair(paramName, paramDesc));
m_lastTag = DOCTAG_PARAM;
return skipLineOrEOS(nlPos, _end);
}
std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end)
{
// Should never be called with an empty vector
if (asserts(!m_params.empty()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Tried to append to empty parameter"));
auto pair = m_params.back();
pair.second += " ";
auto nlPos = std::find(_pos, _end, '\n');
std::copy(_pos, nlPos, back_inserter(pair.second));
m_params.at(m_params.size() - 1) = pair;
return skipLineOrEOS(nlPos, _end);
}
std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string const& _tag)
{
// LTODO: need to check for @(start of a tag) between here and the end of line
// for all cases
if (m_lastTag == DOCTAG_NONE || _tag != "")
{
if (_tag == "dev")
return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV);
else if (_tag == "notice")
return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE);
else if (_tag == "return")
return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN);
else if (_tag == "param")
return parseDocTagParam(_pos, _end);
else
{
// LTODO: Unknown tag, throw some form of warning and not just an exception
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("Unknown tag " + _tag + " encountered"));
}
}
else
return appendDocTag(_pos, _end);
}
std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos,
std::string::const_iterator _end)
{
switch (m_lastTag)
{
case DOCTAG_DEV:
m_dev += " ";
return parseDocTagLine(_pos, _end, m_dev, DOCTAG_DEV);
case DOCTAG_NOTICE:
m_notice += " ";
return parseDocTagLine(_pos, _end, m_notice, DOCTAG_NOTICE);
case DOCTAG_RETURN:
m_return += " ";
return parseDocTagLine(_pos, _end, m_return, DOCTAG_RETURN);
case DOCTAG_PARAM:
return appendDocTagParam(_pos, _end);
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Internal: Illegal documentation tag type"));
break;
}
}
static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_iterator _pos,
std::string::const_iterator _end)
{
auto spacePos = std::find(_pos, _end, ' ');
auto nlPos = std::find(_pos, _end, '\n');
return (spacePos < nlPos) ? spacePos : nlPos;
}
void InterfaceHandler::parseDocString(std::string const& _string)
{
auto currPos = _string.begin();
auto end = _string.end();
while (currPos != end)
{
auto tagPos = std::find(currPos, end, '@');
auto nlPos = std::find(currPos, end, '\n');
if (tagPos != end && tagPos < nlPos)
{
// we found a tag
auto tagNameEndPos = getFirstSpaceOrNl(tagPos, end);
if (tagNameEndPos == end)
BOOST_THROW_EXCEPTION(DocstringParsingError() <<
errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found"));
currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos));
}
else if (m_lastTag != DOCTAG_NONE) // continuation of the previous tag
currPos = appendDocTag(currPos + 1, end);
else if (currPos != end) // skip the line if a newline was found
currPos = nlPos + 1;
}
}
} //solidity NS
} // dev NS

110
libsolidity/InterfaceHandler.h

@ -0,0 +1,110 @@
/*
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/>.
*/
/**
* @author Lefteris <lefteris@ethdev.com>
* @date 2014
* Takes the parsed AST and produces the Natspec
* documentation and the ABI interface
* https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format
*
* Can generally deal with JSON files
*/
#pragma once
#include <string>
#include <memory>
#include <jsonrpc/json/json.h>
namespace dev
{
namespace solidity
{
// Forward declarations
class ContractDefinition;
enum DocumentationType: unsigned short;
enum DocTagType
{
DOCTAG_NONE = 0,
DOCTAG_DEV,
DOCTAG_NOTICE,
DOCTAG_PARAM,
DOCTAG_RETURN
};
class InterfaceHandler
{
public:
InterfaceHandler();
/// Get the given type of documentation
/// @param _contractDef The contract definition
/// @param _type The type of the documentation. Can be one of the
/// types provided by @c DocumentationType
/// @return A unique pointer contained string with the json
/// representation of provided type
std::unique_ptr<std::string> getDocumentation(ContractDefinition& _contractDef,
enum DocumentationType _type);
/// Get the ABI Interface of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's ABI Interface
std::unique_ptr<std::string> getABIInterface(ContractDefinition& _contractDef);
/// Get the User documentation of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's user documentation
std::unique_ptr<std::string> getUserDocumentation(ContractDefinition& _contractDef);
/// Get the Developer's documentation of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// representation of the contract's developer documentation
std::unique_ptr<std::string> getDevDocumentation(ContractDefinition& _contractDef);
private:
void resetUser();
void resetDev();
std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string& _tagString,
enum DocTagType _tagType);
std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end);
std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end);
void parseDocString(std::string const& _string);
std::string::const_iterator appendDocTag(std::string::const_iterator _pos,
std::string::const_iterator _end);
std::string::const_iterator parseDocTag(std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string const& _tag);
Json::StyledWriter m_writer;
// internal state
enum DocTagType m_lastTag;
std::string m_notice;
std::string m_dev;
std::string m_return;
std::vector<std::pair<std::string, std::string>> m_params;
};
} //solidity NS
} // dev NS

2
libwhisper/WhisperHost.cpp

@ -118,7 +118,6 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f)
h256s WhisperHost::watchMessages(unsigned _watchId) h256s WhisperHost::watchMessages(unsigned _watchId)
{ {
cleanup();
h256s ret; h256s ret;
auto wit = m_watches.find(_watchId); auto wit = m_watches.find(_watchId);
if (wit == m_watches.end()) if (wit == m_watches.end())
@ -160,6 +159,7 @@ void WhisperHost::doWork()
{ {
for (auto& i: peers()) for (auto& i: peers())
i->cap<WhisperPeer>()->sendMessages(); i->cap<WhisperPeer>()->sendMessages();
cleanup();
} }
void WhisperHost::cleanup() void WhisperHost::cleanup()

34
libwhisper/WhisperPeer.cpp

@ -82,33 +82,23 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r)
void WhisperPeer::sendMessages() void WhisperPeer::sendMessages()
{ {
RLPStream amalg; if (m_unseen.size())
unsigned n = 0;
{ {
Guard l(x_unseen); RLPStream amalg;
while (m_unseen.size()) unsigned msgCount;
{ {
auto p = *m_unseen.begin(); Guard l(x_unseen);
m_unseen.erase(m_unseen.begin()); msgCount = m_unseen.size();
host()->streamMessage(p.second, amalg); while (m_unseen.size())
n++; {
auto p = *m_unseen.begin();
m_unseen.erase(m_unseen.begin());
host()->streamMessage(p.second, amalg);
}
} }
}
// the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them.
auto diff = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now() - m_timer);
if (n || diff.count() > 0)
{
RLPStream s;
prep(s, MessagesPacket, n).appendRaw(amalg.out(), n);
sealAndSend(s);
m_timer = chrono::system_clock::now();
}
{
RLPStream s; RLPStream s;
prep(s, MessagesPacket, n).appendRaw(amalg.out(), n); prep(s, MessagesPacket, msgCount).appendRaw(amalg.out(), msgCount);
sealAndSend(s); sealAndSend(s);
} }
} }

2
mix/CMakeLists.txt

@ -61,7 +61,7 @@ target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore dev
if (APPLE) if (APPLE)
# First have qt5 install plugins and frameworks # First have qt5 install plugins and frameworks
add_custom_command(TARGET ${EXECUTEABLE} POST_BUILD add_custom_command(TARGET ${EXECUTEABLE} POST_BUILD
COMMAND /usr/local/opt/qt5/bin/macdeployqt ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTEABLE}.app COMMAND /usr/local/opt/qt5/bin/macdeployqt -qmldir=${CMAKE_CURRENT_SOURCE_DIR}/qml ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTEABLE}.app
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
# This tool and next will inspect linked libraries in order to determine which dependencies are required # This tool and next will inspect linked libraries in order to determine which dependencies are required

1
mix/CodeEditorExtensionManager.cpp

@ -27,7 +27,6 @@
#include <QQuickTextDocument> #include <QQuickTextDocument>
#include <libevm/VM.h> #include <libevm/VM.h>
#include "ConstantCompilationCtrl.h" #include "ConstantCompilationCtrl.h"
#include "features.h"
#include "ApplicationCtx.h" #include "ApplicationCtx.h"
#include "CodeEditorExtensionManager.h" #include "CodeEditorExtensionManager.h"
using namespace dev::mix; using namespace dev::mix;

38
mix/EthereumMacOSXBundleInfo.plist.in

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSRequiresCarbon</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>

4
mix/qml/BasicContent.qml

@ -1,5 +1,5 @@
import QtQuick 2.3 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.1
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent

6
mix/qml/MainContent.qml

@ -1,7 +1,7 @@
import QtQuick 2.3 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.1
import CodeEditorExtensionManager 1.0 import CodeEditorExtensionManager 1.0
Rectangle { Rectangle {

6
mix/qml/TabStyle.qml

@ -1,6 +1,6 @@
import QtQuick 2.3 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.1
TabViewStyle { TabViewStyle {
frameOverlap: 1 frameOverlap: 1

6
mix/qml/main.qml

@ -1,6 +1,6 @@
import QtQuick 2.3 import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.2 import QtQuick.Controls.Styles 1.1
import CodeEditorExtensionManager 1.0 import CodeEditorExtensionManager 1.0
ApplicationWindow { ApplicationWindow {

4
solc/main.cpp

@ -147,7 +147,9 @@ int main(int argc, char** argv)
cout << "Opcodes:" << endl cout << "Opcodes:" << endl
<< eth::disassemble(compiler.getBytecode(contract)) << endl << eth::disassemble(compiler.getBytecode(contract)) << endl
<< "Binary: " << toHex(compiler.getBytecode(contract)) << endl << "Binary: " << toHex(compiler.getBytecode(contract)) << endl
<< "Interface specification: " << compiler.getInterface(contract) << endl; << "Interface specification: " << compiler.getJsonDocumentation(contract, ABI_INTERFACE) << endl
<< "Natspec user documentation: " << compiler.getJsonDocumentation(contract, NATSPEC_USER) << endl
<< "Natspec developer documentation: " << compiler.getJsonDocumentation(contract, NATSPEC_DEV) << endl;
} }
return 0; return 0;

35
test/solidityJSONInterfaceTest.cpp

@ -23,6 +23,7 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <libsolidity/CompilerStack.h> #include <libsolidity/CompilerStack.h>
#include <jsonrpc/json/json.h> #include <jsonrpc/json/json.h>
#include <libdevcore/Exceptions.h>
namespace dev namespace dev
{ {
@ -34,15 +35,29 @@ namespace test
class InterfaceChecker class InterfaceChecker
{ {
public: public:
bool checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
{ {
m_compilerStack.parse(_code); try
std::string generatedInterfaceString = m_compilerStack.getInterface(); {
m_compilerStack.parse(_code);
}
catch (const std::exception& e)
{
std::string const* extra = boost::get_error_info<errinfo_comment>(e);
std::string msg = std::string("Parsing contract failed with: ") +
e.what() + std::string("\n");
if (extra)
msg += *extra;
BOOST_FAIL(msg);
}
std::string generatedInterfaceString = m_compilerStack.getJsonDocumentation("", ABI_INTERFACE);
Json::Value generatedInterface; Json::Value generatedInterface;
m_reader.parse(generatedInterfaceString, generatedInterface); m_reader.parse(generatedInterfaceString, generatedInterface);
Json::Value expectedInterface; Json::Value expectedInterface;
m_reader.parse(_expectedInterfaceString, expectedInterface); m_reader.parse(_expectedInterfaceString, expectedInterface);
return expectedInterface == generatedInterface; BOOST_CHECK_MESSAGE(expectedInterface == generatedInterface,
"Expected " << _expectedInterfaceString <<
"\n but got:\n" << generatedInterfaceString);
} }
private: private:
@ -50,7 +65,7 @@ private:
Json::Reader m_reader; Json::Reader m_reader;
}; };
BOOST_FIXTURE_TEST_SUITE(SolidityCompilerJSONInterfaceOutput, InterfaceChecker) BOOST_FIXTURE_TEST_SUITE(SolidityABIJSON, InterfaceChecker)
BOOST_AUTO_TEST_CASE(basic_test) BOOST_AUTO_TEST_CASE(basic_test)
{ {
@ -76,7 +91,7 @@ BOOST_AUTO_TEST_CASE(basic_test)
} }
])"; ])";
BOOST_CHECK(checkInterface(sourceCode, interface)); checkInterface(sourceCode, interface);
} }
BOOST_AUTO_TEST_CASE(empty_contract) BOOST_AUTO_TEST_CASE(empty_contract)
@ -86,7 +101,7 @@ BOOST_AUTO_TEST_CASE(empty_contract)
char const* interface = "[]"; char const* interface = "[]";
BOOST_CHECK(checkInterface(sourceCode, interface)); checkInterface(sourceCode, interface);
} }
BOOST_AUTO_TEST_CASE(multiple_methods) BOOST_AUTO_TEST_CASE(multiple_methods)
@ -129,7 +144,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods)
} }
])"; ])";
BOOST_CHECK(checkInterface(sourceCode, interface)); checkInterface(sourceCode, interface);
} }
BOOST_AUTO_TEST_CASE(multiple_params) BOOST_AUTO_TEST_CASE(multiple_params)
@ -160,7 +175,7 @@ BOOST_AUTO_TEST_CASE(multiple_params)
} }
])"; ])";
BOOST_CHECK(checkInterface(sourceCode, interface)); checkInterface(sourceCode, interface);
} }
BOOST_AUTO_TEST_CASE(multiple_methods_order) BOOST_AUTO_TEST_CASE(multiple_methods_order)
@ -204,7 +219,7 @@ BOOST_AUTO_TEST_CASE(multiple_methods_order)
} }
])"; ])";
BOOST_CHECK(checkInterface(sourceCode, interface)); checkInterface(sourceCode, interface);
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

400
test/solidityNatspecJSON.cpp

@ -0,0 +1,400 @@
/*
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/>.
*/
/**
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2014
* Unit tests for the solidity compiler JSON Interface output.
*/
#include <boost/test/unit_test.hpp>
#include <libsolidity/CompilerStack.h>
#include <jsonrpc/json/json.h>
#include <libdevcore/Exceptions.h>
namespace dev
{
namespace solidity
{
namespace test
{
class DocumentationChecker
{
public:
void checkNatspec(std::string const& _code,
std::string const& _expectedDocumentationString,
bool _userDocumentation)
{
std::string generatedDocumentationString;
try
{
m_compilerStack.parse(_code);
}
catch (const std::exception& e)
{
std::string const* extra = boost::get_error_info<errinfo_comment>(e);
std::string msg = std::string("Parsing contract failed with: ") +
e.what() + std::string("\n");
if (extra)
msg += *extra;
BOOST_FAIL(msg);
}
if (_userDocumentation)
generatedDocumentationString = m_compilerStack.getJsonDocumentation("", NATSPEC_USER);
else
generatedDocumentationString = m_compilerStack.getJsonDocumentation("", NATSPEC_DEV);
Json::Value generatedDocumentation;
m_reader.parse(generatedDocumentationString, generatedDocumentation);
Json::Value expectedDocumentation;
m_reader.parse(_expectedDocumentationString, expectedDocumentation);
BOOST_CHECK_MESSAGE(expectedDocumentation == generatedDocumentation,
"Expected " << _expectedDocumentationString <<
"\n but got:\n" << generatedDocumentationString);
}
private:
CompilerStack m_compilerStack;
Json::Reader m_reader;
};
BOOST_FIXTURE_TEST_SUITE(SolidityNatspecJSON, DocumentationChecker)
BOOST_AUTO_TEST_CASE(user_basic_test)
{
char const* sourceCode = "contract test {\n"
" /// @notice Multiplies `a` by 7\n"
" function mul(uint a) returns(uint d) { return a * 7; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}"
"}}";
checkNatspec(sourceCode, natspec, true);
}
BOOST_AUTO_TEST_CASE(dev_and_user_basic_test)
{
char const* sourceCode = "contract test {\n"
" /// @notice Multiplies `a` by 7\n"
" /// @dev Multiplies a number by 7\n"
" function mul(uint a) returns(uint d) { return a * 7; }\n"
"}\n";
char const* devNatspec = "{"
"\"methods\":{"
" \"mul\":{ \n"
" \"details\": \"Multiplies a number by 7\"\n"
" }\n"
" }\n"
"}}";
char const* userNatspec = "{"
"\"methods\":{"
" \"mul\":{ \"notice\": \"Multiplies `a` by 7\"}"
"}}";
checkNatspec(sourceCode, devNatspec, false);
checkNatspec(sourceCode, userNatspec, true);
}
BOOST_AUTO_TEST_CASE(user_multiline_comment)
{
char const* sourceCode = "contract test {\n"
" /// @notice Multiplies `a` by 7\n"
" /// and then adds `b`\n"
" function mul_and_add(uint a, uint256 b) returns(uint256 d)\n"
" {\n"
" return (a * 7) + b;\n"
" }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul_and_add\":{ \"notice\": \"Multiplies `a` by 7 and then adds `b`\"}"
"}}";
checkNatspec(sourceCode, natspec, true);
}
BOOST_AUTO_TEST_CASE(user_multiple_functions)
{
char const* sourceCode = "contract test {\n"
" /// @notice Multiplies `a` by 7 and then adds `b`\n"
" function mul_and_add(uint a, uint256 b) returns(uint256 d)\n"
" {\n"
" return (a * 7) + b;\n"
" }\n"
"\n"
" /// @notice Divides `input` by `div`\n"
" function divide(uint input, uint div) returns(uint d)\n"
" {\n"
" return input / div;\n"
" }\n"
" /// @notice Subtracts 3 from `input`\n"
" function sub(int input) returns(int d)\n"
" {\n"
" return input - 3;\n"
" }\n"
"}\n";
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`\"}"
"}}";
checkNatspec(sourceCode, natspec, true);
}
BOOST_AUTO_TEST_CASE(user_empty_contract)
{
char const* sourceCode = "contract test {\n"
"}\n";
char const* natspec = "{\"methods\":{} }";
checkNatspec(sourceCode, natspec, true);
}
BOOST_AUTO_TEST_CASE(dev_and_user_no_doc)
{
char const* sourceCode = "contract test {\n"
" function mul(uint a) returns(uint d) { return a * 7; }\n"
" function sub(int input) returns(int d)\n"
" {\n"
" return input - 3;\n"
" }\n"
"}\n";
char const* devNatspec = "{\"methods\":{}}";
char const* userNatspec = "{\"methods\":{}}";
checkNatspec(sourceCode, devNatspec, false);
checkNatspec(sourceCode, userNatspec, true);
}
BOOST_AUTO_TEST_CASE(dev_desc_after_nl)
{
char const* sourceCode = "contract test {\n"
" /// @dev\n"
" /// Multiplies a number by 7 and adds second parameter\n"
" /// @param a Documentation for the first parameter\n"
" /// @param second Documentation for the second parameter\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \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"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_multiple_params)
{
char const* sourceCode = "contract test {\n"
" /// @dev Multiplies a number by 7 and adds second parameter\n"
" /// @param a Documentation for the first parameter\n"
" /// @param second Documentation for the second parameter\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \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"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_mutiline_param_description)
{
char const* sourceCode = "contract test {\n"
" /// @dev Multiplies a number by 7 and adds second parameter\n"
" /// @param a Documentation for the first parameter starts here.\n"
" /// Since it's a really complicated parameter we need 2 lines\n"
" /// @param second Documentation for the second parameter\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \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"
" \"second\": \"Documentation for the second parameter\"\n"
" }\n"
" }\n"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_multiple_functions)
{
char const* sourceCode = "contract test {\n"
" /// @dev Multiplies a number by 7 and adds second parameter\n"
" /// @param a Documentation for the first parameter\n"
" /// @param second Documentation for the second parameter\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
" \n"
" /// @dev Divides 2 numbers\n"
" /// @param input Documentation for the input parameter\n"
" /// @param div Documentation for the div parameter\n"
" function divide(uint input, uint div) returns(uint d)\n"
" {\n"
" return input / div;\n"
" }\n"
" /// @dev Subtracts 3 from `input`\n"
" /// @param input Documentation for the input parameter\n"
" function sub(int input) returns(int d)\n"
" {\n"
" return input - 3;\n"
" }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \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"
" \"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"
" \"details\": \"Subtracts 3 from `input`\",\n"
" \"params\": {\n"
" \"input\": \"Documentation for the input parameter\"\n"
" }\n"
" }\n"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_return)
{
char const* sourceCode = "contract test {\n"
" /// @dev Multiplies a number by 7 and adds second parameter\n"
" /// @param a Documentation for the first parameter starts here.\n"
" /// Since it's a really complicated parameter we need 2 lines\n"
" /// @param second Documentation for the second parameter\n"
" /// @return The result of the multiplication\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \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"
" \"second\": \"Documentation for the second parameter\"\n"
" },\n"
" \"return\": \"The result of the multiplication\"\n"
" }\n"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_return_desc_after_nl)
{
char const* sourceCode = "contract test {\n"
" /// @dev Multiplies a number by 7 and adds second parameter\n"
" /// @param a Documentation for the first parameter starts here.\n"
" /// Since it's a really complicated parameter we need 2 lines\n"
" /// @param second Documentation for the second parameter\n"
" /// @return\n"
" /// The result of the multiplication\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \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"
" \"second\": \"Documentation for the second parameter\"\n"
" },\n"
" \"return\": \" The result of the multiplication\"\n"
" }\n"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_CASE(dev_multiline_return)
{
char const* sourceCode = "contract test {\n"
" /// @dev Multiplies a number by 7 and adds second parameter\n"
" /// @param a Documentation for the first parameter starts here.\n"
" /// Since it's a really complicated parameter we need 2 lines\n"
" /// @param second Documentation for the second parameter\n"
" /// @return The result of the multiplication\n"
" /// and cookies with nutella\n"
" function mul(uint a, uint second) returns(uint d) { return a * 7 + second; }\n"
"}\n";
char const* natspec = "{"
"\"methods\":{"
" \"mul\":{ \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"
" \"second\": \"Documentation for the second parameter\"\n"
" },\n"
" \"return\": \"The result of the multiplication and cookies with nutella\"\n"
" }\n"
"}}";
checkNatspec(sourceCode, natspec, false);
}
BOOST_AUTO_TEST_SUITE_END()
}
}
}

12
test/stSystemOperationsTestFiller.json

@ -12,7 +12,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }", "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 28) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -46,7 +46,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }", "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 1000 4 28) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -80,7 +80,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }", "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 0xfffffffffff 28) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -114,7 +114,7 @@
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000", "balance" : "1000000000000000000",
"nonce" : 0, "nonce" : 0,
"code" : "{ (MSTORE 0 0x601080600c6000396000f20060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }", "code" : "{ (MSTORE 0 0x601080600c6000396000f30060003554156009570060203560003555) [[ 0 ]] (CREATE 23 4 0xfffffffffff) }",
"storage": {} "storage": {}
}, },
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
@ -195,7 +195,7 @@
}, },
"945304eb96065b2a98b57a48a06ae28d285a71b5" : { "945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23", "balance" : "23",
"code" : "0x6001600155603760005360026000f2", "code" : "0x6001600155603760005360026000f3",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
@ -321,7 +321,7 @@
}, },
"945304eb96065b2a98b57a48a06ae28d285a71b5" : { "945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23", "balance" : "23",
"code" : "0x6001600155603760005360026000f2", "code" : "0x6001600155603760005360026000f3",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }

Loading…
Cancel
Save