Browse Source

Merge branch 'develop' into pr-fixes

Conflicts:
	libdevcrypto/EC.cpp
cl-refactor
Paweł Bylica 10 years ago
parent
commit
818c0b6156
  1. 2
      CMakeLists.txt
  2. 2
      alethzero/CMakeLists.txt
  3. 22
      alethzero/MainWin.cpp
  4. 2
      alethzero/MainWin.h
  5. 2
      alethzero/OurWebThreeStubServer.cpp
  6. 2
      alethzero/OurWebThreeStubServer.h
  7. 2
      eth/main.cpp
  8. 96
      exp/main.cpp
  9. 2
      iethxi/MainWin.cpp
  10. 2
      libdevcore/Common.cpp
  11. 8
      libdevcore/CommonData.cpp
  12. 2
      libdevcore/CommonIO.cpp
  13. 1
      libdevcore/Log.h
  14. 9
      libdevcore/RLP.h
  15. 3
      libdevcrypto/Common.cpp
  16. 25
      libdevcrypto/EC.cpp
  17. 2
      libethcore/CommonEth.cpp
  18. 11
      libethereum/Executive.cpp
  19. 2
      libethereum/Executive.h
  20. 2
      libethereum/ExtVM.h
  21. 22
      libethereum/State.cpp
  22. 2
      libethereum/TransactionReceipt.h
  23. 2
      libevm/CMakeLists.txt
  24. 2
      libevm/ExtVMFace.cpp
  25. 8
      libevm/ExtVMFace.h
  26. 3
      libevm/FeeStructure.cpp
  27. 3
      libevm/FeeStructure.h
  28. 31
      libevm/VM.h
  29. 81
      libevmcore/Assembly.cpp
  30. 4
      libevmcore/Assembly.h
  31. 2
      libevmcore/CMakeLists.txt
  32. 36
      libevmcore/Exceptions.h
  33. 337
      libevmcore/Instruction.cpp
  34. 8
      libevmcore/Instruction.h
  35. 337
      libevmface/Instruction.cpp
  36. 109
      libjsqrc/main.js
  37. 8
      libjsqrc/qt.js
  38. 2
      libjsqrc/setup.js
  39. 1
      liblll/All.h
  40. 2
      liblll/CMakeLists.txt
  41. 2
      liblll/CodeFragment.cpp
  42. 4
      liblll/CodeFragment.h
  43. 3
      liblll/Exceptions.h
  44. 2
      libpyserpent/CMakeLists.txt
  45. 30
      libqethereum/QEthereum.cpp
  46. 2
      libqethereum/QmlEthereum.cpp
  47. 2
      libserpent/CMakeLists.txt
  48. 3
      libserpent/compiler.cpp
  49. 33
      libsolidity/AST.cpp
  50. 13
      libsolidity/AST.h
  51. 8
      libsolidity/ASTPrinter.cpp
  52. 4
      libsolidity/ASTPrinter.h
  53. 10
      libsolidity/CMakeLists.txt
  54. 65
      libsolidity/Compiler.cpp
  55. 4
      libsolidity/Compiler.h
  56. 36
      libsolidity/CompilerContext.cpp
  57. 31
      libsolidity/CompilerContext.h
  58. 99
      libsolidity/CompilerStack.cpp
  59. 41
      libsolidity/CompilerStack.h
  60. 234
      libsolidity/ExpressionCompiler.cpp
  61. 66
      libsolidity/ExpressionCompiler.h
  62. 106
      libsolidity/Scanner.cpp
  63. 2
      libsolidity/Scanner.h
  64. 84
      libsolidity/Token.h
  65. 75
      libsolidity/Types.cpp
  66. 21
      libsolidity/Types.h
  67. 101
      libweb3jsonrpc/WebThreeStubServer.cpp
  68. 87
      libweb3jsonrpc/WebThreeStubServer.h
  69. 343
      libweb3jsonrpc/abstractwebthreestubserver.h
  70. 101
      libweb3jsonrpc/spec.json
  71. 35
      libwhisper/Common.cpp
  72. 18
      libwhisper/Common.h
  73. 7
      libwhisper/Interface.cpp
  74. 2
      libwhisper/Interface.h
  75. 4
      libwhisper/Message.cpp
  76. 15
      libwhisper/Message.h
  77. 7
      libwhisper/WhisperHost.cpp
  78. 2
      libwhisper/WhisperHost.h
  79. 4
      libwhisper/WhisperPeer.cpp
  80. 2
      libwhisper/WhisperPeer.h
  81. 2
      lllc/CMakeLists.txt
  82. 2
      lllc/main.cpp
  83. 2
      neth/main.cpp
  84. 2
      sc/CMakeLists.txt
  85. 45
      solc/main.cpp
  86. 52
      test/TestHelper.cpp
  87. 2
      test/TestHelper.h
  88. 15
      test/createRandomTest.cpp
  89. 46
      test/jsonrpc.cpp
  90. 22
      test/solidityCompiler.cpp
  91. 362
      test/solidityEndToEndTest.cpp
  92. 111
      test/solidityExpressionCompiler.cpp
  93. 214
      test/solidityJSONInterfaceTest.cpp
  94. 16
      test/solidityNameAndTypeResolution.cpp
  95. 26
      test/solidityScanner.cpp
  96. 717
      test/stPreCompiledContractsFiller.json
  97. 1334
      test/stSystemOperationsTestFiller.json
  98. 53
      test/state.cpp
  99. 44
      test/tmpFiller.json
  100. 61
      test/vm.cpp

2
CMakeLists.txt

@ -106,7 +106,7 @@ include(EthDependenciesDeprecated)
createBuildInfo() createBuildInfo()
add_subdirectory(libdevcore) add_subdirectory(libdevcore)
add_subdirectory(libevmface) add_subdirectory(libevmcore)
add_subdirectory(liblll) add_subdirectory(liblll)
add_subdirectory(libserpent) add_subdirectory(libserpent)
add_subdirectory(libsolidity) add_subdirectory(libsolidity)

2
alethzero/CMakeLists.txt

@ -53,7 +53,7 @@ else ()
endif () endif ()
qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets)
target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmface devcore web3jsonrpc jsqrc) target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmcore devcore web3jsonrpc jsqrc)
if (APPLE) if (APPLE)
# First have qt5 install plugins and frameworks # First have qt5 install plugins and frameworks

22
alethzero/MainWin.cpp

@ -610,6 +610,7 @@ void Main::readSettings(bool _skipGeometry)
} }
} }
ethereum()->setAddress(m_myKeys.back().address()); ethereum()->setAddress(m_myKeys.back().address());
m_server->setAccounts(keysAsVector(m_myKeys));
} }
{ {
@ -1257,9 +1258,10 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress; s << "<br/>Coinbase: <b>" << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << "</b> " << info.coinbaseAddress;
s << "<br/>Nonce: <b>" << info.nonce << "</b>"; s << "<br/>Nonce: <b>" << info.nonce << "</b>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>"; s << "<br/>Parent: <b>" << info.parentHash << "</b>";
s << "<br/>Bloom: <b>" << details.bloom << "</b>"; // s << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Log Bloom: <b>" << info.logBloom << "</b>"; s << "<br/>Log Bloom: <b>" << info.logBloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>"; s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Receipts: @<b>" << info.receiptsRoot << "</b>:";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>"; s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
for (auto u: block[2]) for (auto u: block[2])
{ {
@ -1282,6 +1284,7 @@ void Main::on_blocks_currentItemChanged()
Transaction tx(block[1][txi].data()); Transaction tx(block[1][txi].data());
auto ss = tx.safeSender(); auto ss = tx.safeSender();
h256 th = sha3(rlpList(ss, tx.nonce())); h256 th = sha3(rlpList(ss, tx.nonce()));
auto receipt = ethereum()->blockChain().receipts(h).receipts[txi];
s << "<h3>" << th << "</h3>"; s << "<h3>" << th << "</h3>";
s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>"; s << "<h4>" << h << "[<b>" << txi << "</b>]</h4>";
s << "<br/>From: <b>" << pretty(ss).toHtmlEscaped().toStdString() << "</b> " << ss; s << "<br/>From: <b>" << pretty(ss).toHtmlEscaped().toStdString() << "</b> " << ss;
@ -1297,6 +1300,10 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>R: <b>" << hex << nouppercase << tx.signature().r << "</b>"; s << "<br/>R: <b>" << hex << nouppercase << tx.signature().r << "</b>";
s << "<br/>S: <b>" << hex << nouppercase << tx.signature().s << "</b>"; s << "<br/>S: <b>" << hex << nouppercase << tx.signature().s << "</b>";
s << "<br/>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>"; s << "<br/>Msg: <b>" << tx.sha3(eth::WithoutSignature) << "</b>";
s << "<div>Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(block[1][txi].data()) << "</span></div>";
auto r = receipt.rlp();
s << "<div>Receipt: " << toString(RLP(r)) << "</div>";
s << "<div>Receipt-Hex: <span style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">" << toHex(receipt.rlp()) << "</span></div>";
if (tx.isCreation()) if (tx.isCreation())
{ {
if (tx.data().size()) if (tx.data().size())
@ -1374,7 +1381,7 @@ void Main::populateDebugger(dev::bytesConstRef _r)
debugFinished(); debugFinished();
vector<WorldState const*> levels; vector<WorldState const*> levels;
m_codes.clear(); m_codes.clear();
bytesConstRef lastExtCode; bytes lastExtCode;
bytesConstRef lastData; bytesConstRef lastData;
h256 lastHash; h256 lastHash;
h256 lastDataHash; h256 lastDataHash;
@ -1387,7 +1394,7 @@ void Main::populateDebugger(dev::bytesConstRef _r)
lastExtCode = ext.code; lastExtCode = ext.code;
lastHash = sha3(lastExtCode); lastHash = sha3(lastExtCode);
if (!m_codes.count(lastHash)) if (!m_codes.count(lastHash))
m_codes[lastHash] = ext.code.toBytes(); m_codes[lastHash] = ext.code;
} }
if (ext.data != lastData) if (ext.data != lastData)
{ {
@ -1601,15 +1608,15 @@ void Main::on_data_textChanged()
} }
else if (src.substr(0, 8) == "contract") // improve this heuristic else if (src.substr(0, 8) == "contract") // improve this heuristic
{ {
shared_ptr<solidity::Scanner> scanner = make_shared<solidity::Scanner>(); dev::solidity::CompilerStack compiler;
try try
{ {
m_data = dev::solidity::CompilerStack::compile(src, scanner); m_data = compiler.compile(src, m_enableOptimizer);
} }
catch (dev::Exception const& exception) catch (dev::Exception const& exception)
{ {
ostringstream error; ostringstream error;
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", *scanner); solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner());
solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>"; solidity = "<h4>Solidity</h4><pre>" + QString::fromStdString(error.str()).toHtmlEscaped() + "</pre>";
} }
catch (...) catch (...)
@ -1821,6 +1828,7 @@ void Main::on_send_clicked()
void Main::keysChanged() void Main::keysChanged()
{ {
onBalancesChange(); onBalancesChange();
m_server->setAccounts(keysAsVector(m_myKeys));
} }
void Main::on_debug_clicked() void Main::on_debug_clicked()
@ -2218,7 +2226,7 @@ void Main::refreshWhispers()
time_t ex = e.expiry(); time_t ex = e.expiry();
QString t(ctime(&ex)); QString t(ctime(&ex));
t.chop(1); t.chop(1);
QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topics()).c_str()).arg(msg);
ui->whispers->addItem(item); ui->whispers->addItem(item);
} }
} }

2
alethzero/MainWin.h

@ -154,6 +154,7 @@ private slots:
void on_newIdentity_triggered(); void on_newIdentity_triggered();
void refreshWhisper(); void refreshWhisper();
void refreshBlockChain();
void addNewId(QString _ids); void addNewId(QString _ids);
signals: signals:
@ -214,7 +215,6 @@ private:
void refreshPending(); void refreshPending();
void refreshAccounts(); void refreshAccounts();
void refreshDestination(); void refreshDestination();
void refreshBlockChain();
void refreshBlockCount(); void refreshBlockCount();
void refreshBalances(); void refreshBalances();

2
alethzero/OurWebThreeStubServer.cpp

@ -28,7 +28,7 @@ OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector* _
WebThreeStubServer(_conn, _web3, _accounts) WebThreeStubServer(_conn, _web3, _accounts)
{} {}
std::string OurWebThreeStubServer::newIdentity() std::string OurWebThreeStubServer::shh_newIdentity()
{ {
dev::KeyPair kp = dev::KeyPair::create(); dev::KeyPair kp = dev::KeyPair::create();
emit onNewId(QString::fromStdString(toJS(kp.sec()))); emit onNewId(QString::fromStdString(toJS(kp.sec())));

2
alethzero/OurWebThreeStubServer.h

@ -31,7 +31,7 @@ class OurWebThreeStubServer: public QObject, public WebThreeStubServer
public: 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);
virtual std::string newIdentity() override; virtual std::string shh_newIdentity() override;
signals: signals:
void onNewId(QString _s); void onNewId(QString _s);

2
eth/main.cpp

@ -32,7 +32,7 @@
#include <libweb3jsonrpc/CorsHttpServer.h> #include <libweb3jsonrpc/CorsHttpServer.h>
#endif #endif
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>

96
exp/main.cpp

@ -36,7 +36,7 @@ using namespace dev::eth;
using namespace dev::p2p; using namespace dev::p2p;
using namespace dev::shh; using namespace dev::shh;
#if 0 #if 1
int main() int main()
{ {
DownloadMan man; DownloadMan man;
@ -44,18 +44,19 @@ int main()
DownloadSub s1(man); DownloadSub s1(man);
DownloadSub s2(man); DownloadSub s2(man);
man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)})); man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)}));
cnote << s0.nextFetch(2); assert((s0.nextFetch(2) == h256Set{(u256)7, (u256)8}));
cnote << s1.nextFetch(2); assert((s1.nextFetch(2) == h256Set{(u256)5, (u256)6}));
cnote << s2.nextFetch(2); assert((s2.nextFetch(2) == h256Set{(u256)3, (u256)4}));
s0.noteBlock(u256(0)); s0.noteBlock(u256(8));
s0.doneFetch(); s0.doneFetch();
cnote << s0.nextFetch(2); assert((s0.nextFetch(2) == h256Set{(u256)2, (u256)7}));
s1.noteBlock(u256(2)); s1.noteBlock(u256(6));
s1.noteBlock(u256(3)); s1.noteBlock(u256(5));
s1.doneFetch(); s1.doneFetch();
cnote << s1.nextFetch(2); assert((s1.nextFetch(2) == h256Set{(u256)0, (u256)1}));
s0.doneFetch(); s0.doneFetch(); // TODO: check exact semantics of doneFetch & nextFetch. Not sure if they're right -> doneFetch calls resetFetch which kills all the info of past fetches.
cnote << s0.nextFetch(2); cdebug << s0.nextFetch(2);
assert((s0.nextFetch(2) == h256Set{(u256)3, (u256)4}));
/* RangeMask<unsigned> m(0, 100); /* RangeMask<unsigned> m(0, 100);
cnote << m; cnote << m;
@ -73,49 +74,70 @@ int main()
} }
#endif #endif
int main(int argc, char** argv) /*int other(bool& o_started)
{ {
g_logVerbosity = 20; setThreadName("other");
short listenPort = 30303;
string remoteHost;
short remotePort = 30303;
for (int i = 1; i < argc; ++i) short listenPort = 30300;
{
string arg = argv[i];
if (arg == "-l" && i + 1 < argc)
listenPort = (short)atoi(argv[++i]);
else if (arg == "-r" && i + 1 < argc)
remoteHost = argv[++i];
else if (arg == "-p" && i + 1 < argc)
remotePort = (short)atoi(argv[++i]);
else
remoteHost = argv[i];
}
Host ph("Test", NetworkPreferences(listenPort, "", false, true)); Host ph("Test", NetworkPreferences(listenPort, "", false, true));
auto wh = ph.registerCapability(new WhisperHost()); auto wh = ph.registerCapability(new WhisperHost());
ph.start(); ph.start();
if (!remoteHost.empty()) o_started = true;
ph.connect(remoteHost, remotePort);
/// Only interested in odd packets /// Only interested in odd packets
auto w = wh->installWatch(BuildTopicMask()("odd")); auto w = wh->installWatch(BuildTopicMask()("odd"));
KeyPair us = KeyPair::create(); unsigned last = 0;
for (int i = 0; ; ++i) unsigned total = 0;
for (int i = 0; i < 100 && last < 81; ++i)
{ {
wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
for (auto i: wh->checkWatch(w)) for (auto i: wh->checkWatch(w))
{ {
Message msg = wh->envelope(i).open(); Message msg = wh->envelope(i).open();
last = RLP(msg.payload()).toInt<unsigned>();
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>(); cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
total += last;
} }
this_thread::sleep_for(chrono::seconds(1)); this_thread::sleep_for(chrono::milliseconds(50));
} }
return 0; return total;
} }
int main(int, char**)
{
g_logVerbosity = 0;
bool started = false;
unsigned result;
std::thread listener([&](){ return (result = other(started)); });
while (!started)
this_thread::sleep_for(chrono::milliseconds(50));
short listenPort = 30303;
string remoteHost = "127.0.0.1";
short remotePort = 30300;
Host ph("Test", NetworkPreferences(listenPort, "", false, true));
auto wh = ph.registerCapability(new WhisperHost());
ph.start();
if (!remoteHost.empty())
ph.connect(remoteHost, remotePort);
KeyPair us = KeyPair::create();
for (int i = 0; i < 10; ++i)
{
wh->post(us.sec(), RLPStream().append(i * i).out(), BuildTopic(i)(i % 2 ? "odd" : "even"));
this_thread::sleep_for(chrono::milliseconds(250));
}
listener.join();
assert(result == 1 + 9 + 25 + 49 + 81);
return 0;
}*/

2
iethxi/MainWin.cpp

@ -9,7 +9,7 @@
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <libethcore/FileSystem.h> #include <libethcore/FileSystem.h>
#include <libethcore/Dagger.h> #include <libethcore/Dagger.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>
#include "BuildInfo.h" #include "BuildInfo.h"

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.7.9"; char const* Version = "0.7.10";
} }

8
libdevcore/CommonData.cpp

@ -29,14 +29,20 @@ using namespace dev;
std::string dev::escaped(std::string const& _s, bool _all) std::string dev::escaped(std::string const& _s, bool _all)
{ {
static const map<char, char> prettyEscapes{{'\r', 'r'}, {'\n', 'n'}, {'\t', 't'}, {'\v', 'v'}};
std::string ret; std::string ret;
ret.reserve(_s.size()); ret.reserve(_s.size() + 2);
ret.push_back('"'); ret.push_back('"');
for (auto i: _s) for (auto i: _s)
if (i == '"' && !_all) if (i == '"' && !_all)
ret += "\\\""; ret += "\\\"";
else if (i == '\\' && !_all) else if (i == '\\' && !_all)
ret += "\\\\"; ret += "\\\\";
else if (prettyEscapes.count(i))
{
ret += '\\';
ret += prettyEscapes.find(i)->second;
}
else if (i < ' ' || _all) else if (i < ' ' || _all)
{ {
ret += "\\x"; ret += "\\x";

2
libdevcore/CommonIO.cpp

@ -30,7 +30,7 @@ string dev::memDump(bytes const& _b, unsigned _w, bool _html)
{ {
stringstream ret; stringstream ret;
if (_html) if (_html)
ret << "<pre style=\"font-family: Monospace, sans-serif; font-size: small\">"; ret << "<pre style=\"font-family: Monospace,Lucida Console,Courier,Courier New,sans-serif; font-size: small\">";
for (unsigned i = 0; i < _b.size(); i += _w) for (unsigned i = 0; i < _b.size(); i += _w)
{ {
ret << hex << setw(4) << setfill('0') << i << " "; ret << hex << setw(4) << setfill('0') << i << " ";

1
libdevcore/Log.h

@ -27,6 +27,7 @@
#include <chrono> #include <chrono>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include "vector_ref.h" #include "vector_ref.h"
#include "CommonIO.h"
namespace dev namespace dev
{ {

9
libdevcore/RLP.h

@ -158,8 +158,13 @@ public:
/// Best-effort conversion operators. /// Best-effort conversion operators.
explicit operator std::string() const { return toString(); } explicit operator std::string() const { return toString(); }
explicit operator bytes() const { return toBytes(); }
explicit operator RLPs() const { return toList(); } explicit operator RLPs() const { return toList(); }
explicit operator byte() const { return toInt<byte>(); } explicit operator uint8_t() const { return toInt<uint8_t>(); }
explicit operator uint16_t() const { return toInt<uint16_t>(); }
explicit operator uint32_t() const { return toInt<uint32_t>(); }
explicit operator uint64_t() const { return toInt<uint64_t>(); }
explicit operator u160() const { return toInt<u160>(); }
explicit operator u256() const { return toInt<u256>(); } explicit operator u256() const { return toInt<u256>(); }
explicit operator bigint() const { return toInt<bigint>(); } explicit operator bigint() const { return toInt<bigint>(); }
template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); } template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); }
@ -337,7 +342,7 @@ public:
RLPStream& append(char const* _s) { return append(std::string(_s)); } RLPStream& append(char const* _s) { return append(std::string(_s)); }
template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); } template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); }
/// Appends an arbitrary RLP fragment - this *must* be a single item. /// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given.
RLPStream& append(RLP const& _rlp, unsigned _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } RLPStream& append(RLP const& _rlp, unsigned _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }
/// Appends a sequence of data to the stream as a list. /// Appends a sequence of data to the stream as a list.

3
libdevcrypto/Common.cpp

@ -21,6 +21,7 @@
*/ */
#include <random> #include <random>
#include <chrono>
#include <mutex> #include <mutex>
#include "EC.h" #include "EC.h"
#include "SHA3.h" #include "SHA3.h"
@ -39,7 +40,7 @@ Address dev::toAddress(Secret _secret)
KeyPair KeyPair::create() KeyPair KeyPair::create()
{ {
static mt19937_64 s_eng(time(0)); static mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
uniform_int_distribution<uint16_t> d(0, 255); uniform_int_distribution<uint16_t> d(0, 255);
for (int i = 0; i < 100; ++i) for (int i = 0; i < 100; ++i)

25
libdevcrypto/EC.cpp

@ -37,6 +37,8 @@ using namespace dev::crypto;
using namespace CryptoPP; using namespace CryptoPP;
using namespace pp; using namespace pp;
static const int c_publicKeySize = 65; // Public key size for I/O is 65 bytes (there's an extra byte that we don't really need).
void crypto::toPublic(Secret const& _s, Public& o_public) void crypto::toPublic(Secret const& _s, Public& o_public)
{ {
exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public);
@ -134,16 +136,16 @@ bool crypto::verify(Signature const& _signature, bytesConstRef _message)
bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed)
{ {
static const size_t c_derMaxEncodingLength = 72;
if (_hashed) if (_hashed)
{ {
assert(_message.size() == 32); assert(_message.size() == 32);
byte encpub[65] = {0x04}; byte encpub[65] = {0x04};
memcpy(&encpub[1], _p.data(), 64); memcpy(&encpub[1], _p.data(), 64);
static const size_t c_derMaxEncodingLength = 72;
byte dersig[c_derMaxEncodingLength]; byte dersig[c_derMaxEncodingLength];
size_t cssz = DSAConvertSignatureFormat(dersig, c_derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363); size_t cssz = DSAConvertSignatureFormat(dersig, c_derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363);
assert(cssz <= c_derMaxEncodingLength); assert(cssz <= c_derMaxEncodingLength);
return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, 65)); return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, c_publicKeySize));
} }
ECDSA<ECP, SHA3_256>::Verifier verifier; ECDSA<ECP, SHA3_256>::Verifier verifier;
@ -155,10 +157,9 @@ Public crypto::recover(Signature _signature, bytesConstRef _message)
{ {
secp256k1_start(); secp256k1_start();
static const int c_pubkeylen = 65; byte pubkey[c_publicKeySize];
int pubkeylen = c_pubkeylen; int keySize;
byte pubkey[c_pubkeylen]; if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &keySize, 0, (int)_signature[64]) || keySize != c_publicKeySize)
if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64]))
return Public(); return Public();
#if ETH_CRYPTO_TRACE #if ETH_CRYPTO_TRACE
@ -181,14 +182,14 @@ bool crypto::verifySecret(Secret const& _s, Public const& _p)
if (!ok) if (!ok)
return false; return false;
static const int c_pubkeylen = 65; byte pubkey[c_publicKeySize];
int pubkeylen = c_pubkeylen;
byte pubkey[c_pubkeylen]; int keySize;
ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0); ok = secp256k1_ecdsa_pubkey_create(pubkey, &keySize, _s.data(), 0);
if (!ok || pubkeylen != 65) if (!ok || keySize != c_publicKeySize)
return false; return false;
ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); ok = secp256k1_ecdsa_pubkey_verify(pubkey, c_publicKeySize);
if (!ok) if (!ok)
return false; return false;

2
libethcore/CommonEth.cpp

@ -34,7 +34,7 @@ namespace dev
namespace eth namespace eth
{ {
const unsigned c_protocolVersion = 39; const unsigned c_protocolVersion = 42;
const unsigned c_databaseVersion = 4; const unsigned c_databaseVersion = 4;
static const vector<pair<u256, string>> g_units = static const vector<pair<u256, string>> g_units =

11
libethereum/Executive.cpp

@ -80,14 +80,14 @@ bool Executive::setup(bytesConstRef _rlp)
if (m_s.balance(m_sender) < cost) if (m_s.balance(m_sender) < cost)
{ {
clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender); clog(StateDetail) << "Not enough cash: Require >" << cost << " Got" << m_s.balance(m_sender);
BOOST_THROW_EXCEPTION(NotEnoughCash()); BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError((int)cost, (int)m_s.balance(m_sender)));
} }
u256 startGasUsed = m_s.gasUsed(); u256 startGasUsed = m_s.gasUsed();
if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit) if (startGasUsed + m_t.gas() > m_s.m_currentBlock.gasLimit)
{ {
clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas();
BOOST_THROW_EXCEPTION(BlockGasLimitReached()); BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((int)(m_s.m_currentBlock.gasLimit - startGasUsed), (int)m_t.gas()));
} }
// Increment associated nonce for sender. // Increment associated nonce for sender.
@ -123,11 +123,7 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms); m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
} }
else else
{
m_endGas = _gas; m_endGas = _gas;
if (m_ext)
m_ext->sub.logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes()));
}
return !m_ext; return !m_ext;
} }
@ -177,7 +173,10 @@ bool Executive::go(OnOpFunc const& _onOp)
{ {
m_out = m_vm->go(*m_ext, _onOp); m_out = m_vm->go(*m_ext, _onOp);
if (m_ext) if (m_ext)
{
m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds); m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds);
m_logs = m_ext->sub.logs;
}
m_endGas = m_vm->gas(); m_endGas = m_vm->gas();
} }
catch (StepsDone const&) catch (StepsDone const&)

2
libethereum/Executive.h

@ -23,7 +23,7 @@
#include <functional> #include <functional>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include "Transaction.h" #include "Transaction.h"

2
libethereum/ExtVM.h

@ -40,7 +40,7 @@ class ExtVM: public ExtVMFace
public: public:
/// Full constructor. /// Full constructor.
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _depth = 0): ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _depth = 0):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms) ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms)
{ {
m_s.ensureCached(_myAddress, true, true); m_s.ensureCached(_myAddress, true, true);
} }

22
libethereum/State.cpp

@ -21,12 +21,13 @@
#include "State.h" #include "State.h"
#include <boost/filesystem.hpp> #include <ctime>
#include <time.h>
#include <random> #include <random>
#include <boost/filesystem.hpp>
#include <boost/timer.hpp>
#include <secp256k1/secp256k1.h> #include <secp256k1/secp256k1.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include "BlockChain.h" #include "BlockChain.h"
@ -553,10 +554,12 @@ h256s State::sync(TransactionQueue& _tq, bool* o_transactionQueueChanged)
try try
{ {
uncommitToMine(); uncommitToMine();
// boost::timer t;
execute(i.second); execute(i.second);
ret.push_back(m_receipts.back().changes().bloom()); ret.push_back(m_receipts.back().changes().bloom());
_tq.noteGood(i); _tq.noteGood(i);
++goodTxs; ++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
} }
catch (InvalidNonce const& in) catch (InvalidNonce const& in)
{ {
@ -1194,12 +1197,15 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
auto it = !(_codeAddress & ~h160(0xffffffff)) ? c_precompiled.find((unsigned)(u160)_codeAddress) : c_precompiled.end(); auto it = !(_codeAddress & ~h160(0xffffffff)) ? c_precompiled.find((unsigned)(u160)_codeAddress) : c_precompiled.end();
if (it != c_precompiled.end()) if (it != c_precompiled.end())
{ {
if (*_gas >= it->second.gas) if (*_gas < it->second.gas)
{ {
*_gas = 0;
return false;
}
*_gas -= it->second.gas; *_gas -= it->second.gas;
it->second.exec(_data, _out); it->second.exec(_data, _out);
} }
}
else if (addressHasCode(_codeAddress)) else if (addressHasCode(_codeAddress))
{ {
VM vm(*_gas); VM vm(*_gas);
@ -1239,12 +1245,6 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
return !revert; return !revert;
} }
else
{
// non-contract call
if (o_sub)
o_sub->logs.push_back(LogEntry(_receiveAddress, {u256((u160)_senderAddress) + 1}, bytes()));
}
return true; return true;
} }

2
libethereum/TransactionReceipt.h

@ -55,6 +55,8 @@ public:
l.streamRLP(_s); l.streamRLP(_s);
} }
bytes rlp() const { RLPStream s; streamRLP(s); return s.out(); }
private: private:
h256 m_stateRoot; h256 m_stateRoot;
u256 m_gasUsed; u256 m_gasUsed;

2
libevm/CMakeLists.txt

@ -17,7 +17,7 @@ include_directories(..)
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} gmp) target_link_libraries(${EXECUTABLE} gmp)

2
libevm/ExtVMFace.cpp

@ -25,7 +25,7 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth): ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth):
myAddress(_myAddress), myAddress(_myAddress),
caller(_caller), caller(_caller),
origin(_origin), origin(_origin),

8
libevm/ExtVMFace.h

@ -27,7 +27,7 @@
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
@ -49,7 +49,7 @@ using LogBloom = h512;
struct LogEntry struct LogEntry
{ {
LogEntry() {} LogEntry() {}
LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = (bytes)_r[2]; } LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = (h256Set)_r[1]; data = _r[2].toBytes(); }
LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_ts)), data(std::move(_d)) {} LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(toSet(_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; }
@ -104,7 +104,7 @@ public:
ExtVMFace() = default; ExtVMFace() = default;
/// Full constructor. /// Full constructor.
ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth); ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth);
virtual ~ExtVMFace() = default; virtual ~ExtVMFace() = default;
@ -153,7 +153,7 @@ public:
u256 value; ///< Value (in Wei) that was passed to this address. u256 value; ///< Value (in Wei) that was passed to this address.
u256 gasPrice; ///< Price of gas (that we already paid). u256 gasPrice; ///< Price of gas (that we already paid).
bytesConstRef data; ///< Current input data. bytesConstRef data; ///< Current input data.
bytesConstRef code; ///< Current code that is executing. bytes code; ///< Current code that is executing.
BlockInfo previousBlock; ///< The previous block's information. BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information. BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).

3
libevm/FeeStructure.cpp

@ -37,3 +37,6 @@ u256 const dev::eth::c_callGas = 20;
u256 const dev::eth::c_memoryGas = 1; u256 const dev::eth::c_memoryGas = 1;
u256 const dev::eth::c_txDataGas = 5; u256 const dev::eth::c_txDataGas = 5;
u256 const dev::eth::c_txGas = 500; u256 const dev::eth::c_txGas = 500;
u256 const dev::eth::c_logGas = 32;
u256 const dev::eth::c_logDataGas = 1;
u256 const dev::eth::c_logTopicGas = 32;

3
libevm/FeeStructure.h

@ -40,6 +40,9 @@ extern u256 const c_callGas; ///< Once per CALL operation & message call trans
extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions.
extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions.
extern u256 const c_logGas; ///< Per LOG* operation.
extern u256 const c_logDataGas; ///< Per byte in a LOG* operation's data.
extern u256 const c_logTopicGas; ///< Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
} }
} }

31
libevm/VM.h

@ -24,7 +24,7 @@
#include <unordered_map> #include <unordered_map>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libethcore/CommonEth.h> #include <libethcore/CommonEth.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include "FeeStructure.h" #include "FeeStructure.h"
@ -206,14 +206,15 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
{ {
unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0; unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0;
require(n + 2); require(n + 2);
newTempSize = memNeed(m_stack[m_stack.size() - 1 - n], m_stack[m_stack.size() - 2 - n]); runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2];
newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]);
break; break;
} }
case Instruction::CALL: case Instruction::CALL:
case Instruction::CALLCODE: case Instruction::CALLCODE:
require(7); require(7);
runGas = c_callGas + m_stack[m_stack.size() - 1]; runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1];
newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5])); newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]));
break; break;
@ -701,7 +702,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break; break;
case Instruction::JUMP: case Instruction::JUMP:
nextPC = m_stack.back(); nextPC = m_stack.back();
if (!m_jumpDests.count((unsigned)nextPC)) if (!m_jumpDests.count(nextPC))
BOOST_THROW_EXCEPTION(BadJumpDestination()); BOOST_THROW_EXCEPTION(BadJumpDestination());
m_stack.pop_back(); m_stack.pop_back();
break; break;
@ -709,7 +710,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (m_stack[m_stack.size() - 2]) if (m_stack[m_stack.size() - 2])
{ {
nextPC = m_stack.back(); nextPC = m_stack.back();
if (!m_jumpDests.count((unsigned)nextPC)) if (!m_jumpDests.count(nextPC))
BOOST_THROW_EXCEPTION(BadJumpDestination()); BOOST_THROW_EXCEPTION(BadJumpDestination());
} }
m_stack.pop_back(); m_stack.pop_back();
@ -743,18 +744,38 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;*/ break;*/
case Instruction::LOG0: case Instruction::LOG0:
_ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG1: case Instruction::LOG1:
_ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG2: case Instruction::LOG2:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG3: case Instruction::LOG3:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::LOG4: case Instruction::LOG4:
_ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); _ext.log({m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5], m_stack[m_stack.size() - 6]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2]));
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
m_stack.pop_back();
break; break;
case Instruction::CREATE: case Instruction::CREATE:
{ {

81
liblll/Assembly.cpp → libevmcore/Assembly.cpp

@ -70,7 +70,12 @@ unsigned Assembly::bytesRequired() const
case PushData: case PushData:
case PushSub: case PushSub:
ret += 1 + br; ret += 1 + br;
default:; break;
case NoOptimizeBegin:
case NoOptimizeEnd:
break;
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
} }
if (dev::bytesRequired(ret) <= br) if (dev::bytesRequired(ret) <= br)
return ret; return ret;
@ -140,9 +145,17 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i)
case PushSubSize: case PushSubSize:
_out << " PUSHss[" << hex << h256(i.data()).abridged() << "]"; _out << " PUSHss[" << hex << h256(i.data()).abridged() << "]";
break; break;
case NoOptimizeBegin:
_out << " DoNotOptimze{{";
break;
case NoOptimizeEnd:
_out << " DoNotOptimze}}";
break;
case UndefinedItem: case UndefinedItem:
_out << " ???"; _out << " ???";
default:; break;
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
} }
return _out; return _out;
} }
@ -177,7 +190,14 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const
case PushData: case PushData:
_out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; _out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl;
break; break;
default:; case NoOptimizeBegin:
_out << _prefix << "DoNotOptimze{{" << endl;
break;
case NoOptimizeEnd:
_out << _prefix << "DoNotOptimze}}" << endl;
break;
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
} }
if (m_data.size() || m_subs.size()) if (m_data.size() || m_subs.size())
@ -217,6 +237,12 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b)
return true; return true;
} }
inline bool popCountIncreased(AssemblyItemsConstRef _pre, AssemblyItems const& _post)
{
auto isPop = [](AssemblyItem const& _item) -> bool { return _item.match(AssemblyItem(Instruction::POP)); };
return count_if(begin(_post), end(_post), isPop) > count_if(begin(_pre), end(_pre), isPop);
}
struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; };
#define copt dev::LogOutputStream<OptimiserChannel, true>() #define copt dev::LogOutputStream<OptimiserChannel, true>()
@ -224,6 +250,14 @@ Assembly& Assembly::optimise(bool _enable)
{ {
if (!_enable) if (!_enable)
return *this; return *this;
auto signextend = [](u256 a, u256 b) -> u256
{
if (a >= 31)
return b;
unsigned testBit = unsigned(a) * 8 + 7;
u256 mask = (u256(1) << testBit) - 1;
return boost::multiprecision::bit_test(b, testBit) ? b | ~mask : b & mask;
};
map<Instruction, function<u256(u256, u256)>> c_simple = map<Instruction, function<u256(u256, u256)>> c_simple =
{ {
{ Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} },
@ -232,6 +266,7 @@ Assembly& Assembly::optimise(bool _enable)
{ Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} }, { Instruction::MOD, [](u256 a, u256 b)->u256{return a % b;} },
{ Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} }, { Instruction::SMOD, [](u256 a, u256 b)->u256{return s2u(u2s(a) % u2s(b));} },
{ Instruction::EXP, [](u256 a, u256 b)->u256{return (u256)boost::multiprecision::powm((bigint)a, (bigint)b, bigint(2) << 256);} }, { Instruction::EXP, [](u256 a, u256 b)->u256{return (u256)boost::multiprecision::powm((bigint)a, (bigint)b, bigint(2) << 256);} },
{ Instruction::SIGNEXTEND, signextend },
{ Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} }, { Instruction::LT, [](u256 a, u256 b)->u256{return a < b ? 1 : 0;} },
{ Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} }, { Instruction::GT, [](u256 a, u256 b)->u256{return a > b ? 1 : 0;} },
{ Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} }, { Instruction::SLT, [](u256 a, u256 b)->u256{return u2s(a) < u2s(b) ? 1 : 0;} },
@ -242,6 +277,9 @@ Assembly& Assembly::optimise(bool _enable)
{ {
{ Instruction::ADD, [](u256 a, u256 b)->u256{return a + b;} }, { Instruction::ADD, [](u256 a, u256 b)->u256{return a + b;} },
{ Instruction::MUL, [](u256 a, u256 b)->u256{return a * b;} }, { Instruction::MUL, [](u256 a, u256 b)->u256{return a * b;} },
{ Instruction::AND, [](u256 a, u256 b)->u256{return a & b;} },
{ Instruction::OR, [](u256 a, u256 b)->u256{return a | b;} },
{ Instruction::XOR, [](u256 a, u256 b)->u256{return a ^ b;} },
}; };
std::vector<pair<AssemblyItems, function<AssemblyItems(AssemblyItemsConstRef)>>> rules = std::vector<pair<AssemblyItems, function<AssemblyItems(AssemblyItemsConstRef)>>> rules =
{ {
@ -260,8 +298,23 @@ Assembly& Assembly::optimise(bool _enable)
{ {
rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } }); rules.push_back({ { Push, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[1].data(), m[0].data()) }; } });
rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } }); rules.push_back({ { Push, i.first, Push, i.first }, [&](AssemblyItemsConstRef m) -> AssemblyItems { return { i.second(m[2].data(), m[0].data()), i.first }; } });
rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {}; else return m.toVector(); }});
} }
// jump to next instruction
rules.push_back({ { PushTag, Instruction::JUMP, Tag }, [&](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].m_data == m[2].m_data) return {m[2]}; else return m.toVector(); }});
// pop optimization, do not compute values that are popped again anyway
rules.push_back({ { AssemblyItem(UndefinedItem), Instruction::POP }, [](AssemblyItemsConstRef m) -> AssemblyItems
{
if (m[0].type() != Operation)
return m.toVector();
Instruction instr = Instruction(byte(m[0].data()));
if (Instruction::DUP1 <= instr && instr <= Instruction::DUP16)
return {};
InstructionInfo info = instructionInfo(instr);
if (info.sideEffects || info.additional != 0 || info.ret != 1)
return m.toVector();
return AssemblyItems(info.args, Instruction::POP);
} });
copt << *this; copt << *this;
@ -269,16 +322,21 @@ Assembly& Assembly::optimise(bool _enable)
for (unsigned count = 1; count > 0; total += count) for (unsigned count = 1; count > 0; total += count)
{ {
count = 0; count = 0;
map<u256, unsigned> tags;
for (unsigned i = 0; i < m_items.size(); ++i) for (unsigned i = 0; i < m_items.size(); ++i)
{ {
if (m_items[i].type() == NoOptimizeBegin)
{
while (i < m_items.size() && m_items[i].type() != NoOptimizeEnd)
++i;
continue;
}
for (auto const& r: rules) for (auto const& r: rules)
{ {
auto vr = AssemblyItemsConstRef(&m_items).cropped(i, r.first.size()); auto vr = AssemblyItemsConstRef(&m_items).cropped(i, r.first.size());
if (matches(&r.first, vr)) if (matches(vr, &r.first))
{ {
auto rw = r.second(vr); auto rw = r.second(vr);
if (rw.size() < vr.size()) if (rw.size() < vr.size() || (rw.size() == vr.size() && popCountIncreased(vr, rw)))
{ {
copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes..."; copt << vr << "matches" << AssemblyItemsConstRef(&r.first) << "becomes...";
for (unsigned j = 0; j < vr.size(); ++j) for (unsigned j = 0; j < vr.size(); ++j)
@ -297,6 +355,8 @@ Assembly& Assembly::optimise(bool _enable)
bool o = false; bool o = false;
while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag) while (m_items.size() > i + 1 && m_items[i + 1].type() != Tag)
{ {
if (m_items[i + 1].type() == NoOptimizeBegin)
break;
m_items.erase(m_items.begin() + i + 1); m_items.erase(m_items.begin() + i + 1);
o = true; o = true;
} }
@ -308,6 +368,7 @@ Assembly& Assembly::optimise(bool _enable)
} }
} }
map<u256, unsigned> tags;
for (unsigned i = 0; i < m_items.size(); ++i) for (unsigned i = 0; i < m_items.size(); ++i)
if (m_items[i].type() == Tag) if (m_items[i].type() == Tag)
tags.insert(make_pair(m_items[i].data(), i)); tags.insert(make_pair(m_items[i].data(), i));
@ -416,7 +477,11 @@ bytes Assembly::assemble() const
tagPos[(unsigned)i.m_data] = ret.size(); tagPos[(unsigned)i.m_data] = ret.size();
ret.push_back((byte)Instruction::JUMPDEST); ret.push_back((byte)Instruction::JUMPDEST);
break; break;
default:; case NoOptimizeBegin:
case NoOptimizeEnd:
break;
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
} }
for (auto const& i: tagRef) for (auto const& i: tagRef)

4
liblll/Assembly.h → libevmcore/Assembly.h

@ -24,7 +24,7 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include "Exceptions.h" #include "Exceptions.h"
namespace dev namespace dev
@ -32,7 +32,7 @@ namespace dev
namespace eth namespace eth
{ {
enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData }; enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData, NoOptimizeBegin, NoOptimizeEnd };
class Assembly; class Assembly;

2
libevmface/CMakeLists.txt → libevmcore/CMakeLists.txt

@ -4,7 +4,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB")
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
set(EXECUTABLE evmface) set(EXECUTABLE evmcore)
file(GLOB HEADERS "*.h") file(GLOB HEADERS "*.h")
if(ETH_STATIC) if(ETH_STATIC)

36
libevmcore/Exceptions.h

@ -0,0 +1,36 @@
/*
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 Exceptions.h
* @author Christian <c@ethdev.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Exceptions.h>
namespace dev
{
namespace eth
{
struct AssemblyException: virtual Exception {};
struct InvalidDeposit: virtual AssemblyException {};
struct InvalidOpcode: virtual AssemblyException {};
}
}

337
libevmcore/Instruction.cpp

@ -0,0 +1,337 @@
/*
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 Instruction.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Instruction.h"
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
const std::map<std::string, Instruction> dev::eth::c_instructions =
{
{ "STOP", Instruction::STOP },
{ "ADD", Instruction::ADD },
{ "SUB", Instruction::SUB },
{ "MUL", Instruction::MUL },
{ "DIV", Instruction::DIV },
{ "SDIV", Instruction::SDIV },
{ "MOD", Instruction::MOD },
{ "SMOD", Instruction::SMOD },
{ "EXP", Instruction::EXP },
{ "BNOT", Instruction::NOT },
{ "LT", Instruction::LT },
{ "GT", Instruction::GT },
{ "SLT", Instruction::SLT },
{ "SGT", Instruction::SGT },
{ "EQ", Instruction::EQ },
{ "NOT", Instruction::ISZERO },
{ "AND", Instruction::AND },
{ "OR", Instruction::OR },
{ "XOR", Instruction::XOR },
{ "BYTE", Instruction::BYTE },
{ "ADDMOD", Instruction::ADDMOD },
{ "MULMOD", Instruction::MULMOD },
{ "SIGNEXTEND", Instruction::SIGNEXTEND },
{ "SHA3", Instruction::SHA3 },
{ "ADDRESS", Instruction::ADDRESS },
{ "BALANCE", Instruction::BALANCE },
{ "ORIGIN", Instruction::ORIGIN },
{ "CALLER", Instruction::CALLER },
{ "CALLVALUE", Instruction::CALLVALUE },
{ "CALLDATALOAD", Instruction::CALLDATALOAD },
{ "CALLDATASIZE", Instruction::CALLDATASIZE },
{ "CALLDATACOPY", Instruction::CALLDATACOPY },
{ "CODESIZE", Instruction::CODESIZE },
{ "CODECOPY", Instruction::CODECOPY },
{ "GASPRICE", Instruction::GASPRICE },
{ "EXTCODESIZE", Instruction::EXTCODESIZE },
{ "EXTCODECOPY", Instruction::EXTCODECOPY },
{ "PREVHASH", Instruction::PREVHASH },
{ "COINBASE", Instruction::COINBASE },
{ "TIMESTAMP", Instruction::TIMESTAMP },
{ "NUMBER", Instruction::NUMBER },
{ "DIFFICULTY", Instruction::DIFFICULTY },
{ "GASLIMIT", Instruction::GASLIMIT },
{ "POP", Instruction::POP },
{ "MLOAD", Instruction::MLOAD },
{ "MSTORE", Instruction::MSTORE },
{ "MSTORE8", Instruction::MSTORE8 },
{ "SLOAD", Instruction::SLOAD },
{ "SSTORE", Instruction::SSTORE },
{ "JUMP", Instruction::JUMP },
{ "JUMPI", Instruction::JUMPI },
{ "PC", Instruction::PC },
{ "MSIZE", Instruction::MSIZE },
{ "GAS", Instruction::GAS },
{ "JUMPDEST", Instruction::JUMPDEST },
{ "PUSH1", Instruction::PUSH1 },
{ "PUSH2", Instruction::PUSH2 },
{ "PUSH3", Instruction::PUSH3 },
{ "PUSH4", Instruction::PUSH4 },
{ "PUSH5", Instruction::PUSH5 },
{ "PUSH6", Instruction::PUSH6 },
{ "PUSH7", Instruction::PUSH7 },
{ "PUSH8", Instruction::PUSH8 },
{ "PUSH9", Instruction::PUSH9 },
{ "PUSH10", Instruction::PUSH10 },
{ "PUSH11", Instruction::PUSH11 },
{ "PUSH12", Instruction::PUSH12 },
{ "PUSH13", Instruction::PUSH13 },
{ "PUSH14", Instruction::PUSH14 },
{ "PUSH15", Instruction::PUSH15 },
{ "PUSH16", Instruction::PUSH16 },
{ "PUSH17", Instruction::PUSH17 },
{ "PUSH18", Instruction::PUSH18 },
{ "PUSH19", Instruction::PUSH19 },
{ "PUSH20", Instruction::PUSH20 },
{ "PUSH21", Instruction::PUSH21 },
{ "PUSH22", Instruction::PUSH22 },
{ "PUSH23", Instruction::PUSH23 },
{ "PUSH24", Instruction::PUSH24 },
{ "PUSH25", Instruction::PUSH25 },
{ "PUSH26", Instruction::PUSH26 },
{ "PUSH27", Instruction::PUSH27 },
{ "PUSH28", Instruction::PUSH28 },
{ "PUSH29", Instruction::PUSH29 },
{ "PUSH30", Instruction::PUSH30 },
{ "PUSH31", Instruction::PUSH31 },
{ "PUSH32", Instruction::PUSH32 },
{ "DUP1", Instruction::DUP1 },
{ "DUP2", Instruction::DUP2 },
{ "DUP3", Instruction::DUP3 },
{ "DUP4", Instruction::DUP4 },
{ "DUP5", Instruction::DUP5 },
{ "DUP6", Instruction::DUP6 },
{ "DUP7", Instruction::DUP7 },
{ "DUP8", Instruction::DUP8 },
{ "DUP9", Instruction::DUP9 },
{ "DUP10", Instruction::DUP10 },
{ "DUP11", Instruction::DUP11 },
{ "DUP12", Instruction::DUP12 },
{ "DUP13", Instruction::DUP13 },
{ "DUP14", Instruction::DUP14 },
{ "DUP15", Instruction::DUP15 },
{ "DUP16", Instruction::DUP16 },
{ "SWAP1", Instruction::SWAP1 },
{ "SWAP2", Instruction::SWAP2 },
{ "SWAP3", Instruction::SWAP3 },
{ "SWAP4", Instruction::SWAP4 },
{ "SWAP5", Instruction::SWAP5 },
{ "SWAP6", Instruction::SWAP6 },
{ "SWAP7", Instruction::SWAP7 },
{ "SWAP8", Instruction::SWAP8 },
{ "SWAP9", Instruction::SWAP9 },
{ "SWAP10", Instruction::SWAP10 },
{ "SWAP11", Instruction::SWAP11 },
{ "SWAP12", Instruction::SWAP12 },
{ "SWAP13", Instruction::SWAP13 },
{ "SWAP14", Instruction::SWAP14 },
{ "SWAP15", Instruction::SWAP15 },
{ "SWAP16", Instruction::SWAP16 },
{ "LOG0", Instruction::LOG0 },
{ "LOG1", Instruction::LOG1 },
{ "LOG2", Instruction::LOG2 },
{ "LOG3", Instruction::LOG3 },
{ "LOG4", Instruction::LOG4 },
{ "CREATE", Instruction::CREATE },
{ "CALL", Instruction::CALL },
{ "CALLCODE", Instruction::CALLCODE },
{ "RETURN", Instruction::RETURN },
{ "SUICIDE", Instruction::SUICIDE }
};
static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ // Add, Args, Ret, SideEffects
{ Instruction::STOP, { "STOP", 0, 0, 0, true } },
{ Instruction::ADD, { "ADD", 0, 2, 1, false } },
{ Instruction::SUB, { "SUB", 0, 2, 1, false } },
{ Instruction::MUL, { "MUL", 0, 2, 1, false } },
{ Instruction::DIV, { "DIV", 0, 2, 1, false } },
{ Instruction::SDIV, { "SDIV", 0, 2, 1, false } },
{ Instruction::MOD, { "MOD", 0, 2, 1, false } },
{ Instruction::SMOD, { "SMOD", 0, 2, 1, false } },
{ Instruction::EXP, { "EXP", 0, 2, 1, false } },
{ Instruction::NOT, { "NOT", 0, 1, 1, false } },
{ Instruction::LT, { "LT", 0, 2, 1, false } },
{ Instruction::GT, { "GT", 0, 2, 1, false } },
{ Instruction::SLT, { "SLT", 0, 2, 1, false } },
{ Instruction::SGT, { "SGT", 0, 2, 1, false } },
{ Instruction::EQ, { "EQ", 0, 2, 1, false } },
{ Instruction::ISZERO, { "ISZERO", 0, 1, 1, false } },
{ Instruction::AND, { "AND", 0, 2, 1, false } },
{ Instruction::OR, { "OR", 0, 2, 1, false } },
{ Instruction::XOR, { "XOR", 0, 2, 1, false } },
{ Instruction::BYTE, { "BYTE", 0, 2, 1, false } },
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1, false } },
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1, false } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1, false } },
{ Instruction::SHA3, { "SHA3", 0, 2, 1, false } },
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1, false } },
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1, false } },
{ Instruction::ORIGIN, { "ORIGIN", 0, 0, 1, false } },
{ Instruction::CALLER, { "CALLER", 0, 0, 1, false } },
{ Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1, false } },
{ Instruction::CALLDATALOAD,{ "CALLDATALOAD", 0, 1, 1, false } },
{ Instruction::CALLDATASIZE,{ "CALLDATASIZE", 0, 0, 1, false } },
{ Instruction::CALLDATACOPY,{ "CALLDATACOPY", 0, 3, 0, true } },
{ Instruction::CODESIZE, { "CODESIZE", 0, 0, 1, false } },
{ Instruction::CODECOPY, { "CODECOPY", 0, 3, 0, true } },
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false } },
{ Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false } },
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true } },
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1, false } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false } },
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1, false } },
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1, false } },
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false } },
{ Instruction::POP, { "POP", 0, 1, 0, false } },
{ Instruction::MLOAD, { "MLOAD", 0, 1, 1, false } },
{ Instruction::MSTORE, { "MSTORE", 0, 2, 0, true } },
{ Instruction::MSTORE8, { "MSTORE8", 0, 2, 0, true } },
{ Instruction::SLOAD, { "SLOAD", 0, 1, 1, false } },
{ Instruction::SSTORE, { "SSTORE", 0, 2, 0, true } },
{ Instruction::JUMP, { "JUMP", 0, 1, 0, true } },
{ Instruction::JUMPI, { "JUMPI", 0, 2, 0, true } },
{ Instruction::PC, { "PC", 0, 0, 1, false } },
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1, false } },
{ Instruction::GAS, { "GAS", 0, 0, 1, false } },
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0, true } },
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1, false } },
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1, false } },
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1, false } },
{ Instruction::PUSH4, { "PUSH4", 4, 0, 1, false } },
{ Instruction::PUSH5, { "PUSH5", 5, 0, 1, false } },
{ Instruction::PUSH6, { "PUSH6", 6, 0, 1, false } },
{ Instruction::PUSH7, { "PUSH7", 7, 0, 1, false } },
{ Instruction::PUSH8, { "PUSH8", 8, 0, 1, false } },
{ Instruction::PUSH9, { "PUSH9", 9, 0, 1, false } },
{ Instruction::PUSH10, { "PUSH10", 10, 0, 1, false } },
{ Instruction::PUSH11, { "PUSH11", 11, 0, 1, false } },
{ Instruction::PUSH12, { "PUSH12", 12, 0, 1, false } },
{ Instruction::PUSH13, { "PUSH13", 13, 0, 1, false } },
{ Instruction::PUSH14, { "PUSH14", 14, 0, 1, false } },
{ Instruction::PUSH15, { "PUSH15", 15, 0, 1, false } },
{ Instruction::PUSH16, { "PUSH16", 16, 0, 1, false } },
{ Instruction::PUSH17, { "PUSH17", 17, 0, 1, false } },
{ Instruction::PUSH18, { "PUSH18", 18, 0, 1, false } },
{ Instruction::PUSH19, { "PUSH19", 19, 0, 1, false } },
{ Instruction::PUSH20, { "PUSH20", 20, 0, 1, false } },
{ Instruction::PUSH21, { "PUSH21", 21, 0, 1, false } },
{ Instruction::PUSH22, { "PUSH22", 22, 0, 1, false } },
{ Instruction::PUSH23, { "PUSH23", 23, 0, 1, false } },
{ Instruction::PUSH24, { "PUSH24", 24, 0, 1, false } },
{ Instruction::PUSH25, { "PUSH25", 25, 0, 1, false } },
{ Instruction::PUSH26, { "PUSH26", 26, 0, 1, false } },
{ Instruction::PUSH27, { "PUSH27", 27, 0, 1, false } },
{ Instruction::PUSH28, { "PUSH28", 28, 0, 1, false } },
{ Instruction::PUSH29, { "PUSH29", 29, 0, 1, false } },
{ Instruction::PUSH30, { "PUSH30", 30, 0, 1, false } },
{ Instruction::PUSH31, { "PUSH31", 31, 0, 1, false } },
{ Instruction::PUSH32, { "PUSH32", 32, 0, 1, false } },
{ Instruction::DUP1, { "DUP1", 0, 1, 2, false } },
{ Instruction::DUP2, { "DUP2", 0, 2, 3, false } },
{ Instruction::DUP3, { "DUP3", 0, 3, 4, false } },
{ Instruction::DUP4, { "DUP4", 0, 4, 5, false } },
{ Instruction::DUP5, { "DUP5", 0, 5, 6, false } },
{ Instruction::DUP6, { "DUP6", 0, 6, 7, false } },
{ Instruction::DUP7, { "DUP7", 0, 7, 8, false } },
{ Instruction::DUP8, { "DUP8", 0, 8, 9, false } },
{ Instruction::DUP9, { "DUP9", 0, 9, 10, false } },
{ Instruction::DUP10, { "DUP10", 0, 10, 11, false } },
{ Instruction::DUP11, { "DUP11", 0, 11, 12, false } },
{ Instruction::DUP12, { "DUP12", 0, 12, 13, false } },
{ Instruction::DUP13, { "DUP13", 0, 13, 14, false } },
{ Instruction::DUP14, { "DUP14", 0, 14, 15, false } },
{ Instruction::DUP15, { "DUP15", 0, 15, 16, false } },
{ Instruction::DUP16, { "DUP16", 0, 16, 17, false } },
{ Instruction::SWAP1, { "SWAP1", 0, 2, 2, false } },
{ Instruction::SWAP2, { "SWAP2", 0, 3, 3, false } },
{ Instruction::SWAP3, { "SWAP3", 0, 4, 4, false } },
{ Instruction::SWAP4, { "SWAP4", 0, 5, 5, false } },
{ Instruction::SWAP5, { "SWAP5", 0, 6, 6, false } },
{ Instruction::SWAP6, { "SWAP6", 0, 7, 7, false } },
{ Instruction::SWAP7, { "SWAP7", 0, 8, 8, false } },
{ Instruction::SWAP8, { "SWAP8", 0, 9, 9, false } },
{ Instruction::SWAP9, { "SWAP9", 0, 10, 10, false } },
{ Instruction::SWAP10, { "SWAP10", 0, 11, 11, false } },
{ Instruction::SWAP11, { "SWAP11", 0, 12, 12, false } },
{ Instruction::SWAP12, { "SWAP12", 0, 13, 13, false } },
{ Instruction::SWAP13, { "SWAP13", 0, 14, 14, false } },
{ Instruction::SWAP14, { "SWAP14", 0, 15, 15, false } },
{ Instruction::SWAP15, { "SWAP15", 0, 16, 16, false } },
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17, false } },
{ Instruction::LOG0, { "LOG0", 0, 2, 0, true } },
{ Instruction::LOG1, { "LOG1", 0, 3, 0, true } },
{ Instruction::LOG2, { "LOG2", 0, 4, 0, true } },
{ Instruction::LOG3, { "LOG3", 0, 5, 0, true } },
{ Instruction::LOG4, { "LOG4", 0, 6, 0, true } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1, true } },
{ Instruction::CALL, { "CALL", 0, 7, 1, true } },
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1, true } },
{ Instruction::RETURN, { "RETURN", 0, 2, 0, true } },
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0, true } }
};
string dev::eth::disassemble(bytes const& _mem)
{
stringstream ret;
unsigned numerics = 0;
for (auto it = _mem.begin(); it != _mem.end(); ++it)
{
byte n = *it;
auto iit = c_instructionInfo.find((Instruction)n);
if (numerics || iit == c_instructionInfo.end() || (byte)iit->first != n) // not an instruction or expecting an argument...
{
if (numerics)
numerics--;
ret << "0x" << hex << (int)n << " ";
}
else
{
auto const& ii = iit->second;
ret << ii.name << " ";
numerics = ii.additional;
}
}
return ret.str();
}
InstructionInfo dev::eth::instructionInfo(Instruction _inst)
{
try
{
return c_instructionInfo.at(_inst);
}
catch (...)
{
cwarn << "<INVALID_INSTRUCTION: " << toString((unsigned)_inst) << ">\n" << boost::current_exception_diagnostic_information();
return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0, false});
}
}
bool dev::eth::isValidInstruction(Instruction _inst)
{
return !!c_instructionInfo.count(_inst);
}

8
libevmface/Instruction.h → libevmcore/Instruction.h

@ -22,18 +22,13 @@
#pragma once #pragma once
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Exceptions.h> #include <libevmcore/Exceptions.h>
namespace boost { namespace spirit { class utree; } }
namespace sp = boost::spirit;
namespace dev namespace dev
{ {
namespace eth namespace eth
{ {
struct InvalidOpcode: virtual Exception {};
/// Virtual machine bytecode instruction. /// Virtual machine bytecode instruction.
enum class Instruction: uint8_t enum class Instruction: uint8_t
{ {
@ -209,6 +204,7 @@ struct InstructionInfo
int additional; ///< Additional items required in memory for this instructions (only for PUSH). int additional; ///< Additional items required in memory for this instructions (only for PUSH).
int args; ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack). int args; ///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack).
int ret; ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed. int ret; ///< Number of items placed (back) on the stack by this instruction, assuming args items were removed.
bool sideEffects; ///< false if the only effect on the execution environment (apart from gas usage) is a change to a topmost segment of the stack
}; };
/// Information on all the instructions. /// Information on all the instructions.

337
libevmface/Instruction.cpp

@ -1,337 +0,0 @@
/*
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 Instruction.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Instruction.h"
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
const std::map<std::string, Instruction> dev::eth::c_instructions =
{
{ "STOP", Instruction::STOP },
{ "ADD", Instruction::ADD },
{ "SUB", Instruction::SUB },
{ "MUL", Instruction::MUL },
{ "DIV", Instruction::DIV },
{ "SDIV", Instruction::SDIV },
{ "MOD", Instruction::MOD },
{ "SMOD", Instruction::SMOD },
{ "EXP", Instruction::EXP },
{ "BNOT", Instruction::NOT },
{ "LT", Instruction::LT },
{ "GT", Instruction::GT },
{ "SLT", Instruction::SLT },
{ "SGT", Instruction::SGT },
{ "EQ", Instruction::EQ },
{ "NOT", Instruction::ISZERO },
{ "AND", Instruction::AND },
{ "OR", Instruction::OR },
{ "XOR", Instruction::XOR },
{ "BYTE", Instruction::BYTE },
{ "ADDMOD", Instruction::ADDMOD },
{ "MULMOD", Instruction::MULMOD },
{ "SIGNEXTEND", Instruction::SIGNEXTEND },
{ "SHA3", Instruction::SHA3 },
{ "ADDRESS", Instruction::ADDRESS },
{ "BALANCE", Instruction::BALANCE },
{ "ORIGIN", Instruction::ORIGIN },
{ "CALLER", Instruction::CALLER },
{ "CALLVALUE", Instruction::CALLVALUE },
{ "CALLDATALOAD", Instruction::CALLDATALOAD },
{ "CALLDATASIZE", Instruction::CALLDATASIZE },
{ "CALLDATACOPY", Instruction::CALLDATACOPY },
{ "CODESIZE", Instruction::CODESIZE },
{ "CODECOPY", Instruction::CODECOPY },
{ "GASPRICE", Instruction::GASPRICE },
{ "EXTCODESIZE", Instruction::EXTCODESIZE },
{ "EXTCODECOPY", Instruction::EXTCODECOPY },
{ "PREVHASH", Instruction::PREVHASH },
{ "COINBASE", Instruction::COINBASE },
{ "TIMESTAMP", Instruction::TIMESTAMP },
{ "NUMBER", Instruction::NUMBER },
{ "DIFFICULTY", Instruction::DIFFICULTY },
{ "GASLIMIT", Instruction::GASLIMIT },
{ "POP", Instruction::POP },
{ "MLOAD", Instruction::MLOAD },
{ "MSTORE", Instruction::MSTORE },
{ "MSTORE8", Instruction::MSTORE8 },
{ "SLOAD", Instruction::SLOAD },
{ "SSTORE", Instruction::SSTORE },
{ "JUMP", Instruction::JUMP },
{ "JUMPI", Instruction::JUMPI },
{ "PC", Instruction::PC },
{ "MSIZE", Instruction::MSIZE },
{ "GAS", Instruction::GAS },
{ "JUMPDEST", Instruction::JUMPDEST },
{ "PUSH1", Instruction::PUSH1 },
{ "PUSH2", Instruction::PUSH2 },
{ "PUSH3", Instruction::PUSH3 },
{ "PUSH4", Instruction::PUSH4 },
{ "PUSH5", Instruction::PUSH5 },
{ "PUSH6", Instruction::PUSH6 },
{ "PUSH7", Instruction::PUSH7 },
{ "PUSH8", Instruction::PUSH8 },
{ "PUSH9", Instruction::PUSH9 },
{ "PUSH10", Instruction::PUSH10 },
{ "PUSH11", Instruction::PUSH11 },
{ "PUSH12", Instruction::PUSH12 },
{ "PUSH13", Instruction::PUSH13 },
{ "PUSH14", Instruction::PUSH14 },
{ "PUSH15", Instruction::PUSH15 },
{ "PUSH16", Instruction::PUSH16 },
{ "PUSH17", Instruction::PUSH17 },
{ "PUSH18", Instruction::PUSH18 },
{ "PUSH19", Instruction::PUSH19 },
{ "PUSH20", Instruction::PUSH20 },
{ "PUSH21", Instruction::PUSH21 },
{ "PUSH22", Instruction::PUSH22 },
{ "PUSH23", Instruction::PUSH23 },
{ "PUSH24", Instruction::PUSH24 },
{ "PUSH25", Instruction::PUSH25 },
{ "PUSH26", Instruction::PUSH26 },
{ "PUSH27", Instruction::PUSH27 },
{ "PUSH28", Instruction::PUSH28 },
{ "PUSH29", Instruction::PUSH29 },
{ "PUSH30", Instruction::PUSH30 },
{ "PUSH31", Instruction::PUSH31 },
{ "PUSH32", Instruction::PUSH32 },
{ "DUP1", Instruction::DUP1 },
{ "DUP2", Instruction::DUP2 },
{ "DUP3", Instruction::DUP3 },
{ "DUP4", Instruction::DUP4 },
{ "DUP5", Instruction::DUP5 },
{ "DUP6", Instruction::DUP6 },
{ "DUP7", Instruction::DUP7 },
{ "DUP8", Instruction::DUP8 },
{ "DUP9", Instruction::DUP9 },
{ "DUP10", Instruction::DUP10 },
{ "DUP11", Instruction::DUP11 },
{ "DUP12", Instruction::DUP12 },
{ "DUP13", Instruction::DUP13 },
{ "DUP14", Instruction::DUP14 },
{ "DUP15", Instruction::DUP15 },
{ "DUP16", Instruction::DUP16 },
{ "SWAP1", Instruction::SWAP1 },
{ "SWAP2", Instruction::SWAP2 },
{ "SWAP3", Instruction::SWAP3 },
{ "SWAP4", Instruction::SWAP4 },
{ "SWAP5", Instruction::SWAP5 },
{ "SWAP6", Instruction::SWAP6 },
{ "SWAP7", Instruction::SWAP7 },
{ "SWAP8", Instruction::SWAP8 },
{ "SWAP9", Instruction::SWAP9 },
{ "SWAP10", Instruction::SWAP10 },
{ "SWAP11", Instruction::SWAP11 },
{ "SWAP12", Instruction::SWAP12 },
{ "SWAP13", Instruction::SWAP13 },
{ "SWAP14", Instruction::SWAP14 },
{ "SWAP15", Instruction::SWAP15 },
{ "SWAP16", Instruction::SWAP16 },
{ "LOG0", Instruction::LOG0 },
{ "LOG1", Instruction::LOG1 },
{ "LOG2", Instruction::LOG2 },
{ "LOG3", Instruction::LOG3 },
{ "LOG4", Instruction::LOG4 },
{ "CREATE", Instruction::CREATE },
{ "CALL", Instruction::CALL },
{ "CALLCODE", Instruction::CALLCODE },
{ "RETURN", Instruction::RETURN },
{ "SUICIDE", Instruction::SUICIDE }
};
static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ // Add, Args, Ret
{ Instruction::STOP, { "STOP", 0, 0, 0 } },
{ Instruction::ADD, { "ADD", 0, 2, 1 } },
{ Instruction::SUB, { "SUB", 0, 2, 1 } },
{ Instruction::MUL, { "MUL", 0, 2, 1 } },
{ Instruction::DIV, { "DIV", 0, 2, 1 } },
{ Instruction::SDIV, { "SDIV", 0, 2, 1 } },
{ Instruction::MOD, { "MOD", 0, 2, 1 } },
{ Instruction::SMOD, { "SMOD", 0, 2, 1 } },
{ Instruction::EXP, { "EXP", 0, 2, 1 } },
{ Instruction::NOT, { "BNOT", 0, 1, 1 } },
{ Instruction::LT, { "LT", 0, 2, 1 } },
{ Instruction::GT, { "GT", 0, 2, 1 } },
{ Instruction::SLT, { "SLT", 0, 2, 1 } },
{ Instruction::SGT, { "SGT", 0, 2, 1 } },
{ Instruction::EQ, { "EQ", 0, 2, 1 } },
{ Instruction::ISZERO, { "NOT", 0, 1, 1 } },
{ Instruction::AND, { "AND", 0, 2, 1 } },
{ Instruction::OR, { "OR", 0, 2, 1 } },
{ Instruction::XOR, { "XOR", 0, 2, 1 } },
{ Instruction::BYTE, { "BYTE", 0, 2, 1 } },
{ Instruction::ADDMOD, { "ADDMOD", 0, 3, 1 } },
{ Instruction::MULMOD, { "MULMOD", 0, 3, 1 } },
{ Instruction::SIGNEXTEND, { "SIGNEXTEND", 0, 2, 1 } },
{ Instruction::SHA3, { "SHA3", 0, 2, 1 } },
{ Instruction::ADDRESS, { "ADDRESS", 0, 0, 1 } },
{ Instruction::BALANCE, { "BALANCE", 0, 1, 1 } },
{ Instruction::ORIGIN, { "ORIGIN", 0, 0, 1 } },
{ Instruction::CALLER, { "CALLER", 0, 0, 1 } },
{ Instruction::CALLVALUE, { "CALLVALUE", 0, 0, 1 } },
{ Instruction::CALLDATALOAD,{ "CALLDATALOAD", 0, 1, 1 } },
{ Instruction::CALLDATASIZE,{ "CALLDATASIZE", 0, 0, 1 } },
{ Instruction::CALLDATACOPY,{ "CALLDATACOPY", 0, 3, 0 } },
{ Instruction::CODESIZE, { "CODESIZE", 0, 0, 1 } },
{ Instruction::CODECOPY, { "CODECOPY", 0, 3, 0 } },
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1 } },
{ Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1 } },
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0 } },
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1 } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1 } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1 } },
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1 } },
{ Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1 } },
{ Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1 } },
{ Instruction::POP, { "POP", 0, 1, 0 } },
{ Instruction::MLOAD, { "MLOAD", 0, 1, 1 } },
{ Instruction::MSTORE, { "MSTORE", 0, 2, 0 } },
{ Instruction::MSTORE8, { "MSTORE8", 0, 2, 0 } },
{ Instruction::SLOAD, { "SLOAD", 0, 1, 1 } },
{ Instruction::SSTORE, { "SSTORE", 0, 2, 0 } },
{ Instruction::JUMP, { "JUMP", 0, 1, 0 } },
{ Instruction::JUMPI, { "JUMPI", 0, 2, 0 } },
{ Instruction::PC, { "PC", 0, 0, 1 } },
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1 } },
{ Instruction::GAS, { "GAS", 0, 0, 1 } },
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0 } },
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1 } },
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1 } },
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1 } },
{ Instruction::PUSH4, { "PUSH4", 4, 0, 1 } },
{ Instruction::PUSH5, { "PUSH5", 5, 0, 1 } },
{ Instruction::PUSH6, { "PUSH6", 6, 0, 1 } },
{ Instruction::PUSH7, { "PUSH7", 7, 0, 1 } },
{ Instruction::PUSH8, { "PUSH8", 8, 0, 1 } },
{ Instruction::PUSH9, { "PUSH9", 9, 0, 1 } },
{ Instruction::PUSH10, { "PUSH10", 10, 0, 1 } },
{ Instruction::PUSH11, { "PUSH11", 11, 0, 1 } },
{ Instruction::PUSH12, { "PUSH12", 12, 0, 1 } },
{ Instruction::PUSH13, { "PUSH13", 13, 0, 1 } },
{ Instruction::PUSH14, { "PUSH14", 14, 0, 1 } },
{ Instruction::PUSH15, { "PUSH15", 15, 0, 1 } },
{ Instruction::PUSH16, { "PUSH16", 16, 0, 1 } },
{ Instruction::PUSH17, { "PUSH17", 17, 0, 1 } },
{ Instruction::PUSH18, { "PUSH18", 18, 0, 1 } },
{ Instruction::PUSH19, { "PUSH19", 19, 0, 1 } },
{ Instruction::PUSH20, { "PUSH20", 20, 0, 1 } },
{ Instruction::PUSH21, { "PUSH21", 21, 0, 1 } },
{ Instruction::PUSH22, { "PUSH22", 22, 0, 1 } },
{ Instruction::PUSH23, { "PUSH23", 23, 0, 1 } },
{ Instruction::PUSH24, { "PUSH24", 24, 0, 1 } },
{ Instruction::PUSH25, { "PUSH25", 25, 0, 1 } },
{ Instruction::PUSH26, { "PUSH26", 26, 0, 1 } },
{ Instruction::PUSH27, { "PUSH27", 27, 0, 1 } },
{ Instruction::PUSH28, { "PUSH28", 28, 0, 1 } },
{ Instruction::PUSH29, { "PUSH29", 29, 0, 1 } },
{ Instruction::PUSH30, { "PUSH30", 30, 0, 1 } },
{ Instruction::PUSH31, { "PUSH31", 31, 0, 1 } },
{ Instruction::PUSH32, { "PUSH32", 32, 0, 1 } },
{ Instruction::DUP1, { "DUP1", 0, 1, 2 } },
{ Instruction::DUP2, { "DUP2", 0, 2, 3 } },
{ Instruction::DUP3, { "DUP3", 0, 3, 4 } },
{ Instruction::DUP4, { "DUP4", 0, 4, 5 } },
{ Instruction::DUP5, { "DUP5", 0, 5, 6 } },
{ Instruction::DUP6, { "DUP6", 0, 6, 7 } },
{ Instruction::DUP7, { "DUP7", 0, 7, 8 } },
{ Instruction::DUP8, { "DUP8", 0, 8, 9 } },
{ Instruction::DUP9, { "DUP9", 0, 9, 10 } },
{ Instruction::DUP10, { "DUP10", 0, 10, 11 } },
{ Instruction::DUP11, { "DUP11", 0, 11, 12 } },
{ Instruction::DUP12, { "DUP12", 0, 12, 13 } },
{ Instruction::DUP13, { "DUP13", 0, 13, 14 } },
{ Instruction::DUP14, { "DUP14", 0, 14, 15 } },
{ Instruction::DUP15, { "DUP15", 0, 15, 16 } },
{ Instruction::DUP16, { "DUP16", 0, 16, 17 } },
{ Instruction::SWAP1, { "SWAP1", 0, 2, 2 } },
{ Instruction::SWAP2, { "SWAP2", 0, 3, 3 } },
{ Instruction::SWAP3, { "SWAP3", 0, 4, 4 } },
{ Instruction::SWAP4, { "SWAP4", 0, 5, 5 } },
{ Instruction::SWAP5, { "SWAP5", 0, 6, 6 } },
{ Instruction::SWAP6, { "SWAP6", 0, 7, 7 } },
{ Instruction::SWAP7, { "SWAP7", 0, 8, 8 } },
{ Instruction::SWAP8, { "SWAP8", 0, 9, 9 } },
{ Instruction::SWAP9, { "SWAP9", 0, 10, 10 } },
{ Instruction::SWAP10, { "SWAP10", 0, 11, 11 } },
{ Instruction::SWAP11, { "SWAP11", 0, 12, 12 } },
{ Instruction::SWAP12, { "SWAP12", 0, 13, 13 } },
{ Instruction::SWAP13, { "SWAP13", 0, 14, 14 } },
{ Instruction::SWAP14, { "SWAP14", 0, 15, 15 } },
{ Instruction::SWAP15, { "SWAP15", 0, 16, 16 } },
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17 } },
{ Instruction::LOG0, { "LOG0", 0, 1, 0 } },
{ Instruction::LOG1, { "LOG1", 0, 2, 0 } },
{ Instruction::LOG2, { "LOG2", 0, 3, 0 } },
{ Instruction::LOG3, { "LOG3", 0, 4, 0 } },
{ Instruction::LOG4, { "LOG4", 0, 5, 0 } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } },
{ Instruction::CALL, { "CALL", 0, 7, 1 } },
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } },
{ Instruction::RETURN, { "RETURN", 0, 2, 0 } },
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} }
};
string dev::eth::disassemble(bytes const& _mem)
{
stringstream ret;
unsigned numerics = 0;
for (auto it = _mem.begin(); it != _mem.end(); ++it)
{
byte n = *it;
auto iit = c_instructionInfo.find((Instruction)n);
if (numerics || iit == c_instructionInfo.end() || (byte)iit->first != n) // not an instruction or expecting an argument...
{
if (numerics)
numerics--;
ret << "0x" << hex << (int)n << " ";
}
else
{
auto const& ii = iit->second;
ret << ii.name << " ";
numerics = ii.additional;
}
}
return ret.str();
}
InstructionInfo dev::eth::instructionInfo(Instruction _inst)
{
try
{
return c_instructionInfo.at(_inst);
}
catch (...)
{
cwarn << "<INVALID_INSTRUCTION: " << toString((unsigned)_inst) << ">\n" << boost::current_exception_diagnostic_information();
return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0});
}
}
bool dev::eth::isValidInstruction(Instruction _inst)
{
return !!c_instructionInfo.count(_inst);
}

109
libjsqrc/main.js

@ -2,19 +2,19 @@
This file is part of ethereum.js. This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ethereum.js is distributed in the hope that it will be useful, ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file ethereum.js /** @file main.js
* @authors: * @authors:
* Marek Kotewicz <marek@ethdev.com> * Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014
@ -66,82 +66,83 @@
var ethMethods = function () { var ethMethods = function () {
var blockCall = function (args) { var blockCall = function (args) {
return typeof args[0] === "string" ? "blockByHash" : "blockByNumber"; return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber";
}; };
var transactionCall = function (args) { var transactionCall = function (args) {
return typeof args[0] === "string" ? 'transactionByHash' : 'transactionByNumber'; return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber';
}; };
var uncleCall = function (args) { var uncleCall = function (args) {
return typeof args[0] === "string" ? 'uncleByHash' : 'uncleByNumber'; return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber';
}; };
var methods = [ var methods = [
{ name: 'balanceAt', call: 'balanceAt' }, { name: 'balanceAt', call: 'eth_balanceAt' },
{ name: 'stateAt', call: 'stateAt' }, { name: 'stateAt', call: 'eth_stateAt' },
{ name: 'countAt', call: 'countAt'}, { name: 'countAt', call: 'eth_countAt'},
{ name: 'codeAt', call: 'codeAt' }, { name: 'codeAt', call: 'eth_codeAt' },
{ name: 'transact', call: 'transact' }, { name: 'transact', call: 'eth_transact' },
{ name: 'call', call: 'call' }, { name: 'call', call: 'eth_call' },
{ name: 'block', call: blockCall }, { name: 'block', call: blockCall },
{ name: 'transaction', call: transactionCall }, { name: 'transaction', call: transactionCall },
{ name: 'uncle', call: uncleCall }, { name: 'uncle', call: uncleCall },
{ name: 'compile', call: 'compile' } { name: 'compile', call: 'eth_compile' },
{ name: 'lll', call: 'eth_lll' }
]; ];
return methods; return methods;
}; };
var ethProperties = function () { var ethProperties = function () {
return [ return [
{ name: 'coinbase', getter: 'coinbase', setter: 'setCoinbase' }, { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },
{ name: 'listening', getter: 'listening', setter: 'setListening' }, { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },
{ name: 'mining', getter: 'mining', setter: 'setMining' }, { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },
{ name: 'gasPrice', getter: 'gasPrice' }, { name: 'gasPrice', getter: 'eth_gasPrice' },
{ name: 'account', getter: 'account' }, { name: 'account', getter: 'eth_account' },
{ name: 'accounts', getter: 'accounts' }, { name: 'accounts', getter: 'eth_accounts' },
{ name: 'peerCount', getter: 'peerCount' }, { name: 'peerCount', getter: 'eth_peerCount' },
{ name: 'defaultBlock', getter: 'defaultBlock', setter: 'setDefaultBlock' }, { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },
{ name: 'number', getter: 'number'} { name: 'number', getter: 'eth_number'}
]; ];
}; };
var dbMethods = function () { var dbMethods = function () {
return [ return [
{ name: 'put', call: 'put' }, { name: 'put', call: 'db_put' },
{ name: 'get', call: 'get' }, { name: 'get', call: 'db_get' },
{ name: 'putString', call: 'putString' }, { name: 'putString', call: 'db_putString' },
{ name: 'getString', call: 'getString' } { name: 'getString', call: 'db_getString' }
]; ];
}; };
var shhMethods = function () { var shhMethods = function () {
return [ return [
{ name: 'post', call: 'post' }, { name: 'post', call: 'shh_post' },
{ name: 'newIdentity', call: 'newIdentity' }, { name: 'newIdentity', call: 'shh_newIdentity' },
{ name: 'haveIdentity', call: 'haveIdentity' }, { name: 'haveIdentity', call: 'shh_haveIdentity' },
{ name: 'newGroup', call: 'newGroup' }, { name: 'newGroup', call: 'shh_newGroup' },
{ name: 'addToGroup', call: 'addToGroup' } { name: 'addToGroup', call: 'shh_addToGroup' }
]; ];
}; };
var ethWatchMethods = function () { var ethWatchMethods = function () {
var newFilter = function (args) { var newFilter = function (args) {
return typeof args[0] === 'string' ? 'newFilterString' : 'newFilter'; return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';
}; };
return [ return [
{ name: 'newFilter', call: newFilter }, { name: 'newFilter', call: newFilter },
{ name: 'uninstallFilter', call: 'uninstallFilter' }, { name: 'uninstallFilter', call: 'eth_uninstallFilter' },
{ name: 'getMessages', call: 'getMessages' } { name: 'getMessages', call: 'eth_getMessages' }
]; ];
}; };
var shhWatchMethods = function () { var shhWatchMethods = function () {
return [ return [
{ name: 'newFilter', call: 'shhNewFilter' }, { name: 'newFilter', call: 'shh_newFilter' },
{ name: 'uninstallFilter', call: 'shhUninstallFilter' }, { name: 'uninstallFilter', call: 'shh_uninstallFilter' },
{ name: 'getMessage', call: 'shhGetMessages' } { name: 'getMessage', call: 'shh_getMessages' }
]; ];
}; };
@ -153,15 +154,15 @@
return {call: call, args: args}; return {call: call, args: args};
}).then(function (request) { }).then(function (request) {
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
web3.provider.send(request, function (result) { web3.provider.send(request, function (err, result) {
if (result || typeof result === "boolean") { if (!err) {
resolve(result); resolve(result);
return; return;
} }
reject(result); reject(err);
}); });
}); });
}).catch(function( err) { }).catch(function(err) {
console.error(err); console.error(err);
}); });
}; };
@ -173,8 +174,12 @@
var proto = {}; var proto = {};
proto.get = function () { proto.get = function () {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
web3.provider.send({call: property.getter}, function(result) { web3.provider.send({call: property.getter}, function(err, result) {
if (!err) {
resolve(result); resolve(result);
return;
}
reject(err);
}); });
}); });
}; };
@ -182,12 +187,12 @@
proto.set = function (val) { proto.set = function (val) {
return flattenPromise([val]).then(function (args) { return flattenPromise([val]).then(function (args) {
return new Promise(function (resolve) { return new Promise(function (resolve) {
web3.provider.send({call: property.setter, args: args}, function (result) { web3.provider.send({call: property.setter, args: args}, function (err, result) {
if (result) { if (!err) {
resolve(result); resolve(result);
} else { return;
reject(result);
} }
reject(err);
}); });
}); });
}).catch(function (err) { }).catch(function (err) {
@ -240,7 +245,7 @@
var hex = this.toHex(str); var hex = this.toHex(str);
while(hex.length < pad*2) while(hex.length < pad*2)
hex += "00"; hex += "00";
return "0x" + hex return "0x" + hex;
}, },
eth: { eth: {
@ -295,11 +300,11 @@
setupMethods(web3.shh, shhMethods()); setupMethods(web3.shh, shhMethods());
var ethWatch = { var ethWatch = {
changed: 'changed' changed: 'eth_changed'
}; };
setupMethods(ethWatch, ethWatchMethods()); setupMethods(ethWatch, ethWatchMethods());
var shhWatch = { var shhWatch = {
changed: 'shhChanged' changed: 'shh_changed'
}; };
setupMethods(shhWatch, shhWatchMethods()); setupMethods(shhWatch, shhWatchMethods());
@ -410,9 +415,11 @@
}; };
Filter.prototype.trigger = function(messages) { Filter.prototype.trigger = function(messages) {
if (!(messages instanceof Array) || messages.length) {
for(var i = 0; i < this.callbacks.length; i++) { for(var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].call(this, messages); this.callbacks[i].call(this, messages);
} }
}
}; };
Filter.prototype.uninstall = function() { Filter.prototype.uninstall = function() {
@ -440,7 +447,7 @@
if(data._id) { if(data._id) {
var cb = web3._callbacks[data._id]; var cb = web3._callbacks[data._id];
if (cb) { if (cb) {
cb.call(this, data.data) cb.call(this, data.error, data.data);
delete web3._callbacks[data._id]; delete web3._callbacks[data._id];
} }
} }

8
libjsqrc/qt.js

@ -2,19 +2,19 @@
This file is part of ethereum.js. This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ethereum.js is distributed in the hope that it will be useful, ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file ethereum.js /** @file qt.js
* @authors: * @authors:
* Marek Kotewicz <marek@ethdev.com> * Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014

2
libjsqrc/setup.js

@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file QEthereum.cpp /** @file setup.js
* @authors: * @authors:
* Marek Kotewicz <marek@ethdev.com> * Marek Kotewicz <marek@ethdev.com>
* @date 2014 * @date 2014

1
liblll/All.h

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "Assembly.h"
#include "CodeFragment.h" #include "CodeFragment.h"
#include "Compiler.h" #include "Compiler.h"
#include "CompilerState.h" #include "CompilerState.h"

2
liblll/CMakeLists.txt

@ -15,7 +15,7 @@ endif()
include_directories(..) include_directories(..)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)

2
liblll/CodeFragment.cpp

@ -25,7 +25,7 @@
#include <boost/spirit/include/support_utree.hpp> #include <boost/spirit/include/support_utree.hpp>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include "CompilerState.h" #include "CompilerState.h"
#include "Parser.h" #include "Parser.h"
using namespace std; using namespace std;

4
liblll/CodeFragment.h

@ -22,8 +22,8 @@
#pragma once #pragma once
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include "Assembly.h" #include <libevmcore/Assembly.h>
#include "Exceptions.h" #include "Exceptions.h"
namespace boost { namespace spirit { class utree; } } namespace boost { namespace spirit { class utree; } }

3
liblll/Exceptions.h

@ -32,16 +32,13 @@ namespace eth
class CompilerException: public dev::Exception {}; class CompilerException: public dev::Exception {};
class InvalidOperation: public CompilerException {}; class InvalidOperation: public CompilerException {};
class IntegerOutOfRange: public CompilerException {}; class IntegerOutOfRange: public CompilerException {};
class StringTooLong: public CompilerException {};
class EmptyList: public CompilerException {}; class EmptyList: public CompilerException {};
class DataNotExecutable: public CompilerException {}; class DataNotExecutable: public CompilerException {};
class IncorrectParameterCount: public CompilerException {}; class IncorrectParameterCount: public CompilerException {};
class InvalidDeposit: public CompilerException {};
class InvalidName: public CompilerException {}; class InvalidName: public CompilerException {};
class InvalidMacroArgs: public CompilerException {}; class InvalidMacroArgs: public CompilerException {};
class InvalidLiteral: public CompilerException {}; class InvalidLiteral: public CompilerException {};
class BareSymbol: public CompilerException {}; class BareSymbol: public CompilerException {};
class ExpectedLiteral: public CompilerException {};
} }
} }

2
libpyserpent/CMakeLists.txt

@ -13,7 +13,7 @@ include_directories(..)
target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} serpent)
target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} ${PYTHON_LS}) target_link_libraries(${EXECUTABLE} ${PYTHON_LS})

30
libqethereum/QEthereum.cpp

@ -59,13 +59,13 @@ void QWebThree::poll()
{ {
if (m_watches.size() > 0) if (m_watches.size() > 0)
{ {
QString batch = toJsonRpcBatch(m_watches, "changed"); QString batch = toJsonRpcBatch(m_watches, "eth_changed");
emit processData(batch, "changed"); emit processData(batch, "eth_changed");
} }
if (m_shhWatches.size() > 0) if (m_shhWatches.size() > 0)
{ {
QString batch = toJsonRpcBatch(m_shhWatches, "shhChanged"); QString batch = toJsonRpcBatch(m_shhWatches, "shh_changed");
emit processData(batch, "shhChanged"); emit processData(batch, "shh_changed");
} }
} }
@ -73,13 +73,13 @@ void QWebThree::clearWatches()
{ {
if (m_watches.size() > 0) if (m_watches.size() > 0)
{ {
QString batch = toJsonRpcBatch(m_watches, "uninstallFilter"); QString batch = toJsonRpcBatch(m_watches, "eth_uninstallFilter");
m_watches.clear(); m_watches.clear();
emit processData(batch, "internal"); emit processData(batch, "internal");
} }
if (m_shhWatches.size() > 0) if (m_shhWatches.size() > 0)
{ {
QString batch = toJsonRpcBatch(m_shhWatches, "shhUninstallFilter"); QString batch = toJsonRpcBatch(m_shhWatches, "shh_uninstallFilter");
m_shhWatches.clear(); m_shhWatches.clear();
emit processData(batch, "internal"); emit processData(batch, "internal");
} }
@ -106,7 +106,12 @@ void QWebThree::postMessage(QString _json)
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
QString method = f["call"].toString(); QString method = f["call"].toString();
if (!method.compare("uninstallFilter") && f["args"].isArray() && f["args"].toArray().size()) if (!method.compare("eth_uninstallFilter") && f["args"].isArray() && f["args"].toArray().size())
{
int idToRemove = f["args"].toArray()[0].toInt();
m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end());
}
else if (!method.compare("eth_uninstallFilter") && f["args"].isArray() && f["args"].toArray().size())
{ {
int idToRemove = f["args"].toArray()[0].toInt(); int idToRemove = f["args"].toArray()[0].toInt();
m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end()); m_watches.erase(std::remove(m_watches.begin(), m_watches.end(), idToRemove), m_watches.end());
@ -120,6 +125,7 @@ static QString formatOutput(QJsonObject const& _object)
QJsonObject res; QJsonObject res;
res["_id"] = _object["id"]; res["_id"] = _object["id"];
res["data"] = _object["result"]; res["data"] = _object["result"];
res["error"] = _object["error"];
return QString::fromUtf8(QJsonDocument(res).toJson()); return QString::fromUtf8(QJsonDocument(res).toJson());
} }
@ -128,7 +134,7 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo)
if (!_addInfo.compare("internal")) if (!_addInfo.compare("internal"))
return; return;
if (!_addInfo.compare("changed")) if (!_addInfo.compare("eth_changed"))
{ {
QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array(); QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array();
for (int i = 0; i < resultsArray.size(); i++) for (int i = 0; i < resultsArray.size(); i++)
@ -145,7 +151,7 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo)
return; return;
} }
if (!_addInfo.compare("shhChanged")) if (!_addInfo.compare("shh_changed"))
{ {
QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array(); QJsonArray resultsArray = QJsonDocument::fromJson(_json.toUtf8()).array();
for (int i = 0; i < resultsArray.size(); i++) for (int i = 0; i < resultsArray.size(); i++)
@ -164,11 +170,11 @@ void QWebThree::onDataProcessed(QString _json, QString _addInfo)
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if ((!_addInfo.compare("newFilter") || !_addInfo.compare("newFilterString")) && f.contains("result")) if ((!_addInfo.compare("eth_newFilter") || !_addInfo.compare("eth_newFilterString")) && f.contains("result"))
m_watches.push_back(f["result"].toInt()); m_watches.push_back(f["result"].toInt());
if (!_addInfo.compare("shhNewFilter") && f.contains("result")) else if (!_addInfo.compare("shh_newFilter") && f.contains("result"))
m_shhWatches.push_back(f["result"].toInt()); m_shhWatches.push_back(f["result"].toInt());
if (!_addInfo.compare("newIdentity") && f.contains("result")) else if (!_addInfo.compare("shh_newIdentity") && f.contains("result"))
emit onNewId(f["result"].toString()); emit onNewId(f["result"].toString());
response(formatOutput(f)); response(formatOutput(f));

2
libqethereum/QmlEthereum.cpp

@ -4,7 +4,7 @@
#include <QtCore/QtCore> #include <QtCore/QtCore>
#include <QtWebKitWidgets/QWebFrame> #include <QtWebKitWidgets/QWebFrame>
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libethereum/EthereumHost.h> #include <libethereum/EthereumHost.h>

2
libserpent/CMakeLists.txt

@ -16,7 +16,7 @@ endif()
include_directories(..) include_directories(..)
target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
if("${TARGET_PLATFORM}" STREQUAL "w64") if("${TARGET_PLATFORM}" STREQUAL "w64")

3
libserpent/compiler.cpp

@ -131,8 +131,7 @@ programData opcodeify(Node node,
} }
// Declare variable // Declare variable
else { else {
Node nodelist[] = { }; return pd(aux, multiToken(nullptr, 0, m), 0);
return pd(aux, multiToken(nodelist, 0, m), 0);
} }
} }
// Define functions (TODO: eventually move to rewriter.cpp, keep // Define functions (TODO: eventually move to rewriter.cpp, keep

33
libsolidity/AST.cpp

@ -263,6 +263,21 @@ TypeError ASTNode::createTypeError(string const& _description)
return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
} }
vector<FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const
{
vector<FunctionDefinition const*> exportedFunctions;
for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
if (f->isPublic() && f->getName() != getName())
exportedFunctions.push_back(f.get());
auto compareNames = [](FunctionDefinition const* _a, FunctionDefinition const* _b)
{
return _a->getName().compare(_b->getName()) < 0;
};
sort(exportedFunctions.begin(), exportedFunctions.end(), compareNames);
return exportedFunctions;
}
void Block::checkTypeRequirements() void Block::checkTypeRequirements()
{ {
for (shared_ptr<Statement> const& statement: m_statements) for (shared_ptr<Statement> const& statement: m_statements)
@ -337,9 +352,11 @@ void ExpressionStatement::checkTypeRequirements()
void Expression::expectType(Type const& _expectedType) void Expression::expectType(Type const& _expectedType)
{ {
checkTypeRequirements(); checkTypeRequirements();
if (!getType()->isImplicitlyConvertibleTo(_expectedType)) Type const& type = *getType();
BOOST_THROW_EXCEPTION(createTypeError("Type not implicitly convertible to expected type.")); if (!type.isImplicitlyConvertibleTo(_expectedType))
//@todo provide more information to the exception BOOST_THROW_EXCEPTION(createTypeError("Type " + type.toString() +
" not implicitly convertible to expected type "
+ _expectedType.toString() + "."));
} }
void UnaryOperation::checkTypeRequirements() void UnaryOperation::checkTypeRequirements()
@ -363,14 +380,18 @@ void BinaryOperation::checkTypeRequirements()
else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType()))
m_commonType = m_right->getType(); m_commonType = m_right->getType();
else else
BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation: " +
m_left->getType()->toString() + " vs. " +
m_right->getType()->toString()));
if (Token::isCompareOp(m_operator)) if (Token::isCompareOp(m_operator))
m_type = make_shared<BoolType>(); m_type = make_shared<BoolType>();
else else
{ {
m_type = m_commonType; m_type = m_commonType;
if (!m_commonType->acceptsBinaryOperator(m_operator)) if (!m_commonType->acceptsBinaryOperator(m_operator))
BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) +
" not compatible with type " +
m_commonType->toString()));
} }
} }
@ -479,6 +500,8 @@ void ElementaryTypeNameExpression::checkTypeRequirements()
void Literal::checkTypeRequirements() void Literal::checkTypeRequirements()
{ {
m_type = Type::forLiteral(*this); m_type = Type::forLiteral(*this);
if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Literal value too large."));
} }
} }

13
libsolidity/AST.h

@ -116,10 +116,12 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
std::vector<ASTPointer<StructDefinition>> const& getDefinedStructs() { return m_definedStructs; } std::vector<ASTPointer<StructDefinition>> const& getDefinedStructs() const { return m_definedStructs; }
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() { return m_stateVariables; } std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() { return m_definedFunctions; } std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
/// Returns the functions that make up the calling interface in the intended order.
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
private: private:
std::vector<ASTPointer<StructDefinition>> m_definedStructs; std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables; std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
@ -135,6 +137,8 @@ public:
Declaration(_location, _name), m_members(_members) {} Declaration(_location, _name), m_members(_members) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
std::vector<ASTPointer<VariableDeclaration>> const& getMembers() const { return m_members; }
private: private:
std::vector<ASTPointer<VariableDeclaration>> m_members; std::vector<ASTPointer<VariableDeclaration>> m_members;
}; };
@ -565,12 +569,15 @@ public:
Expression& getLeftExpression() const { return *m_left; } Expression& getLeftExpression() const { return *m_left; }
Expression& getRightExpression() const { return *m_right; } Expression& getRightExpression() const { return *m_right; }
Token::Value getOperator() const { return m_operator; } Token::Value getOperator() const { return m_operator; }
Type const& getCommonType() const { return *m_commonType; }
private: private:
ASTPointer<Expression> m_left; ASTPointer<Expression> m_left;
Token::Value m_operator; Token::Value m_operator;
ASTPointer<Expression> m_right; ASTPointer<Expression> m_right;
/// The common type that is used for the operation, not necessarily the result type (e.g. for
/// comparisons, this is always bool).
std::shared_ptr<Type const> m_commonType; std::shared_ptr<Type const> m_commonType;
}; };

8
libsolidity/ASTPrinter.cpp

@ -30,8 +30,8 @@ namespace dev
namespace solidity namespace solidity
{ {
ASTPrinter::ASTPrinter(ASTPointer<ASTNode> const& _ast, string const& _source): ASTPrinter::ASTPrinter(ASTNode& _ast, string const& _source):
m_indentation(0), m_source(_source), m_ast(_ast) m_indentation(0), m_source(_source), m_ast(&_ast)
{ {
} }
@ -430,8 +430,8 @@ void ASTPrinter::printSourcePart(ASTNode const& _node)
if (!m_source.empty()) if (!m_source.empty())
{ {
Location const& location(_node.getLocation()); Location const& location(_node.getLocation());
*m_ostream << getIndentation() << " Source: |" *m_ostream << getIndentation() << " Source: "
<< m_source.substr(location.start, location.end - location.start) << "|" << endl; << escaped(m_source.substr(location.start, location.end - location.start), false) << endl;
} }
} }

4
libsolidity/ASTPrinter.h

@ -38,7 +38,7 @@ class ASTPrinter: public ASTVisitor
public: public:
/// Create a printer for the given abstract syntax tree. If the source is specified, /// Create a printer for the given abstract syntax tree. If the source is specified,
/// the corresponding parts of the source are printed with each node. /// the corresponding parts of the source are printed with each node.
ASTPrinter(ASTPointer<ASTNode> const& _ast, std::string const& _source = std::string()); ASTPrinter(ASTNode& _ast, std::string const& _source = std::string());
/// Output the string representation of the AST to _stream. /// Output the string representation of the AST to _stream.
void print(std::ostream& _stream); void print(std::ostream& _stream);
@ -114,7 +114,7 @@ private:
int m_indentation; int m_indentation;
std::string m_source; std::string m_source;
ASTPointer<ASTNode> m_ast; ASTNode* m_ast;
std::ostream* m_ostream; std::ostream* m_ostream;
}; };

10
libsolidity/CMakeLists.txt

@ -6,18 +6,16 @@ aux_source_directory(. SRC_LIST)
set(EXECUTABLE solidity) set(EXECUTABLE solidity)
file(GLOB HEADERS "*.h")
if(ETH_STATIC) if(ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${SRC_LIST}) add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS})
else() else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST}) add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif() endif()
file(GLOB HEADERS "*.h")
include_directories(..) include_directories(..)
# @todo we only depend on Assembly, not on all of lll target_link_libraries(${EXECUTABLE} evmcore devcore)
target_link_libraries(${EXECUTABLE} evmface devcore lll)
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} )

65
libsolidity/Compiler.cpp

@ -21,6 +21,8 @@
*/ */
#include <algorithm> #include <algorithm>
#include <libevmcore/Instruction.h>
#include <libevmcore/Assembly.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
#include <libsolidity/Compiler.h> #include <libsolidity/Compiler.h>
#include <libsolidity/ExpressionCompiler.h> #include <libsolidity/ExpressionCompiler.h>
@ -30,11 +32,11 @@ using namespace std;
namespace dev { namespace dev {
namespace solidity { namespace solidity {
bytes Compiler::compile(ContractDefinition& _contract) bytes Compiler::compile(ContractDefinition& _contract, bool _optimize)
{ {
Compiler compiler; Compiler compiler;
compiler.compileContract(_contract); compiler.compileContract(_contract);
return compiler.m_context.getAssembledBytecode(); return compiler.m_context.getAssembledBytecode(_optimize);
} }
void Compiler::compileContract(ContractDefinition& _contract) void Compiler::compileContract(ContractDefinition& _contract)
@ -42,10 +44,12 @@ void Compiler::compileContract(ContractDefinition& _contract)
m_context = CompilerContext(); // clear it just in case m_context = CompilerContext(); // clear it just in case
//@todo constructor //@todo constructor
//@todo register state variables
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
m_context.addFunction(*function); m_context.addFunction(*function);
//@todo sort them?
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
m_context.addStateVariable(*variable);
appendFunctionSelector(_contract.getDefinedFunctions()); appendFunctionSelector(_contract.getDefinedFunctions());
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
@ -77,35 +81,34 @@ void Compiler::appendFunctionSelector(vector<ASTPointer<FunctionDefinition>> con
if (publicFunctions.size() > 255) if (publicFunctions.size() > 255)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract.")); BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract."));
//@todo check for calldatasize? // retrieve the first byte of the call data, which determines the called function
// retrieve the first byte of the call data // @todo This code had a jump table in a previous version which was more efficient but also
m_context << u256(0) << eth::Instruction::CALLDATALOAD << u256(0) << eth::Instruction::BYTE; // error prone (due to the optimizer and variable length tag addresses)
// check that it is not too large m_context << u256(1) << u256(0) // some constants
m_context << eth::Instruction::DUP1 << u256(publicFunctions.size() - 1) << eth::Instruction::LT; << eth::dupInstruction(1) << eth::Instruction::CALLDATALOAD
eth::AssemblyItem returnTag = m_context.appendConditionalJump(); << eth::dupInstruction(2) << eth::Instruction::BYTE
<< eth::dupInstruction(2);
// otherwise, jump inside jump table (each entry of the table has size 4) // stack here: 1 0 <funid> 0, stack top will be counted up until it matches funid
m_context << u256(4) << eth::Instruction::MUL;
eth::AssemblyItem jumpTableStart = m_context.pushNewTag();
m_context << eth::Instruction::ADD << eth::Instruction::JUMP;
// jump table @todo it could be that the optimizer destroys this
m_context << jumpTableStart;
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions) for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
m_context.appendJumpTo(f.second.second) << eth::Instruction::JUMPDEST; {
eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
m_context << returnTag << eth::Instruction::STOP; m_context << eth::dupInstruction(2) << eth::dupInstruction(2) << eth::Instruction::EQ;
m_context.appendConditionalJumpTo(callDataUnpackerEntry);
m_context << eth::dupInstruction(4) << eth::Instruction::ADD;
//@todo avoid the last ADD (or remove it in the optimizer)
}
m_context << eth::Instruction::STOP; // function not found
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions) for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
{ {
FunctionDefinition const& function = *f.second.first; FunctionDefinition const& function = *f.second.first;
m_context << f.second.second; eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
m_context << callDataUnpackerEntry;
eth::AssemblyItem returnTag = m_context.pushNewTag(); eth::AssemblyItem returnTag = m_context.pushNewTag();
appendCalldataUnpacker(function); appendCalldataUnpacker(function);
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
m_context << returnTag; m_context << returnTag;
appendReturnValuePacker(function); appendReturnValuePacker(function);
} }
} }
@ -122,7 +125,7 @@ void Compiler::appendCalldataUnpacker(FunctionDefinition const& _function)
if (numBytes == 0) if (numBytes == 0)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation()) << errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type not yet supported.")); << errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
if (numBytes == 32) if (numBytes == 32)
m_context << u256(dataOffset) << eth::Instruction::CALLDATALOAD; m_context << u256(dataOffset) << eth::Instruction::CALLDATALOAD;
else else
@ -139,11 +142,12 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters(); vector<ASTPointer<VariableDeclaration>> const& parameters = _function.getReturnParameters();
for (unsigned i = 0; i < parameters.size(); ++i) for (unsigned i = 0; i < parameters.size(); ++i)
{ {
unsigned numBytes = parameters[i]->getType()->getCalldataEncodedSize(); Type const& paramType = *parameters[i]->getType();
unsigned numBytes = paramType.getCalldataEncodedSize();
if (numBytes == 0) if (numBytes == 0)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(parameters[i]->getLocation()) << errinfo_sourceLocation(parameters[i]->getLocation())
<< errinfo_comment("Type not yet supported.")); << errinfo_comment("Type " + paramType.toString() + " not yet supported."));
m_context << eth::dupInstruction(parameters.size() - i); m_context << eth::dupInstruction(parameters.size() - i);
if (numBytes != 32) if (numBytes != 32)
m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL; m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
@ -271,8 +275,9 @@ bool Compiler::visit(Return& _return)
{ {
ExpressionCompiler::compileExpression(m_context, *expression); ExpressionCompiler::compileExpression(m_context, *expression);
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(), *firstVariable.getType()); ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType());
int stackPosition = m_context.getStackPositionOfVariable(firstVariable);
unsigned stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(firstVariable));
m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
} }
m_context.appendJumpTo(m_returnTag); m_context.appendJumpTo(m_returnTag);
@ -284,9 +289,11 @@ bool Compiler::visit(VariableDefinition& _variableDefinition)
if (Expression* expression = _variableDefinition.getExpression()) if (Expression* expression = _variableDefinition.getExpression())
{ {
ExpressionCompiler::compileExpression(m_context, *expression); ExpressionCompiler::compileExpression(m_context, *expression);
ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(), ExpressionCompiler::appendTypeConversion(m_context,
*expression->getType(),
*_variableDefinition.getDeclaration().getType()); *_variableDefinition.getDeclaration().getType());
int stackPosition = m_context.getStackPositionOfVariable(_variableDefinition.getDeclaration()); unsigned baseStackOffset = m_context.getBaseStackOffsetOfVariable(_variableDefinition.getDeclaration());
unsigned stackPosition = m_context.baseToCurrentStackOffset(baseStackOffset);
m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
} }
return false; return false;

4
libsolidity/Compiler.h

@ -33,11 +33,11 @@ public:
Compiler(): m_returnTag(m_context.newTag()) {} Compiler(): m_returnTag(m_context.newTag()) {}
void compileContract(ContractDefinition& _contract); void compileContract(ContractDefinition& _contract);
bytes getAssembledBytecode() { return m_context.getAssembledBytecode(); } bytes getAssembledBytecode(bool _optimize = false) { return m_context.getAssembledBytecode(_optimize); }
void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); }
/// Compile the given contract and return the EVM bytecode. /// Compile the given contract and return the EVM bytecode.
static bytes compile(ContractDefinition& _contract); static bytes compile(ContractDefinition& _contract, bool _optimize);
private: private:
/// Creates a new compiler context / assembly and packs the current code into the data part. /// Creates a new compiler context / assembly and packs the current code into the data part.

36
libsolidity/CompilerContext.cpp

@ -30,6 +30,12 @@ using namespace std;
namespace dev { namespace dev {
namespace solidity { namespace solidity {
void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
{
m_stateVariables[&_declaration] = m_stateVariablesSize;
m_stateVariablesSize += _declaration.getType()->getStorageSize();
}
void CompilerContext::initializeLocalVariables(unsigned _numVariables) void CompilerContext::initializeLocalVariables(unsigned _numVariables)
{ {
if (_numVariables > 0) if (_numVariables > 0)
@ -41,12 +47,9 @@ void CompilerContext::initializeLocalVariables(unsigned _numVariables)
} }
} }
int CompilerContext::getStackPositionOfVariable(Declaration const& _declaration) bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
{ {
auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration); return std::find(m_localVariables.begin(), m_localVariables.end(), _declaration) != m_localVariables.end();
if (asserts(res != m_localVariables.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack."));
return end(m_localVariables) - res - 1 + m_asm.deposit();
} }
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const
@ -57,5 +60,28 @@ eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition cons
return res->second.tag(); return res->second.tag();
} }
unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const
{
auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration);
if (asserts(res != m_localVariables.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack."));
return unsigned(end(m_localVariables) - res - 1);
}
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
{
return _baseOffset + m_asm.deposit();
}
u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const
{
auto it = m_stateVariables.find(&_declaration);
if (it == m_stateVariables.end())
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found in storage."));
return it->second;
}
} }
} }

31
libsolidity/CompilerContext.h

@ -23,8 +23,8 @@
#pragma once #pragma once
#include <ostream> #include <ostream>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <liblll/Assembly.h> #include <libevmcore/Assembly.h>
#include <libsolidity/Types.h> #include <libsolidity/Types.h>
namespace dev { namespace dev {
@ -38,19 +38,28 @@ namespace solidity {
class CompilerContext class CompilerContext
{ {
public: public:
CompilerContext() {} CompilerContext(): m_stateVariablesSize(0) {}
void addStateVariable(VariableDeclaration const& _declaration);
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); } void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
void initializeLocalVariables(unsigned _numVariables); void initializeLocalVariables(unsigned _numVariables);
void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); } void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); }
/// Returns the distance of the given local variable from the top of the stack.
int getStackPositionOfVariable(Declaration const& _declaration);
void addFunction(FunctionDefinition const& _function) { m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag())); } void addFunction(FunctionDefinition const& _function) { m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag())); }
eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const;
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
bool isFunctionDefinition(Declaration const* _declaration) const { return m_functionEntryLabels.count(_declaration); }
bool isLocalVariable(Declaration const* _declaration) const;
bool isStateVariable(Declaration const* _declaration) const { return m_stateVariables.count(_declaration); }
eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const;
/// Returns the distance of the given local variable from the top of the local variable stack.
unsigned getBaseStackOffsetOfVariable(Declaration const& _declaration) const;
/// If supplied by a value returned by @ref getBaseStackOffsetOfVariable(variable), returns
/// the distance of that variable from the current top of the stack.
unsigned baseToCurrentStackOffset(unsigned _baseOffset) const;
u256 getStorageLocationOfVariable(Declaration const& _declaration) const;
/// Appends a JUMPI instruction to a new tag and @returns the tag /// Appends a JUMPI instruction to a new tag and @returns the tag
eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); } eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); }
/// Appends a JUMPI instruction to @a _tag /// Appends a JUMPI instruction to @a _tag
@ -75,14 +84,18 @@ public:
eth::Assembly const& getAssembly() const { return m_asm; } eth::Assembly const& getAssembly() const { return m_asm; }
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; } void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
bytes getAssembledBytecode() const { return m_asm.assemble(); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }
private: private:
eth::Assembly m_asm; eth::Assembly m_asm;
/// Size of the state variables, offset of next variable to be added.
u256 m_stateVariablesSize;
/// Storage offsets of state variables
std::map<Declaration const*, u256> m_stateVariables;
/// Offsets of local variables on the stack. /// Offsets of local variables on the stack.
std::vector<Declaration const*> m_localVariables; std::vector<Declaration const*> m_localVariables;
/// Labels pointing to the entry points of funcitons. /// Labels pointing to the entry points of funcitons.
std::map<FunctionDefinition const*, eth::AssemblyItem> m_functionEntryLabels; std::map<Declaration const*, eth::AssemblyItem> m_functionEntryLabels;
}; };
} }

99
libsolidity/CompilerStack.cpp

@ -34,16 +34,101 @@ namespace dev
namespace solidity namespace solidity
{ {
bytes CompilerStack::compile(std::string const& _sourceCode, shared_ptr<Scanner> _scanner) void CompilerStack::setSource(string const& _sourceCode)
{ {
if (!_scanner) reset();
_scanner = make_shared<Scanner>(); m_scanner = make_shared<Scanner>(CharStream(_sourceCode));
_scanner->reset(CharStream(_sourceCode)); }
void CompilerStack::parse()
{
if (!m_scanner)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available."));
m_contractASTNode = Parser().parse(m_scanner);
NameAndTypeResolver().resolveNamesAndTypes(*m_contractASTNode);
m_parseSuccessful = true;
}
void CompilerStack::parse(string const& _sourceCode)
{
setSource(_sourceCode);
parse();
}
bytes const& CompilerStack::compile(bool _optimize)
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
m_bytecode.clear();
m_compiler = make_shared<Compiler>();
m_compiler->compileContract(*m_contractASTNode);
return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
}
ASTPointer<ContractDefinition> contract = Parser().parse(_scanner); bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
NameAndTypeResolver().resolveNamesAndTypes(*contract); {
return Compiler::compile(*contract); parse(_sourceCode);
return compile(_optimize);
} }
void CompilerStack::streamAssembly(ostream& _outStream)
{
if (!m_compiler || m_bytecode.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
m_compiler->streamAssembly(_outStream);
}
string const& CompilerStack::getInterface()
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
if (m_interface.empty())
{
stringstream interface;
interface << '[';
vector<FunctionDefinition const*> exportedFunctions = m_contractASTNode->getInterfaceFunctions();
unsigned functionsCount = exportedFunctions.size();
for (FunctionDefinition const* f: exportedFunctions)
{
auto streamVariables = [&](vector<ASTPointer<VariableDeclaration>> const& _vars)
{
unsigned varCount = _vars.size();
for (ASTPointer<VariableDeclaration> const& var: _vars)
{
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 << ']';
m_interface = interface.str();
}
return m_interface;
}
bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)
{
CompilerStack stack;
return stack.compile(_sourceCode, _optimize);
}
} }
} }

41
libsolidity/CompilerStack.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <ostream>
#include <string> #include <string>
#include <memory> #include <memory>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
@ -30,13 +31,51 @@ namespace dev {
namespace solidity { namespace solidity {
class Scanner; // forward class Scanner; // forward
class ContractDefinition; // forward
class Compiler; // forward
/**
* Easy to use and self-contained Solidity compiler with as few header dependencies as possible.
* It holds state and can be used to either step through the compilation stages (and abort e.g.
* before compilation to bytecode) or run the whole compilation in one call.
*/
class CompilerStack class CompilerStack
{ {
public: public:
CompilerStack() {}
void reset() { *this = CompilerStack(); }
void setSource(std::string const& _sourceCode);
void parse();
void parse(std::string const& _sourceCode);
/// Compiles the contract that was previously parsed.
bytes const& compile(bool _optimize = false);
/// Parses and compiles the given source code.
bytes const& compile(std::string const& _sourceCode, bool _optimize = false);
bytes const& getBytecode() const { return m_bytecode; }
/// Streams a verbose version of the assembly to @a _outStream.
/// Prerequisite: Successful compilation.
void streamAssembly(std::ostream& _outStream);
/// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile.
std::string const& getInterface();
/// Returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& getScanner() const { return *m_scanner; }
ContractDefinition& getAST() const { return *m_contractASTNode; }
/// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for /// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for
/// scanning the source code - this is useful for printing exception information. /// scanning the source code - this is useful for printing exception information.
static bytes compile(std::string const& _sourceCode, std::shared_ptr<Scanner> _scanner = std::shared_ptr<Scanner>()); static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false);
private:
std::shared_ptr<Scanner> m_scanner;
std::shared_ptr<ContractDefinition> m_contractASTNode;
bool m_parseSuccessful;
std::string m_interface;
std::shared_ptr<Compiler> m_compiler;
bytes m_bytecode;
}; };
} }

234
libsolidity/ExpressionCompiler.cpp

@ -37,25 +37,25 @@ void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression
_expression.accept(compiler); _expression.accept(compiler);
} }
bool ExpressionCompiler::visit(Assignment& _assignment) void ExpressionCompiler::appendTypeConversion(CompilerContext& _context,
Type const& _typeOnStack, Type const& _targetType)
{ {
m_currentLValue = nullptr; ExpressionCompiler compiler(_context);
compiler.appendTypeConversion(_typeOnStack, _targetType);
}
Expression& rightHandSide = _assignment.getRightHandSide(); bool ExpressionCompiler::visit(Assignment& _assignment)
rightHandSide.accept(*this); {
Type const& resultType = *_assignment.getType(); _assignment.getRightHandSide().accept(*this);
cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
m_currentLValue.reset();
_assignment.getLeftHandSide().accept(*this); _assignment.getLeftHandSide().accept(*this);
Token::Value op = _assignment.getAssignmentOperator(); Token::Value op = _assignment.getAssignmentOperator();
if (op != Token::ASSIGN) if (op != Token::ASSIGN) // compound assignment
{ appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
// compound assignment
m_context << eth::Instruction::SWAP1;
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType);
}
else else
m_context << eth::Instruction::POP; //@todo do not retrieve the value in the first place m_context << eth::Instruction::POP;
storeInLValue(_assignment); storeInLValue(_assignment);
return false; return false;
@ -92,10 +92,7 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
m_context << eth::Instruction::ADD; m_context << eth::Instruction::ADD;
else else
m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap
if (_unaryOperation.isPrefixOperation()) storeInLValue(_unaryOperation, !_unaryOperation.isPrefixOperation());
storeInLValue(_unaryOperation);
else
moveToLValue(_unaryOperation);
break; break;
case Token::ADD: // + case Token::ADD: // +
// unary add, so basically no-op // unary add, so basically no-op
@ -113,31 +110,26 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
{ {
Expression& leftExpression = _binaryOperation.getLeftExpression(); Expression& leftExpression = _binaryOperation.getLeftExpression();
Expression& rightExpression = _binaryOperation.getRightExpression(); Expression& rightExpression = _binaryOperation.getRightExpression();
Type const& resultType = *_binaryOperation.getType(); Type const& commonType = _binaryOperation.getCommonType();
Token::Value const op = _binaryOperation.getOperator(); Token::Value const op = _binaryOperation.getOperator();
if (op == Token::AND || op == Token::OR) if (op == Token::AND || op == Token::OR) // special case: short-circuiting
{
// special case: short-circuiting
appendAndOrOperatorCode(_binaryOperation); appendAndOrOperatorCode(_binaryOperation);
}
else if (Token::isCompareOp(op))
{
leftExpression.accept(*this);
rightExpression.accept(*this);
// the types to compare have to be the same, but the resulting type is always bool
if (asserts(*leftExpression.getType() == *rightExpression.getType()))
BOOST_THROW_EXCEPTION(InternalCompilerError());
appendCompareOperatorCode(op, *leftExpression.getType());
}
else else
{ {
leftExpression.accept(*this); bool cleanupNeeded = false;
cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType); if (commonType.getCategory() == Type::Category::INTEGER)
if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD)
cleanupNeeded = true;
rightExpression.accept(*this); rightExpression.accept(*this);
cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType); appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded);
appendOrdinaryBinaryOperatorCode(op, resultType); leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
if (Token::isCompareOp(op))
appendCompareOperatorCode(op, commonType);
else
appendOrdinaryBinaryOperatorCode(op, commonType);
} }
// do not visit the child nodes, we already did that explicitly // do not visit the child nodes, we already did that explicitly
@ -153,15 +145,19 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
BOOST_THROW_EXCEPTION(InternalCompilerError()); BOOST_THROW_EXCEPTION(InternalCompilerError());
Expression& firstArgument = *_functionCall.getArguments().front(); Expression& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this); firstArgument.accept(*this);
cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType()); appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
} }
else else
{ {
// Calling convention: Caller pushes return address and arguments // Calling convention: Caller pushes return address and arguments
// Callee removes them and pushes return values // Callee removes them and pushes return values
m_currentLValue = nullptr; m_currentLValue.reset();
_functionCall.getExpression().accept(*this); _functionCall.getExpression().accept(*this);
FunctionDefinition const& function = dynamic_cast<FunctionDefinition&>(*m_currentLValue); if (asserts(m_currentLValue.isInCode()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Code reference expected."));
eth::AssemblyItem functionTag(eth::PushTag, m_currentLValue.location);
FunctionDefinition const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()).getFunction();
eth::AssemblyItem returnLabel = m_context.pushNewTag(); eth::AssemblyItem returnLabel = m_context.pushNewTag();
std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments(); std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments();
@ -170,11 +166,10 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
arguments[i]->accept(*this); arguments[i]->accept(*this);
cleanHigherOrderBitsIfNeeded(*arguments[i]->getType(), appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType());
*function.getParameters()[i]->getType());
} }
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); m_context.appendJumpTo(functionTag);
m_context << returnLabel; m_context << returnLabel;
// callee adds return parameters, but removes arguments and return label // callee adds return parameters, but removes arguments and return label
@ -200,24 +195,20 @@ void ExpressionCompiler::endVisit(IndexAccess&)
void ExpressionCompiler::endVisit(Identifier& _identifier) void ExpressionCompiler::endVisit(Identifier& _identifier)
{ {
m_currentLValue = _identifier.getReferencedDeclaration(); Declaration const* declaration = _identifier.getReferencedDeclaration();
switch (_identifier.getType()->getCategory()) if (m_context.isLocalVariable(declaration))
{ m_currentLValue = LValueLocation(LValueLocation::STACK,
case Type::Category::BOOL: m_context.getBaseStackOffsetOfVariable(*declaration));
case Type::Category::INTEGER: else if (m_context.isStateVariable(declaration))
case Type::Category::REAL: m_currentLValue = LValueLocation(LValueLocation::STORAGE,
{ m_context.getStorageLocationOfVariable(*declaration));
//@todo we also have to check where to retrieve them from once we add storage variables else if (m_context.isFunctionDefinition(declaration))
unsigned stackPos = stackPositionOfLValue(); m_currentLValue = LValueLocation(LValueLocation::CODE,
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory m_context.getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(*declaration)).data());
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_identifier.getLocation()) else
<< errinfo_comment("Stack too deep.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not supported or identifier not found."));
m_context << eth::dupInstruction(stackPos + 1);
break; retrieveLValueValue(_identifier);
}
default:
break;
}
} }
void ExpressionCompiler::endVisit(Literal& _literal) void ExpressionCompiler::endVisit(Literal& _literal)
@ -233,28 +224,6 @@ void ExpressionCompiler::endVisit(Literal& _literal)
} }
} }
void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType)
{
// If the type of one of the operands is extended, we need to remove all
// higher-order bits that we might have ignored in previous operations.
// @todo: store in the AST whether the operand might have "dirty" higher
// order bits
if (_typeOnStack == _targetType)
return;
if (_typeOnStack.getCategory() == Type::Category::INTEGER &&
_targetType.getCategory() == Type::Category::INTEGER)
{
//@todo
}
else
{
// If we get here, there is either an implementation missing to clean higher oder bits
// for non-integer types that are explicitly convertible or we got here in error.
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested."));
}
}
void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation)
{ {
Token::Value const op = _binaryOperation.getOperator(); Token::Value const op = _binaryOperation.getOperator();
@ -284,23 +253,21 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
IntegerType const& type = dynamic_cast<IntegerType const&>(_type); IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
bool const isSigned = type.isSigned(); bool const isSigned = type.isSigned();
// note that EVM opcodes compare like "stack[0] < stack[1]",
// but our left value is at stack[1], so everyhing is reversed.
switch (_operator) switch (_operator)
{ {
case Token::GTE: case Token::GTE:
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT) m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT)
<< eth::Instruction::ISZERO; << eth::Instruction::ISZERO;
break; break;
case Token::LTE: case Token::LTE:
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT)
<< eth::Instruction::ISZERO; << eth::Instruction::ISZERO;
break; break;
case Token::GT: case Token::GT:
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
break; break;
case Token::LT: case Token::LT:
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator."));
@ -331,16 +298,16 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
m_context << eth::Instruction::ADD; m_context << eth::Instruction::ADD;
break; break;
case Token::SUB: case Token::SUB:
m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; m_context << eth::Instruction::SUB;
break; break;
case Token::MUL: case Token::MUL:
m_context << eth::Instruction::MUL; m_context << eth::Instruction::MUL;
break; break;
case Token::DIV: case Token::DIV:
m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV);
break; break;
case Token::MOD: case Token::MOD:
m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator."));
@ -379,31 +346,90 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
} }
} }
void ExpressionCompiler::storeInLValue(Expression const& _expression) void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
{ {
moveToLValue(_expression); // For a type extension, we need to remove all higher-order bits that we might have ignored in
unsigned stackPos = stackPositionOfLValue(); // previous operations.
if (stackPos > 16) // @todo: store in the AST whether the operand might have "dirty" higher order bits
if (_typeOnStack == _targetType && !_cleanupNeeded)
return;
if (_typeOnStack.getCategory() == Type::Category::INTEGER)
appendHighBitsCleanup(dynamic_cast<IntegerType const&>(_typeOnStack));
else if (_typeOnStack != _targetType)
// All other types should not be convertible to non-equal types.
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested."));
}
void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack)
{
if (_typeOnStack.getNumBits() == 256)
return;
else if (_typeOnStack.isSigned())
m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND;
else
m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND;
}
void ExpressionCompiler::retrieveLValueValue(Expression const& _expression)
{
switch (m_currentLValue.locationType)
{
case LValueLocation::CODE:
// not stored on the stack
break;
case LValueLocation::STACK:
{
unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location));
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
<< errinfo_comment("Stack too deep.")); << errinfo_comment("Stack too deep."));
m_context << eth::dupInstruction(stackPos + 1); m_context << eth::dupInstruction(stackPos + 1);
break;
}
case LValueLocation::STORAGE:
m_context << m_currentLValue.location << eth::Instruction::SLOAD;
break;
case LValueLocation::MEMORY:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented."));
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type."));
break;
}
} }
void ExpressionCompiler::moveToLValue(Expression const& _expression) void ExpressionCompiler::storeInLValue(Expression const& _expression, bool _move)
{ {
unsigned stackPos = stackPositionOfLValue(); switch (m_currentLValue.locationType)
{
case LValueLocation::STACK:
{
unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location));
if (stackPos > 16) if (stackPos > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
<< errinfo_comment("Stack too deep.")); << errinfo_comment("Stack too deep."));
else if (stackPos > 0) else if (stackPos > 0)
m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP;
} if (!_move)
retrieveLValueValue(_expression);
unsigned ExpressionCompiler::stackPositionOfLValue() const break;
{ }
if (asserts(m_currentLValue)) case LValueLocation::STORAGE:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not available on request.")); if (!_move)
return m_context.getStackPositionOfVariable(*m_currentLValue); m_context << eth::Instruction::DUP1;
m_context << m_currentLValue.location << eth::Instruction::SSTORE;
break;
case LValueLocation::CODE:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type does not support assignment."));
break;
case LValueLocation::MEMORY:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented."));
break;
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type."));
break;
}
} }
} }

66
libsolidity/ExpressionCompiler.h

@ -20,16 +20,25 @@
* Solidity AST to EVM bytecode compiler for expressions. * Solidity AST to EVM bytecode compiler for expressions.
*/ */
#include <libdevcore/Common.h>
#include <libsolidity/ASTVisitor.h> #include <libsolidity/ASTVisitor.h>
namespace dev { namespace dev {
namespace eth
{
class AssemblyItem; // forward
}
namespace solidity { namespace solidity {
class CompilerContext; // forward class CompilerContext; // forward
class Type; // forward
class IntegerType; // forward
/// Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream /**
/// of EVM instructions. It needs a compiler context that is the same for the whole compilation * Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream
/// unit. * of EVM instructions. It needs a compiler context that is the same for the whole compilation
* unit.
*/
class ExpressionCompiler: private ASTVisitor class ExpressionCompiler: private ASTVisitor
{ {
public: public:
@ -37,10 +46,10 @@ public:
static void compileExpression(CompilerContext& _context, Expression& _expression); static void compileExpression(CompilerContext& _context, Expression& _expression);
/// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type.
static void cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType); static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType);
private: private:
ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {} ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {}
virtual bool visit(Assignment& _assignment) override; virtual bool visit(Assignment& _assignment) override;
virtual void endVisit(UnaryOperation& _unaryOperation) override; virtual void endVisit(UnaryOperation& _unaryOperation) override;
@ -62,15 +71,44 @@ private:
void appendShiftOperatorCode(Token::Value _operator); void appendShiftOperatorCode(Token::Value _operator);
/// @} /// @}
/// Stores the value on top of the stack in the current lvalue and copies that value to the /// Appends an implicit or explicit type conversion. For now this comprises only erasing
/// top of the stack again /// higher-order bits (@see appendHighBitCleanup) when widening integer types.
void storeInLValue(Expression const& _expression); /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
/// The same as storeInLValue but do not again retrieve the value to the top of the stack. /// necessary.
void moveToLValue(Expression const& _expression); void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false);
/// Returns the position of @a m_currentLValue in the stack, where 0 is the top of the stack. //// Appends code that cleans higher-order bits for integer types.
unsigned stackPositionOfLValue() const; void appendHighBitsCleanup(IntegerType const& _typeOnStack);
Declaration* m_currentLValue; /// Copies the value of the current lvalue to the top of the stack.
void retrieveLValueValue(Expression const& _expression);
/// Stores the value on top of the stack in the current lvalue. Removes it from the stack if
/// @a _move is true.
void storeInLValue(Expression const& _expression, bool _move = false);
/**
* Location of an lvalue, either in code (for a function) on the stack, in the storage or memory.
*/
struct LValueLocation
{
enum LocationType { INVALID, CODE, STACK, MEMORY, STORAGE };
LValueLocation() { reset(); }
LValueLocation(LocationType _type, u256 const& _location): locationType(_type), location(_location) {}
void reset() { locationType = INVALID; location = 0; }
bool isValid() const { return locationType != INVALID; }
bool isInCode() const { return locationType == CODE; }
bool isInOnStack() const { return locationType == STACK; }
bool isInMemory() const { return locationType == MEMORY; }
bool isInStorage() const { return locationType == STORAGE; }
LocationType locationType;
/// Depending on the type, this is the id of a tag (code), the base offset of a stack
/// variable (@see CompilerContext::getBaseStackOffsetOfVariable) or the offset in
/// storage or memory.
u256 location;
};
LValueLocation m_currentLValue;
CompilerContext& m_context; CompilerContext& m_context;
}; };

106
libsolidity/Scanner.cpp

@ -271,7 +271,7 @@ void Scanner::scanToken()
token = Token::ADD; token = Token::ADD;
break; break;
case '-': case '-':
// - -- -= // - -- -= Number
advance(); advance();
if (m_char == '-') if (m_char == '-')
{ {
@ -280,6 +280,8 @@ void Scanner::scanToken()
} }
else if (m_char == '=') else if (m_char == '=')
token = selectToken(Token::ASSIGN_SUB); token = selectToken(Token::ASSIGN_SUB);
else if (m_char == '.' || IsDecimalDigit(m_char))
token = scanNumber('-');
else else
token = Token::SUB; token = Token::SUB;
break; break;
@ -331,7 +333,7 @@ void Scanner::scanToken()
// . Number // . Number
advance(); advance();
if (IsDecimalDigit(m_char)) if (IsDecimalDigit(m_char))
token = scanNumber(true); token = scanNumber('.');
else else
token = Token::PERIOD; token = Token::PERIOD;
break; break;
@ -372,7 +374,7 @@ void Scanner::scanToken()
if (IsIdentifierStart(m_char)) if (IsIdentifierStart(m_char))
token = scanIdentifierOrKeyword(); token = scanIdentifierOrKeyword();
else if (IsDecimalDigit(m_char)) else if (IsDecimalDigit(m_char))
token = scanNumber(false); token = scanNumber();
else if (skipWhitespace()) else if (skipWhitespace())
token = Token::WHITESPACE; token = Token::WHITESPACE;
else if (isSourcePastEndOfInput()) else if (isSourcePastEndOfInput())
@ -461,14 +463,11 @@ void Scanner::scanDecimalDigits()
} }
Token::Value Scanner::scanNumber(bool _periodSeen) Token::Value Scanner::scanNumber(char _charSeen)
{ {
// the first digit of the number or the fraction enum { DECIMAL, HEX, BINARY } kind = DECIMAL;
if (asserts(IsDecimalDigit(m_char)))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Number does not start with decimal digit."));
enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL;
LiteralScope literal(this); LiteralScope literal(this);
if (_periodSeen) if (_charSeen == '.')
{ {
// we have already seen a decimal point of the float // we have already seen a decimal point of the float
addLiteralChar('.'); addLiteralChar('.');
@ -476,12 +475,13 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
} }
else else
{ {
if (_charSeen == '-')
addLiteralChar('-');
// if the first character is '0' we must check for octals and hex // if the first character is '0' we must check for octals and hex
if (m_char == '0') if (m_char == '0')
{ {
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or // either 0, 0exxx, 0Exxx, 0.xxx or a hex number
// an octal number.
if (m_char == 'x' || m_char == 'X') if (m_char == 'x' || m_char == 'X')
{ {
// hex number // hex number
@ -556,17 +556,73 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
KEYWORD("function", Token::FUNCTION) \ KEYWORD("function", Token::FUNCTION) \
KEYWORD_GROUP('h') \ KEYWORD_GROUP('h') \
KEYWORD("hash", Token::HASH) \ KEYWORD("hash", Token::HASH) \
KEYWORD("hash8", Token::HASH8) \
KEYWORD("hash16", Token::HASH16) \
KEYWORD("hash24", Token::HASH24) \
KEYWORD("hash32", Token::HASH32) \ KEYWORD("hash32", Token::HASH32) \
KEYWORD("hash40", Token::HASH40) \
KEYWORD("hash48", Token::HASH48) \
KEYWORD("hash56", Token::HASH56) \
KEYWORD("hash64", Token::HASH64) \ KEYWORD("hash64", Token::HASH64) \
KEYWORD("hash72", Token::HASH72) \
KEYWORD("hash80", Token::HASH80) \
KEYWORD("hash88", Token::HASH88) \
KEYWORD("hash96", Token::HASH96) \
KEYWORD("hash104", Token::HASH104) \
KEYWORD("hash112", Token::HASH112) \
KEYWORD("hash120", Token::HASH120) \
KEYWORD("hash128", Token::HASH128) \ KEYWORD("hash128", Token::HASH128) \
KEYWORD("hash136", Token::HASH136) \
KEYWORD("hash144", Token::HASH144) \
KEYWORD("hash152", Token::HASH152) \
KEYWORD("hash160", Token::HASH160) \
KEYWORD("hash168", Token::HASH168) \
KEYWORD("hash178", Token::HASH176) \
KEYWORD("hash184", Token::HASH184) \
KEYWORD("hash192", Token::HASH192) \
KEYWORD("hash200", Token::HASH200) \
KEYWORD("hash208", Token::HASH208) \
KEYWORD("hash216", Token::HASH216) \
KEYWORD("hash224", Token::HASH224) \
KEYWORD("hash232", Token::HASH232) \
KEYWORD("hash240", Token::HASH240) \
KEYWORD("hash248", Token::HASH248) \
KEYWORD("hash256", Token::HASH256) \ KEYWORD("hash256", Token::HASH256) \
KEYWORD_GROUP('i') \ KEYWORD_GROUP('i') \
KEYWORD("if", Token::IF) \ KEYWORD("if", Token::IF) \
KEYWORD("in", Token::IN) \ KEYWORD("in", Token::IN) \
KEYWORD("int", Token::INT) \ KEYWORD("int", Token::INT) \
KEYWORD("int8", Token::INT8) \
KEYWORD("int16", Token::INT16) \
KEYWORD("int24", Token::INT24) \
KEYWORD("int32", Token::INT32) \ KEYWORD("int32", Token::INT32) \
KEYWORD("int40", Token::INT40) \
KEYWORD("int48", Token::INT48) \
KEYWORD("int56", Token::INT56) \
KEYWORD("int64", Token::INT64) \ KEYWORD("int64", Token::INT64) \
KEYWORD("int72", Token::INT72) \
KEYWORD("int80", Token::INT80) \
KEYWORD("int88", Token::INT88) \
KEYWORD("int96", Token::INT96) \
KEYWORD("int104", Token::INT104) \
KEYWORD("int112", Token::INT112) \
KEYWORD("int120", Token::INT120) \
KEYWORD("int128", Token::INT128) \ KEYWORD("int128", Token::INT128) \
KEYWORD("int136", Token::INT136) \
KEYWORD("int144", Token::INT144) \
KEYWORD("int152", Token::INT152) \
KEYWORD("int160", Token::INT160) \
KEYWORD("int168", Token::INT168) \
KEYWORD("int178", Token::INT176) \
KEYWORD("int184", Token::INT184) \
KEYWORD("int192", Token::INT192) \
KEYWORD("int200", Token::INT200) \
KEYWORD("int208", Token::INT208) \
KEYWORD("int216", Token::INT216) \
KEYWORD("int224", Token::INT224) \
KEYWORD("int232", Token::INT232) \
KEYWORD("int240", Token::INT240) \
KEYWORD("int248", Token::INT248) \
KEYWORD("int256", Token::INT256) \ KEYWORD("int256", Token::INT256) \
KEYWORD_GROUP('l') \ KEYWORD_GROUP('l') \
KEYWORD_GROUP('m') \ KEYWORD_GROUP('m') \
@ -591,9 +647,37 @@ Token::Value Scanner::scanNumber(bool _periodSeen)
KEYWORD("true", Token::TRUE_LITERAL) \ KEYWORD("true", Token::TRUE_LITERAL) \
KEYWORD_GROUP('u') \ KEYWORD_GROUP('u') \
KEYWORD("uint", Token::UINT) \ KEYWORD("uint", Token::UINT) \
KEYWORD("uint8", Token::UINT8) \
KEYWORD("uint16", Token::UINT16) \
KEYWORD("uint24", Token::UINT24) \
KEYWORD("uint32", Token::UINT32) \ KEYWORD("uint32", Token::UINT32) \
KEYWORD("uint40", Token::UINT40) \
KEYWORD("uint48", Token::UINT48) \
KEYWORD("uint56", Token::UINT56) \
KEYWORD("uint64", Token::UINT64) \ KEYWORD("uint64", Token::UINT64) \
KEYWORD("uint72", Token::UINT72) \
KEYWORD("uint80", Token::UINT80) \
KEYWORD("uint88", Token::UINT88) \
KEYWORD("uint96", Token::UINT96) \
KEYWORD("uint104", Token::UINT104) \
KEYWORD("uint112", Token::UINT112) \
KEYWORD("uint120", Token::UINT120) \
KEYWORD("uint128", Token::UINT128) \ KEYWORD("uint128", Token::UINT128) \
KEYWORD("uint136", Token::UINT136) \
KEYWORD("uint144", Token::UINT144) \
KEYWORD("uint152", Token::UINT152) \
KEYWORD("uint160", Token::UINT160) \
KEYWORD("uint168", Token::UINT168) \
KEYWORD("uint178", Token::UINT176) \
KEYWORD("uint184", Token::UINT184) \
KEYWORD("uint192", Token::UINT192) \
KEYWORD("uint200", Token::UINT200) \
KEYWORD("uint208", Token::UINT208) \
KEYWORD("uint216", Token::UINT216) \
KEYWORD("uint224", Token::UINT224) \
KEYWORD("uint232", Token::UINT232) \
KEYWORD("uint240", Token::UINT240) \
KEYWORD("uint248", Token::UINT248) \
KEYWORD("uint256", Token::UINT256) \ KEYWORD("uint256", Token::UINT256) \
KEYWORD("ureal", Token::UREAL) \ KEYWORD("ureal", Token::UREAL) \
KEYWORD_GROUP('v') \ KEYWORD_GROUP('v') \

2
libsolidity/Scanner.h

@ -180,7 +180,7 @@ private:
Token::Value skipMultiLineComment(); Token::Value skipMultiLineComment();
void scanDecimalDigits(); void scanDecimalDigits();
Token::Value scanNumber(bool _periodSeen); Token::Value scanNumber(char _charSeen = 0);
Token::Value scanIdentifierOrKeyword(); Token::Value scanIdentifierOrKeyword();
Token::Value scanString(); Token::Value scanString();

84
libsolidity/Token.h

@ -169,19 +169,103 @@ namespace solidity
* the implementation in Types.cpp has to be synced to this here * the implementation in Types.cpp has to be synced to this here
* TODO more to be added */ \ * TODO more to be added */ \
K(INT, "int", 0) \ K(INT, "int", 0) \
K(INT8, "int8", 0) \
K(INT16, "int16", 0) \
K(INT24, "int24", 0) \
K(INT32, "int32", 0) \ K(INT32, "int32", 0) \
K(INT40, "int40", 0) \
K(INT48, "int48", 0) \
K(INT56, "int56", 0) \
K(INT64, "int64", 0) \ K(INT64, "int64", 0) \
K(INT72, "int72", 0) \
K(INT80, "int80", 0) \
K(INT88, "int88", 0) \
K(INT96, "int96", 0) \
K(INT104, "int104", 0) \
K(INT112, "int112", 0) \
K(INT120, "int120", 0) \
K(INT128, "int128", 0) \ K(INT128, "int128", 0) \
K(INT136, "int136", 0) \
K(INT144, "int144", 0) \
K(INT152, "int152", 0) \
K(INT160, "int160", 0) \
K(INT168, "int168", 0) \
K(INT176, "int178", 0) \
K(INT184, "int184", 0) \
K(INT192, "int192", 0) \
K(INT200, "int200", 0) \
K(INT208, "int208", 0) \
K(INT216, "int216", 0) \
K(INT224, "int224", 0) \
K(INT232, "int232", 0) \
K(INT240, "int240", 0) \
K(INT248, "int248", 0) \
K(INT256, "int256", 0) \ K(INT256, "int256", 0) \
K(UINT, "uint", 0) \ K(UINT, "uint", 0) \
K(UINT8, "uint8", 0) \
K(UINT16, "uint16", 0) \
K(UINT24, "uint24", 0) \
K(UINT32, "uint32", 0) \ K(UINT32, "uint32", 0) \
K(UINT40, "uint40", 0) \
K(UINT48, "uint48", 0) \
K(UINT56, "uint56", 0) \
K(UINT64, "uint64", 0) \ K(UINT64, "uint64", 0) \
K(UINT72, "uint72", 0) \
K(UINT80, "uint80", 0) \
K(UINT88, "uint88", 0) \
K(UINT96, "uint96", 0) \
K(UINT104, "uint104", 0) \
K(UINT112, "uint112", 0) \
K(UINT120, "uint120", 0) \
K(UINT128, "uint128", 0) \ K(UINT128, "uint128", 0) \
K(UINT136, "uint136", 0) \
K(UINT144, "uint144", 0) \
K(UINT152, "uint152", 0) \
K(UINT160, "uint160", 0) \
K(UINT168, "uint168", 0) \
K(UINT176, "uint178", 0) \
K(UINT184, "uint184", 0) \
K(UINT192, "uint192", 0) \
K(UINT200, "uint200", 0) \
K(UINT208, "uint208", 0) \
K(UINT216, "uint216", 0) \
K(UINT224, "uint224", 0) \
K(UINT232, "uint232", 0) \
K(UINT240, "uint240", 0) \
K(UINT248, "uint248", 0) \
K(UINT256, "uint256", 0) \ K(UINT256, "uint256", 0) \
K(HASH, "hash", 0) \ K(HASH, "hash", 0) \
K(HASH8, "hash8", 0) \
K(HASH16, "hash16", 0) \
K(HASH24, "hash24", 0) \
K(HASH32, "hash32", 0) \ K(HASH32, "hash32", 0) \
K(HASH40, "hash40", 0) \
K(HASH48, "hash48", 0) \
K(HASH56, "hash56", 0) \
K(HASH64, "hash64", 0) \ K(HASH64, "hash64", 0) \
K(HASH72, "hash72", 0) \
K(HASH80, "hash80", 0) \
K(HASH88, "hash88", 0) \
K(HASH96, "hash96", 0) \
K(HASH104, "hash104", 0) \
K(HASH112, "hash112", 0) \
K(HASH120, "hash120", 0) \
K(HASH128, "hash128", 0) \ K(HASH128, "hash128", 0) \
K(HASH136, "hash136", 0) \
K(HASH144, "hash144", 0) \
K(HASH152, "hash152", 0) \
K(HASH160, "hash160", 0) \
K(HASH168, "hash168", 0) \
K(HASH176, "hash178", 0) \
K(HASH184, "hash184", 0) \
K(HASH192, "hash192", 0) \
K(HASH200, "hash200", 0) \
K(HASH208, "hash208", 0) \
K(HASH216, "hash216", 0) \
K(HASH224, "hash224", 0) \
K(HASH232, "hash232", 0) \
K(HASH240, "hash240", 0) \
K(HASH248, "hash248", 0) \
K(HASH256, "hash256", 0) \ K(HASH256, "hash256", 0) \
K(ADDRESS, "address", 0) \ K(ADDRESS, "address", 0) \
K(BOOL, "bool", 0) \ K(BOOL, "bool", 0) \

75
libsolidity/Types.cpp

@ -25,12 +25,14 @@
#include <libsolidity/Types.h> #include <libsolidity/Types.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
using namespace std;
namespace dev namespace dev
{ {
namespace solidity namespace solidity
{ {
std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken) shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
{ {
if (asserts(Token::isElementaryTypeName(_typeToken))) if (asserts(Token::isElementaryTypeName(_typeToken)))
BOOST_THROW_EXCEPTION(InternalCompilerError()); BOOST_THROW_EXCEPTION(InternalCompilerError());
@ -38,66 +40,69 @@ std::shared_ptr<Type> Type::fromElementaryTypeName(Token::Value _typeToken)
if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) if (Token::INT <= _typeToken && _typeToken <= Token::HASH256)
{ {
int offset = _typeToken - Token::INT; int offset = _typeToken - Token::INT;
int bits = offset % 5; int bytes = offset % 33;
if (bits == 0) if (bytes == 0)
bits = 256; bytes = 32;
else int modifier = offset / 33;
bits = (1 << (bits - 1)) * 32; return make_shared<IntegerType>(bytes * 8,
int modifier = offset / 5;
return std::make_shared<IntegerType>(bits,
modifier == 0 ? IntegerType::Modifier::SIGNED : modifier == 0 ? IntegerType::Modifier::SIGNED :
modifier == 1 ? IntegerType::Modifier::UNSIGNED : modifier == 1 ? IntegerType::Modifier::UNSIGNED :
IntegerType::Modifier::HASH); IntegerType::Modifier::HASH);
} }
else if (_typeToken == Token::ADDRESS) else if (_typeToken == Token::ADDRESS)
return std::make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS); return make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS);
else if (_typeToken == Token::BOOL) else if (_typeToken == Token::BOOL)
return std::make_shared<BoolType>(); return make_shared<BoolType>();
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
std::string(Token::toString(_typeToken)) + " to type.")); std::string(Token::toString(_typeToken)) + " to type."));
return std::shared_ptr<Type>();
} }
std::shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) shared_ptr<Type> Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
{ {
return std::make_shared<StructType>(*_typeName.getReferencedStruct()); return make_shared<StructType>(*_typeName.getReferencedStruct());
} }
std::shared_ptr<Type> Type::fromMapping(Mapping const&) shared_ptr<Type> Type::fromMapping(Mapping const&)
{ {
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented."));
return std::shared_ptr<Type>();
} }
std::shared_ptr<Type> Type::forLiteral(Literal const& _literal) shared_ptr<Type> Type::forLiteral(Literal const& _literal)
{ {
switch (_literal.getToken()) switch (_literal.getToken())
{ {
case Token::TRUE_LITERAL: case Token::TRUE_LITERAL:
case Token::FALSE_LITERAL: case Token::FALSE_LITERAL:
return std::make_shared<BoolType>(); return make_shared<BoolType>();
case Token::NUMBER: case Token::NUMBER:
return IntegerType::smallestTypeForLiteral(_literal.getValue()); return IntegerType::smallestTypeForLiteral(_literal.getValue());
case Token::STRING_LITERAL: case Token::STRING_LITERAL:
return std::shared_ptr<Type>(); // @todo return shared_ptr<Type>(); // @todo
default: default:
return std::shared_ptr<Type>(); return shared_ptr<Type>();
} }
} }
std::shared_ptr<IntegerType> IntegerType::smallestTypeForLiteral(std::string const&) shared_ptr<IntegerType> IntegerType::smallestTypeForLiteral(string const& _literal)
{ {
//@todo bigint value(_literal);
return std::make_shared<IntegerType>(256, Modifier::UNSIGNED); bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-');
if (isSigned)
// convert to positive number of same bit requirements
value = ((-value) - 1) << 1;
unsigned bytes = max(bytesRequired(value), 1u);
if (bytes > 32)
return shared_ptr<IntegerType>();
return make_shared<IntegerType>(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED);
} }
IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
m_bits(_bits), m_modifier(_modifier) m_bits(_bits), m_modifier(_modifier)
{ {
if (isAddress()) if (isAddress())
_bits = 160; m_bits = 160;
if (asserts(_bits > 0 && _bits <= 256 && _bits % 8 == 0)) if (asserts(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid bit number for integer type: " + dev::toString(_bits))); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid bit number for integer type: " + dev::toString(_bits)));
} }
@ -155,19 +160,17 @@ bool IntegerType::operator==(Type const& _other) const
return other.m_bits == m_bits && other.m_modifier == m_modifier; return other.m_bits == m_bits && other.m_modifier == m_modifier;
} }
std::string IntegerType::toString() const string IntegerType::toString() const
{ {
if (isAddress()) if (isAddress())
return "address"; return "address";
std::string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint");
return prefix + dev::toString(m_bits); return prefix + dev::toString(m_bits);
} }
u256 IntegerType::literalValue(Literal const& _literal) const u256 IntegerType::literalValue(Literal const& _literal) const
{ {
bigint value(_literal.getValue()); bigint value(_literal.getValue());
//@todo check that the number is not too large
//@todo does this work for signed numbers?
return u256(value); return u256(value);
} }
@ -202,6 +205,14 @@ bool ContractType::operator==(Type const& _other) const
return other.m_contract == m_contract; return other.m_contract == m_contract;
} }
u256 ContractType::getStorageSize() const
{
u256 size = 0;
for (ASTPointer<VariableDeclaration> const& variable: m_contract.getStateVariables())
size += variable->getType()->getStorageSize();
return max<u256>(1, size);
}
bool StructType::operator==(Type const& _other) const bool StructType::operator==(Type const& _other) const
{ {
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())
@ -210,6 +221,14 @@ bool StructType::operator==(Type const& _other) const
return other.m_struct == m_struct; return other.m_struct == m_struct;
} }
u256 StructType::getStorageSize() const
{
u256 size = 0;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
size += variable->getType()->getStorageSize();
return max<u256>(1, size);
}
bool FunctionType::operator==(Type const& _other) const bool FunctionType::operator==(Type const& _other) const
{ {
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())

21
libsolidity/Types.h

@ -56,7 +56,8 @@ public:
static std::shared_ptr<Type> fromMapping(Mapping const& _typeName); static std::shared_ptr<Type> fromMapping(Mapping const& _typeName);
/// @} /// @}
/// Auto-detect the proper type for a literal /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
/// not fit any type.
static std::shared_ptr<Type> forLiteral(Literal const& _literal); static std::shared_ptr<Type> forLiteral(Literal const& _literal);
virtual Category getCategory() const = 0; virtual Category getCategory() const = 0;
@ -74,6 +75,9 @@ public:
/// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding /// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding
/// is not a simple big-endian encoding or the type cannot be stored on the stack. /// is not a simple big-endian encoding or the type cannot be stored on the stack.
virtual unsigned getCalldataEncodedSize() const { return 0; } virtual unsigned getCalldataEncodedSize() const { return 0; }
/// @returns number of bytes required to hold this value in storage.
/// For dynamically "allocated" types, it returns the size of the statically allocated head,
virtual u256 getStorageSize() const { return 1; }
virtual std::string toString() const = 0; virtual std::string toString() const = 0;
virtual u256 literalValue(Literal const&) const virtual u256 literalValue(Literal const&) const
@ -95,6 +99,8 @@ public:
}; };
virtual Category getCategory() const override { return Category::INTEGER; } virtual Category getCategory() const override { return Category::INTEGER; }
/// @returns the smallest integer type for the given literal or an empty pointer
/// if no type fits.
static std::shared_ptr<IntegerType> smallestTypeForLiteral(std::string const& _literal); static std::shared_ptr<IntegerType> smallestTypeForLiteral(std::string const& _literal);
explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED);
@ -154,7 +160,7 @@ public:
ContractType(ContractDefinition const& _contract): m_contract(_contract) {} ContractType(ContractDefinition const& _contract): m_contract(_contract) {}
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const;
virtual std::string toString() const override { return "contract{...}"; } virtual std::string toString() const override { return "contract{...}"; }
private: private:
@ -175,7 +181,7 @@ public:
} }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const;
virtual std::string toString() const override { return "struct{...}"; } virtual std::string toString() const override { return "struct{...}"; }
private: private:
@ -193,9 +199,9 @@ public:
FunctionDefinition const& getFunction() const { return m_function; } FunctionDefinition const& getFunction() const { return m_function; }
virtual std::string toString() const override { return "function(...)returns(...)"; }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override { return "function(...)returns(...)"; }
virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable function type requested.")); }
private: private:
FunctionDefinition const& m_function; FunctionDefinition const& m_function;
@ -209,9 +215,9 @@ class MappingType: public Type
public: public:
virtual Category getCategory() const override { return Category::MAPPING; } virtual Category getCategory() const override { return Category::MAPPING; }
MappingType() {} MappingType() {}
virtual std::string toString() const override { return "mapping(...=>...)"; }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override { return "mapping(...=>...)"; }
private: private:
std::shared_ptr<Type const> m_keyType; std::shared_ptr<Type const> m_keyType;
@ -229,6 +235,7 @@ public:
VoidType() {} VoidType() {}
virtual std::string toString() const override { return "void"; } virtual std::string toString() const override { return "void"; }
virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); }
}; };
/** /**
@ -244,7 +251,7 @@ public:
std::shared_ptr<Type const> const& getActualType() const { return m_actualType; } std::shared_ptr<Type const> const& getActualType() const { return m_actualType; }
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual u256 getStorageSize() const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); }
virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; }
private: private:

101
libweb3jsonrpc/WebThreeStubServer.cpp

@ -22,7 +22,7 @@
*/ */
#include "WebThreeStubServer.h" #include "WebThreeStubServer.h"
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
@ -194,9 +194,11 @@ static dev::eth::MessageFilter toMessageFilter(Json::Value const& _json)
if (!_json["topics"].empty()) if (!_json["topics"].empty())
{ {
if (_json["topics"].isArray()) if (_json["topics"].isArray())
{
for (auto i: _json["topics"]) for (auto i: _json["topics"])
if (i.isString()) if (i.isString())
filter.topic(jsToU256(i.asString())); filter.topic(jsToU256(i.asString()));
}
else if(_json["topics"].isString()) else if(_json["topics"].isString())
filter.topic(jsToU256(_json["topics"].asString())); filter.topic(jsToU256(_json["topics"].asString()));
} }
@ -268,14 +270,14 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message
res["sent"] = (int)_e.sent(); res["sent"] = (int)_e.sent();
res["ttl"] = (int)_e.ttl(); res["ttl"] = (int)_e.ttl();
res["workProved"] = (int)_e.workProved(); res["workProved"] = (int)_e.workProved();
res["topic"] = toJS(_e.topic()); for (auto const& t: _e.topics())
res["payload"] = asString(_m.payload()); res["topics"].append(toJS(t));
res["payload"] = toJS(_m.payload());
res["from"] = toJS(_m.from()); res["from"] = toJS(_m.from());
res["to"] = toJS(_m.to()); res["to"] = toJS(_m.to());
return res; return res;
} }
WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts): WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts):
AbstractWebThreeStubServer(_conn), AbstractWebThreeStubServer(_conn),
m_web3(_web3) m_web3(_web3)
@ -312,7 +314,7 @@ std::shared_ptr<dev::shh::Interface> WebThreeStubServer::face() const
return m_web3.whisper(); return m_web3.whisper();
} }
Json::Value WebThreeStubServer::accounts() Json::Value WebThreeStubServer::eth_accounts()
{ {
Json::Value ret(Json::arrayValue); Json::Value ret(Json::arrayValue);
for (auto i: m_accounts) for (auto i: m_accounts)
@ -320,27 +322,27 @@ Json::Value WebThreeStubServer::accounts()
return ret; return ret;
} }
std::string WebThreeStubServer::addToGroup(std::string const& _group, std::string const& _who) std::string WebThreeStubServer::shh_addToGroup(std::string const& _group, std::string const& _who)
{ {
(void)_group; (void)_group;
(void)_who; (void)_who;
return ""; return "";
} }
std::string WebThreeStubServer::balanceAt(string const& _address) std::string WebThreeStubServer::eth_balanceAt(string const& _address)
{ {
int block = 0; int block = 0;
return toJS(client()->balanceAt(jsToAddress(_address), block)); return toJS(client()->balanceAt(jsToAddress(_address), block));
} }
Json::Value WebThreeStubServer::blockByHash(std::string const& _hash) Json::Value WebThreeStubServer::eth_blockByHash(std::string const& _hash)
{ {
if (!client()) if (!client())
return ""; return "";
return toJson(client()->blockInfo(jsToFixed<32>(_hash))); return toJson(client()->blockInfo(jsToFixed<32>(_hash)));
} }
Json::Value WebThreeStubServer::blockByNumber(int const& _number) Json::Value WebThreeStubServer::eth_blockByNumber(int const& _number)
{ {
if (!client()) if (!client())
return ""; return "";
@ -383,7 +385,7 @@ static TransactionSkeleton toTransaction(Json::Value const& _json)
return ret; return ret;
} }
std::string WebThreeStubServer::call(Json::Value const& _json) std::string WebThreeStubServer::eth_call(Json::Value const& _json)
{ {
std::string ret; std::string ret;
if (!client()) if (!client())
@ -407,41 +409,41 @@ std::string WebThreeStubServer::call(Json::Value const& _json)
return ret; return ret;
} }
bool WebThreeStubServer::changed(int const& _id) bool WebThreeStubServer::eth_changed(int const& _id)
{ {
if (!client()) if (!client())
return false; return false;
return client()->checkWatch(_id); return client()->checkWatch(_id);
} }
std::string WebThreeStubServer::codeAt(string const& _address) std::string WebThreeStubServer::eth_codeAt(string const& _address)
{ {
int block = 0; int block = 0;
return client() ? jsFromBinary(client()->codeAt(jsToAddress(_address), block)) : ""; return client() ? jsFromBinary(client()->codeAt(jsToAddress(_address), block)) : "";
} }
std::string WebThreeStubServer::coinbase() std::string WebThreeStubServer::eth_coinbase()
{ {
return client() ? toJS(client()->address()) : ""; return client() ? toJS(client()->address()) : "";
} }
double WebThreeStubServer::countAt(string const& _address) double WebThreeStubServer::eth_countAt(string const& _address)
{ {
int block = 0; int block = 0;
return client() ? (double)(uint64_t)client()->countAt(jsToAddress(_address), block) : 0; return client() ? (double)(uint64_t)client()->countAt(jsToAddress(_address), block) : 0;
} }
int WebThreeStubServer::defaultBlock() int WebThreeStubServer::eth_defaultBlock()
{ {
return client() ? client()->getDefault() : 0; return client() ? client()->getDefault() : 0;
} }
std::string WebThreeStubServer::gasPrice() std::string WebThreeStubServer::eth_gasPrice()
{ {
return toJS(10 * dev::eth::szabo); return toJS(10 * dev::eth::szabo);
} }
std::string WebThreeStubServer::get(std::string const& _name, std::string const& _key) std::string WebThreeStubServer::db_get(std::string const& _name, std::string const& _key)
{ {
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
string ret; string ret;
@ -449,14 +451,14 @@ std::string WebThreeStubServer::get(std::string const& _name, std::string const&
return toJS(dev::asBytes(ret)); return toJS(dev::asBytes(ret));
} }
Json::Value WebThreeStubServer::getMessages(int const& _id) Json::Value WebThreeStubServer::eth_getMessages(int const& _id)
{ {
if (!client()) if (!client())
return Json::Value(); return Json::Value();
return toJson(client()->messages(_id)); return toJson(client()->messages(_id));
} }
std::string WebThreeStubServer::getString(std::string const& _name, std::string const& _key) std::string WebThreeStubServer::db_getString(std::string const& _name, std::string const& _key)
{ {
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
string ret; string ret;
@ -464,22 +466,22 @@ std::string WebThreeStubServer::getString(std::string const& _name, std::string
return ret; return ret;
} }
bool WebThreeStubServer::haveIdentity(std::string const& _id) bool WebThreeStubServer::shh_haveIdentity(std::string const& _id)
{ {
return m_ids.count(jsToPublic(_id)) > 0; return m_ids.count(jsToPublic(_id)) > 0;
} }
bool WebThreeStubServer::listening() bool WebThreeStubServer::eth_listening()
{ {
return m_web3.isNetworkStarted(); return m_web3.isNetworkStarted();
} }
bool WebThreeStubServer::mining() bool WebThreeStubServer::eth_mining()
{ {
return client() ? client()->isMining() : false; return client() ? client()->isMining() : false;
} }
int WebThreeStubServer::newFilter(Json::Value const& _json) int WebThreeStubServer::eth_newFilter(Json::Value const& _json)
{ {
unsigned ret = -1; unsigned ret = -1;
if (!client()) if (!client())
@ -488,7 +490,7 @@ int WebThreeStubServer::newFilter(Json::Value const& _json)
return ret; return ret;
} }
int WebThreeStubServer::newFilterString(std::string const& _filter) int WebThreeStubServer::eth_newFilterString(std::string const& _filter)
{ {
unsigned ret = -1; unsigned ret = -1;
if (!client()) if (!client())
@ -500,14 +502,14 @@ int WebThreeStubServer::newFilterString(std::string const& _filter)
return ret; return ret;
} }
std::string WebThreeStubServer::newGroup(std::string const& _id, std::string const& _who) std::string WebThreeStubServer::shh_newGroup(std::string const& _id, std::string const& _who)
{ {
(void)_id; (void)_id;
(void)_who; (void)_who;
return ""; return "";
} }
std::string WebThreeStubServer::newIdentity() std::string WebThreeStubServer::shh_newIdentity()
{ {
cnote << this << m_ids; cnote << this << m_ids;
KeyPair kp = KeyPair::create(); KeyPair kp = KeyPair::create();
@ -515,22 +517,27 @@ std::string WebThreeStubServer::newIdentity()
return toJS(kp.pub()); return toJS(kp.pub());
} }
std::string WebThreeStubServer::compile(string const& _s) std::string WebThreeStubServer::eth_compile(string const& _s)
{
return toJS(dev::eth::compileLLL(_s));
}
std::string WebThreeStubServer::eth_lll(string const& _s)
{ {
return toJS(dev::eth::compileLLL(_s)); return toJS(dev::eth::compileLLL(_s));
} }
int WebThreeStubServer::number() int WebThreeStubServer::eth_number()
{ {
return client() ? client()->number() + 1 : 0; return client() ? client()->number() + 1 : 0;
} }
int WebThreeStubServer::peerCount() int WebThreeStubServer::eth_peerCount()
{ {
return m_web3.peerCount(); return m_web3.peerCount();
} }
bool WebThreeStubServer::post(Json::Value const& _json) bool WebThreeStubServer::shh_post(Json::Value const& _json)
{ {
cnote << this << m_ids; cnote << this << m_ids;
shh::Message m = toMessage(_json); shh::Message m = toMessage(_json);
@ -547,7 +554,7 @@ bool WebThreeStubServer::post(Json::Value const& _json)
return true; return true;
} }
bool WebThreeStubServer::put(std::string const& _name, std::string const& _key, std::string const& _value) bool WebThreeStubServer::db_put(std::string const& _name, std::string const& _key, std::string const& _value)
{ {
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
bytes v = jsToBytes(_value); bytes v = jsToBytes(_value);
@ -555,7 +562,7 @@ bool WebThreeStubServer::put(std::string const& _name, std::string const& _key,
return true; return true;
} }
bool WebThreeStubServer::putString(std::string const& _name, std::string const& _key, std::string const& _value) bool WebThreeStubServer::db_putString(std::string const& _name, std::string const& _key, std::string const& _value)
{ {
bytes k = sha3(_name).asBytes() + sha3(_key).asBytes(); bytes k = sha3(_name).asBytes() + sha3(_key).asBytes();
string v = _value; string v = _value;
@ -563,7 +570,7 @@ bool WebThreeStubServer::putString(std::string const& _name, std::string const&
return true; return true;
} }
bool WebThreeStubServer::setCoinbase(std::string const& _address) bool WebThreeStubServer::eth_setCoinbase(std::string const& _address)
{ {
if (!client()) if (!client())
return false; return false;
@ -571,7 +578,7 @@ bool WebThreeStubServer::setCoinbase(std::string const& _address)
return true; return true;
} }
bool WebThreeStubServer::setDefaultBlock(int const& _block) bool WebThreeStubServer::eth_setDefaultBlock(int const& _block)
{ {
if (!client()) if (!client())
return false; return false;
@ -579,7 +586,7 @@ bool WebThreeStubServer::setDefaultBlock(int const& _block)
return true; return true;
} }
bool WebThreeStubServer::setListening(bool const& _listening) bool WebThreeStubServer::eth_setListening(bool const& _listening)
{ {
if (_listening) if (_listening)
m_web3.startNetwork(); m_web3.startNetwork();
@ -588,7 +595,7 @@ bool WebThreeStubServer::setListening(bool const& _listening)
return true; return true;
} }
bool WebThreeStubServer::setMining(bool const& _mining) bool WebThreeStubServer::eth_setMining(bool const& _mining)
{ {
if (!client()) if (!client())
return false; return false;
@ -600,7 +607,7 @@ bool WebThreeStubServer::setMining(bool const& _mining)
return true; return true;
} }
Json::Value WebThreeStubServer::shhChanged(int const& _id) Json::Value WebThreeStubServer::shh_changed(int const& _id)
{ {
Json::Value ret(Json::arrayValue); Json::Value ret(Json::arrayValue);
auto pub = m_shhWatches[_id]; auto pub = m_shhWatches[_id];
@ -618,13 +625,13 @@ Json::Value WebThreeStubServer::shhChanged(int const& _id)
} }
else else
m = e.open(); m = e.open();
ret.append(toJson(h,e,m)); ret.append(toJson(h, e, m));
} }
return ret; return ret;
} }
int WebThreeStubServer::shhNewFilter(Json::Value const& _json) int WebThreeStubServer::shh_newFilter(Json::Value const& _json)
{ {
auto w = toWatch(_json); auto w = toWatch(_json);
auto ret = face()->installWatch(w.first); auto ret = face()->installWatch(w.first);
@ -632,19 +639,19 @@ int WebThreeStubServer::shhNewFilter(Json::Value const& _json)
return ret; return ret;
} }
bool WebThreeStubServer::shhUninstallFilter(int const& _id) bool WebThreeStubServer::shh_uninstallFilter(int const& _id)
{ {
face()->uninstallWatch(_id); face()->uninstallWatch(_id);
return true; return true;
} }
std::string WebThreeStubServer::stateAt(string const& _address, string const& _storage) std::string WebThreeStubServer::eth_stateAt(string const& _address, string const& _storage)
{ {
int block = 0; int block = 0;
return client() ? toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)) : ""; return client() ? toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)) : "";
} }
std::string WebThreeStubServer::transact(Json::Value const& _json) std::string WebThreeStubServer::eth_transact(Json::Value const& _json)
{ {
std::string ret; std::string ret;
if (!client()) if (!client())
@ -674,35 +681,35 @@ std::string WebThreeStubServer::transact(Json::Value const& _json)
return ret; return ret;
} }
Json::Value WebThreeStubServer::transactionByHash(std::string const& _hash, int const& _i) Json::Value WebThreeStubServer::eth_transactionByHash(std::string const& _hash, int const& _i)
{ {
if (!client()) if (!client())
return ""; return "";
return toJson(client()->transaction(jsToFixed<32>(_hash), _i)); return toJson(client()->transaction(jsToFixed<32>(_hash), _i));
} }
Json::Value WebThreeStubServer::transactionByNumber(int const& _number, int const& _i) Json::Value WebThreeStubServer::eth_transactionByNumber(int const& _number, int const& _i)
{ {
if (!client()) if (!client())
return ""; return "";
return toJson(client()->transaction(client()->hashFromNumber(_number), _i)); return toJson(client()->transaction(client()->hashFromNumber(_number), _i));
} }
Json::Value WebThreeStubServer::uncleByHash(std::string const& _hash, int const& _i) Json::Value WebThreeStubServer::eth_uncleByHash(std::string const& _hash, int const& _i)
{ {
if (!client()) if (!client())
return ""; return "";
return toJson(client()->uncle(jsToFixed<32>(_hash), _i)); return toJson(client()->uncle(jsToFixed<32>(_hash), _i));
} }
Json::Value WebThreeStubServer::uncleByNumber(int const& _number, int const& _i) Json::Value WebThreeStubServer::eth_uncleByNumber(int const& _number, int const& _i)
{ {
if (!client()) if (!client())
return ""; return "";
return toJson(client()->uncle(client()->hashFromNumber(_number), _i)); return toJson(client()->uncle(client()->hashFromNumber(_number), _i));
} }
bool WebThreeStubServer::uninstallFilter(int const& _id) bool WebThreeStubServer::eth_uninstallFilter(int const& _id)
{ {
if (!client()) if (!client())
return false; return false;

87
libweb3jsonrpc/WebThreeStubServer.h

@ -64,48 +64,51 @@ class WebThreeStubServer: public AbstractWebThreeStubServer
public: public:
WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts); WebThreeStubServer(jsonrpc::AbstractServerConnector* _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
virtual Json::Value accounts(); virtual Json::Value eth_accounts();
virtual std::string addToGroup(std::string const& _group, std::string const& _who); virtual std::string eth_balanceAt(std::string const& _address);
virtual std::string balanceAt(std::string const& _address); virtual Json::Value eth_blockByHash(std::string const& _hash);
virtual Json::Value blockByHash(std::string const& _hash); virtual Json::Value eth_blockByNumber(int const& _number);
virtual Json::Value blockByNumber(int const& _number); virtual std::string eth_call(Json::Value const& _json);
virtual std::string call(Json::Value const& _json); virtual bool eth_changed(int const& _id);
virtual bool changed(int const& _id); virtual std::string eth_codeAt(std::string const& _address);
virtual std::string codeAt(std::string const& _address); virtual std::string eth_coinbase();
virtual std::string coinbase(); virtual std::string eth_compile(std::string const& _s);
virtual std::string compile(std::string const& _s); virtual double eth_countAt(std::string const& _address);
virtual double countAt(std::string const& _address); virtual int eth_defaultBlock();
virtual int defaultBlock(); virtual std::string eth_gasPrice();
virtual std::string gasPrice(); virtual Json::Value eth_getMessages(int const& _id);
virtual std::string get(std::string const& _name, std::string const& _key); virtual bool eth_listening();
virtual Json::Value getMessages(int const& _id); virtual bool eth_mining();
virtual std::string getString(std::string const& _name, std::string const& _key); virtual int eth_newFilter(Json::Value const& _json);
virtual bool haveIdentity(std::string const& _id); virtual int eth_newFilterString(std::string const& _filter);
virtual bool listening(); virtual int eth_number();
virtual bool mining(); virtual int eth_peerCount();
virtual int newFilter(Json::Value const& _json); virtual bool eth_setCoinbase(std::string const& _address);
virtual int newFilterString(std::string const& _filter); virtual bool eth_setDefaultBlock(int const& _block);
virtual std::string newGroup(std::string const& _id, std::string const& _who); virtual bool eth_setListening(bool const& _listening);
virtual std::string newIdentity(); virtual std::string eth_lll(std::string const& _s);
virtual int number(); virtual bool eth_setMining(bool const& _mining);
virtual int peerCount(); virtual std::string eth_stateAt(std::string const& _address, std::string const& _storage);
virtual bool post(Json::Value const& _json); virtual std::string eth_transact(Json::Value const& _json);
virtual bool put(std::string const& _name, std::string const& _key, std::string const& _value); virtual Json::Value eth_transactionByHash(std::string const& _hash, int const& _i);
virtual bool putString(std::string const& _name, std::string const& _key, std::string const& _value); virtual Json::Value eth_transactionByNumber(int const& _number, int const& _i);
virtual bool setCoinbase(std::string const& _address); virtual Json::Value eth_uncleByHash(std::string const& _hash, int const& _i);
virtual bool setDefaultBlock(int const& _block); virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i);
virtual bool setListening(bool const& _listening); virtual bool eth_uninstallFilter(int const& _id);
virtual bool setMining(bool const& _mining);
virtual Json::Value shhChanged(int const& _id); virtual std::string db_get(std::string const& _name, std::string const& _key);
virtual int shhNewFilter(Json::Value const& _json); virtual std::string db_getString(std::string const& _name, std::string const& _key);
virtual bool shhUninstallFilter(int const& _id); virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value);
virtual std::string stateAt(std::string const& _address, std::string const& _storage); virtual bool db_putString(std::string const& _name, std::string const& _key, std::string const& _value);
virtual std::string transact(Json::Value const& _json);
virtual Json::Value transactionByHash(std::string const& _hash, int const& _i); virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who);
virtual Json::Value transactionByNumber(int const& _number, int const& _i); virtual Json::Value shh_changed(int const& _id);
virtual Json::Value uncleByHash(std::string const& _hash, int const& _i); virtual bool shh_haveIdentity(std::string const& _id);
virtual Json::Value uncleByNumber(int const& _number, int const& _i); virtual int shh_newFilter(Json::Value const& _json);
virtual bool uninstallFilter(int const& _id); virtual std::string shh_newGroup(std::string const& _id, std::string const& _who);
virtual std::string shh_newIdentity();
virtual bool shh_post(Json::Value const& _json);
virtual bool shh_uninstallFilter(int const& _id);
void setAccounts(std::vector<dev::KeyPair> const& _accounts); void setAccounts(std::vector<dev::KeyPair> const& _accounts);
void setIdentities(std::vector<dev::KeyPair> const& _ids); void setIdentities(std::vector<dev::KeyPair> const& _ids);

343
libweb3jsonrpc/abstractwebthreestubserver.h

@ -13,304 +13,311 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
AbstractWebThreeStubServer(jsonrpc::AbstractServerConnector* conn) : AbstractWebThreeStubServer(jsonrpc::AbstractServerConnector* conn) :
jsonrpc::AbstractServer<AbstractWebThreeStubServer>(conn) jsonrpc::AbstractServer<AbstractWebThreeStubServer>(conn)
{ {
this->bindAndAddMethod(new jsonrpc::Procedure("accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::accountsI); this->bindAndAddMethod(new jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI);
this->bindAndAddMethod(new jsonrpc::Procedure("addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::addToGroupI); this->bindAndAddMethod(new jsonrpc::Procedure("db_getString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::balanceAtI); this->bindAndAddMethod(new jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI);
this->bindAndAddMethod(new jsonrpc::Procedure("blockByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::blockByHashI); this->bindAndAddMethod(new jsonrpc::Procedure("db_putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("blockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::blockByNumberI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_accounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_accountsI);
this->bindAndAddMethod(new jsonrpc::Procedure("call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::callI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_balanceAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_balanceAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::changedI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_blockByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_blockByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::codeAtI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_blockByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_blockByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::coinbaseI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_callI);
this->bindAndAddMethod(new jsonrpc::Procedure("compile", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::compileI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_changedI);
this->bindAndAddMethod(new jsonrpc::Procedure("countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::countAtI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_codeAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("defaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::defaultBlockI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_coinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_coinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::gasPriceI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_compile", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileI);
this->bindAndAddMethod(new jsonrpc::Procedure("get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::getI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_countAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::getMessagesI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_defaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_defaultBlockI);
this->bindAndAddMethod(new jsonrpc::Procedure("getString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::getStringI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_gasPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_gasPriceI);
this->bindAndAddMethod(new jsonrpc::Procedure("haveIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::haveIdentityI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_getMessagesI);
this->bindAndAddMethod(new jsonrpc::Procedure("listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::listeningI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_listening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_listeningI);
this->bindAndAddMethod(new jsonrpc::Procedure("mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::miningI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_lll", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_lllI);
this->bindAndAddMethod(new jsonrpc::Procedure("newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::newFilterI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_mining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_miningI);
this->bindAndAddMethod(new jsonrpc::Procedure("newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newFilterStringI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("newGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newGroupI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_newFilterString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newFilterStringI);
this->bindAndAddMethod(new jsonrpc::Procedure("newIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::newIdentityI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_number", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_numberI);
this->bindAndAddMethod(new jsonrpc::Procedure("number", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::numberI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_peerCountI);
this->bindAndAddMethod(new jsonrpc::Procedure("peerCount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::peerCountI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_setCoinbaseI);
this->bindAndAddMethod(new jsonrpc::Procedure("post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::postI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_setDefaultBlockI);
this->bindAndAddMethod(new jsonrpc::Procedure("put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::putI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setListeningI);
this->bindAndAddMethod(new jsonrpc::Procedure("putString", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::putStringI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::eth_setMiningI);
this->bindAndAddMethod(new jsonrpc::Procedure("setCoinbase", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::setCoinbaseI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_stateAtI);
this->bindAndAddMethod(new jsonrpc::Procedure("setDefaultBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::setDefaultBlockI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_transactI);
this->bindAndAddMethod(new jsonrpc::Procedure("setListening", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setListeningI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN, NULL), &AbstractWebThreeStubServer::setMiningI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_transactionByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("shhChanged", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhChangedI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_uncleByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByHashI);
this->bindAndAddMethod(new jsonrpc::Procedure("shhNewFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shhNewFilterI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_uncleByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleByNumberI);
this->bindAndAddMethod(new jsonrpc::Procedure("shhUninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shhUninstallFilterI); this->bindAndAddMethod(new jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::stateAtI); this->bindAndAddMethod(new jsonrpc::Procedure("shh_addToGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_addToGroupI);
this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::transactI); this->bindAndAddMethod(new jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI);
this->bindAndAddMethod(new jsonrpc::Procedure("transactionByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::transactionByHashI); this->bindAndAddMethod(new jsonrpc::Procedure("shh_haveIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_haveIdentityI);
this->bindAndAddMethod(new jsonrpc::Procedure("transactionByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::transactionByNumberI); this->bindAndAddMethod(new jsonrpc::Procedure("shh_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_newFilterI);
this->bindAndAddMethod(new jsonrpc::Procedure("uncleByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uncleByHashI); this->bindAndAddMethod(new jsonrpc::Procedure("shh_newGroup", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newGroupI);
this->bindAndAddMethod(new jsonrpc::Procedure("uncleByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uncleByNumberI); this->bindAndAddMethod(new jsonrpc::Procedure("shh_newIdentity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_newIdentityI);
this->bindAndAddMethod(new jsonrpc::Procedure("uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::uninstallFilterI); this->bindAndAddMethod(new jsonrpc::Procedure("shh_post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_postI);
this->bindAndAddMethod(new jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI);
} }
inline virtual void accountsI(const Json::Value& request, Json::Value& response) inline virtual void db_getI(const Json::Value& request, Json::Value& response)
{ {
response = this->accounts(); response = this->db_get(request[0u].asString(), request[1u].asString());
} }
inline virtual void addToGroupI(const Json::Value& request, Json::Value& response) inline virtual void db_getStringI(const Json::Value& request, Json::Value& response)
{ {
response = this->addToGroup(request[0u].asString(), request[1u].asString()); response = this->db_getString(request[0u].asString(), request[1u].asString());
} }
inline virtual void balanceAtI(const Json::Value& request, Json::Value& response) inline virtual void db_putI(const Json::Value& request, Json::Value& response)
{ {
response = this->balanceAt(request[0u].asString()); response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString());
} }
inline virtual void blockByHashI(const Json::Value& request, Json::Value& response) inline virtual void db_putStringI(const Json::Value& request, Json::Value& response)
{ {
response = this->blockByHash(request[0u].asString()); response = this->db_putString(request[0u].asString(), request[1u].asString(), request[2u].asString());
} }
inline virtual void blockByNumberI(const Json::Value& request, Json::Value& response) inline virtual void eth_accountsI(const Json::Value& request, Json::Value& response)
{ {
response = this->blockByNumber(request[0u].asInt()); response = this->eth_accounts();
} }
inline virtual void callI(const Json::Value& request, Json::Value& response) inline virtual void eth_balanceAtI(const Json::Value& request, Json::Value& response)
{ {
response = this->call(request[0u]); response = this->eth_balanceAt(request[0u].asString());
} }
inline virtual void changedI(const Json::Value& request, Json::Value& response) inline virtual void eth_blockByHashI(const Json::Value& request, Json::Value& response)
{ {
response = this->changed(request[0u].asInt()); response = this->eth_blockByHash(request[0u].asString());
} }
inline virtual void codeAtI(const Json::Value& request, Json::Value& response) inline virtual void eth_blockByNumberI(const Json::Value& request, Json::Value& response)
{ {
response = this->codeAt(request[0u].asString()); response = this->eth_blockByNumber(request[0u].asInt());
} }
inline virtual void coinbaseI(const Json::Value& request, Json::Value& response) inline virtual void eth_callI(const Json::Value& request, Json::Value& response)
{ {
response = this->coinbase(); response = this->eth_call(request[0u]);
} }
inline virtual void compileI(const Json::Value& request, Json::Value& response) inline virtual void eth_changedI(const Json::Value& request, Json::Value& response)
{ {
response = this->compile(request[0u].asString()); response = this->eth_changed(request[0u].asInt());
} }
inline virtual void countAtI(const Json::Value& request, Json::Value& response) inline virtual void eth_codeAtI(const Json::Value& request, Json::Value& response)
{ {
response = this->countAt(request[0u].asString()); response = this->eth_codeAt(request[0u].asString());
} }
inline virtual void defaultBlockI(const Json::Value& request, Json::Value& response) inline virtual void eth_coinbaseI(const Json::Value& request, Json::Value& response)
{ {
response = this->defaultBlock(); response = this->eth_coinbase();
} }
inline virtual void gasPriceI(const Json::Value& request, Json::Value& response) inline virtual void eth_compileI(const Json::Value& request, Json::Value& response)
{ {
response = this->gasPrice(); response = this->eth_compile(request[0u].asString());
} }
inline virtual void getI(const Json::Value& request, Json::Value& response) inline virtual void eth_countAtI(const Json::Value& request, Json::Value& response)
{ {
response = this->get(request[0u].asString(), request[1u].asString()); response = this->eth_countAt(request[0u].asString());
} }
inline virtual void getMessagesI(const Json::Value& request, Json::Value& response) inline virtual void eth_defaultBlockI(const Json::Value& request, Json::Value& response)
{ {
response = this->getMessages(request[0u].asInt()); response = this->eth_defaultBlock();
} }
inline virtual void getStringI(const Json::Value& request, Json::Value& response) inline virtual void eth_gasPriceI(const Json::Value& request, Json::Value& response)
{ {
response = this->getString(request[0u].asString(), request[1u].asString()); response = this->eth_gasPrice();
} }
inline virtual void haveIdentityI(const Json::Value& request, Json::Value& response) inline virtual void eth_getMessagesI(const Json::Value& request, Json::Value& response)
{ {
response = this->haveIdentity(request[0u].asString()); response = this->eth_getMessages(request[0u].asInt());
} }
inline virtual void listeningI(const Json::Value& request, Json::Value& response) inline virtual void eth_listeningI(const Json::Value& request, Json::Value& response)
{ {
response = this->listening(); response = this->eth_listening();
} }
inline virtual void miningI(const Json::Value& request, Json::Value& response) inline virtual void eth_lllI(const Json::Value& request, Json::Value& response)
{ {
response = this->mining(); response = this->eth_lll(request[0u].asString());
} }
inline virtual void newFilterI(const Json::Value& request, Json::Value& response) inline virtual void eth_miningI(const Json::Value& request, Json::Value& response)
{ {
response = this->newFilter(request[0u]); response = this->eth_mining();
} }
inline virtual void newFilterStringI(const Json::Value& request, Json::Value& response) inline virtual void eth_newFilterI(const Json::Value& request, Json::Value& response)
{ {
response = this->newFilterString(request[0u].asString()); response = this->eth_newFilter(request[0u]);
} }
inline virtual void newGroupI(const Json::Value& request, Json::Value& response) inline virtual void eth_newFilterStringI(const Json::Value& request, Json::Value& response)
{ {
response = this->newGroup(request[0u].asString(), request[1u].asString()); response = this->eth_newFilterString(request[0u].asString());
} }
inline virtual void newIdentityI(const Json::Value& request, Json::Value& response) inline virtual void eth_numberI(const Json::Value& request, Json::Value& response)
{ {
response = this->newIdentity(); response = this->eth_number();
} }
inline virtual void numberI(const Json::Value& request, Json::Value& response) inline virtual void eth_peerCountI(const Json::Value& request, Json::Value& response)
{ {
response = this->number(); response = this->eth_peerCount();
} }
inline virtual void peerCountI(const Json::Value& request, Json::Value& response) inline virtual void eth_setCoinbaseI(const Json::Value& request, Json::Value& response)
{ {
response = this->peerCount(); response = this->eth_setCoinbase(request[0u].asString());
} }
inline virtual void postI(const Json::Value& request, Json::Value& response) inline virtual void eth_setDefaultBlockI(const Json::Value& request, Json::Value& response)
{ {
response = this->post(request[0u]); response = this->eth_setDefaultBlock(request[0u].asInt());
} }
inline virtual void putI(const Json::Value& request, Json::Value& response) inline virtual void eth_setListeningI(const Json::Value& request, Json::Value& response)
{ {
response = this->put(request[0u].asString(), request[1u].asString(), request[2u].asString()); response = this->eth_setListening(request[0u].asBool());
} }
inline virtual void putStringI(const Json::Value& request, Json::Value& response) inline virtual void eth_setMiningI(const Json::Value& request, Json::Value& response)
{ {
response = this->putString(request[0u].asString(), request[1u].asString(), request[2u].asString()); response = this->eth_setMining(request[0u].asBool());
} }
inline virtual void setCoinbaseI(const Json::Value& request, Json::Value& response) inline virtual void eth_stateAtI(const Json::Value& request, Json::Value& response)
{ {
response = this->setCoinbase(request[0u].asString()); response = this->eth_stateAt(request[0u].asString(), request[1u].asString());
} }
inline virtual void setDefaultBlockI(const Json::Value& request, Json::Value& response) inline virtual void eth_transactI(const Json::Value& request, Json::Value& response)
{ {
response = this->setDefaultBlock(request[0u].asInt()); response = this->eth_transact(request[0u]);
} }
inline virtual void setListeningI(const Json::Value& request, Json::Value& response) inline virtual void eth_transactionByHashI(const Json::Value& request, Json::Value& response)
{ {
response = this->setListening(request[0u].asBool()); response = this->eth_transactionByHash(request[0u].asString(), request[1u].asInt());
} }
inline virtual void setMiningI(const Json::Value& request, Json::Value& response) inline virtual void eth_transactionByNumberI(const Json::Value& request, Json::Value& response)
{ {
response = this->setMining(request[0u].asBool()); response = this->eth_transactionByNumber(request[0u].asInt(), request[1u].asInt());
} }
inline virtual void shhChangedI(const Json::Value& request, Json::Value& response) inline virtual void eth_uncleByHashI(const Json::Value& request, Json::Value& response)
{ {
response = this->shhChanged(request[0u].asInt()); response = this->eth_uncleByHash(request[0u].asString(), request[1u].asInt());
} }
inline virtual void shhNewFilterI(const Json::Value& request, Json::Value& response) inline virtual void eth_uncleByNumberI(const Json::Value& request, Json::Value& response)
{ {
response = this->shhNewFilter(request[0u]); response = this->eth_uncleByNumber(request[0u].asInt(), request[1u].asInt());
} }
inline virtual void shhUninstallFilterI(const Json::Value& request, Json::Value& response) inline virtual void eth_uninstallFilterI(const Json::Value& request, Json::Value& response)
{ {
response = this->shhUninstallFilter(request[0u].asInt()); response = this->eth_uninstallFilter(request[0u].asInt());
} }
inline virtual void stateAtI(const Json::Value& request, Json::Value& response) inline virtual void shh_addToGroupI(const Json::Value& request, Json::Value& response)
{ {
response = this->stateAt(request[0u].asString(), request[1u].asString()); response = this->shh_addToGroup(request[0u].asString(), request[1u].asString());
} }
inline virtual void transactI(const Json::Value& request, Json::Value& response) inline virtual void shh_changedI(const Json::Value& request, Json::Value& response)
{ {
response = this->transact(request[0u]); response = this->shh_changed(request[0u].asInt());
} }
inline virtual void transactionByHashI(const Json::Value& request, Json::Value& response) inline virtual void shh_haveIdentityI(const Json::Value& request, Json::Value& response)
{ {
response = this->transactionByHash(request[0u].asString(), request[1u].asInt()); response = this->shh_haveIdentity(request[0u].asString());
} }
inline virtual void transactionByNumberI(const Json::Value& request, Json::Value& response) inline virtual void shh_newFilterI(const Json::Value& request, Json::Value& response)
{ {
response = this->transactionByNumber(request[0u].asInt(), request[1u].asInt()); response = this->shh_newFilter(request[0u]);
} }
inline virtual void uncleByHashI(const Json::Value& request, Json::Value& response) inline virtual void shh_newGroupI(const Json::Value& request, Json::Value& response)
{ {
response = this->uncleByHash(request[0u].asString(), request[1u].asInt()); response = this->shh_newGroup(request[0u].asString(), request[1u].asString());
} }
inline virtual void uncleByNumberI(const Json::Value& request, Json::Value& response) inline virtual void shh_newIdentityI(const Json::Value& request, Json::Value& response)
{ {
response = this->uncleByNumber(request[0u].asInt(), request[1u].asInt()); response = this->shh_newIdentity();
} }
inline virtual void uninstallFilterI(const Json::Value& request, Json::Value& response) inline virtual void shh_postI(const Json::Value& request, Json::Value& response)
{ {
response = this->uninstallFilter(request[0u].asInt()); response = this->shh_post(request[0u]);
}
inline virtual void shh_uninstallFilterI(const Json::Value& request, Json::Value& response)
{
response = this->shh_uninstallFilter(request[0u].asInt());
} }
virtual Json::Value accounts() = 0; virtual std::string db_get(const std::string& param1, const std::string& param2) = 0;
virtual std::string addToGroup(const std::string& param1, const std::string& param2) = 0; virtual std::string db_getString(const std::string& param1, const std::string& param2) = 0;
virtual std::string balanceAt(const std::string& param1) = 0; virtual bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual Json::Value blockByHash(const std::string& param1) = 0; virtual bool db_putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0;
virtual Json::Value blockByNumber(const int& param1) = 0; virtual Json::Value eth_accounts() = 0;
virtual std::string call(const Json::Value& param1) = 0; virtual std::string eth_balanceAt(const std::string& param1) = 0;
virtual bool changed(const int& param1) = 0; virtual Json::Value eth_blockByHash(const std::string& param1) = 0;
virtual std::string codeAt(const std::string& param1) = 0; virtual Json::Value eth_blockByNumber(const int& param1) = 0;
virtual std::string coinbase() = 0; virtual std::string eth_call(const Json::Value& param1) = 0;
virtual std::string compile(const std::string& param1) = 0; virtual bool eth_changed(const int& param1) = 0;
virtual double countAt(const std::string& param1) = 0; virtual std::string eth_codeAt(const std::string& param1) = 0;
virtual int defaultBlock() = 0; virtual std::string eth_coinbase() = 0;
virtual std::string gasPrice() = 0; virtual std::string eth_compile(const std::string& param1) = 0;
virtual std::string get(const std::string& param1, const std::string& param2) = 0; virtual double eth_countAt(const std::string& param1) = 0;
virtual Json::Value getMessages(const int& param1) = 0; virtual int eth_defaultBlock() = 0;
virtual std::string getString(const std::string& param1, const std::string& param2) = 0; virtual std::string eth_gasPrice() = 0;
virtual bool haveIdentity(const std::string& param1) = 0; virtual Json::Value eth_getMessages(const int& param1) = 0;
virtual bool listening() = 0; virtual bool eth_listening() = 0;
virtual bool mining() = 0; virtual std::string eth_lll(const std::string& param1) = 0;
virtual int newFilter(const Json::Value& param1) = 0; virtual bool eth_mining() = 0;
virtual int newFilterString(const std::string& param1) = 0; virtual int eth_newFilter(const Json::Value& param1) = 0;
virtual std::string newGroup(const std::string& param1, const std::string& param2) = 0; virtual int eth_newFilterString(const std::string& param1) = 0;
virtual std::string newIdentity() = 0; virtual int eth_number() = 0;
virtual int number() = 0; virtual int eth_peerCount() = 0;
virtual int peerCount() = 0; virtual bool eth_setCoinbase(const std::string& param1) = 0;
virtual bool post(const Json::Value& param1) = 0; virtual bool eth_setDefaultBlock(const int& param1) = 0;
virtual bool put(const std::string& param1, const std::string& param2, const std::string& param3) = 0; virtual bool eth_setListening(const bool& param1) = 0;
virtual bool putString(const std::string& param1, const std::string& param2, const std::string& param3) = 0; virtual bool eth_setMining(const bool& param1) = 0;
virtual bool setCoinbase(const std::string& param1) = 0; virtual std::string eth_stateAt(const std::string& param1, const std::string& param2) = 0;
virtual bool setDefaultBlock(const int& param1) = 0; virtual std::string eth_transact(const Json::Value& param1) = 0;
virtual bool setListening(const bool& param1) = 0; virtual Json::Value eth_transactionByHash(const std::string& param1, const int& param2) = 0;
virtual bool setMining(const bool& param1) = 0; virtual Json::Value eth_transactionByNumber(const int& param1, const int& param2) = 0;
virtual Json::Value shhChanged(const int& param1) = 0; virtual Json::Value eth_uncleByHash(const std::string& param1, const int& param2) = 0;
virtual int shhNewFilter(const Json::Value& param1) = 0; virtual Json::Value eth_uncleByNumber(const int& param1, const int& param2) = 0;
virtual bool shhUninstallFilter(const int& param1) = 0; virtual bool eth_uninstallFilter(const int& param1) = 0;
virtual std::string stateAt(const std::string& param1, const std::string& param2) = 0; virtual std::string shh_addToGroup(const std::string& param1, const std::string& param2) = 0;
virtual std::string transact(const Json::Value& param1) = 0; virtual Json::Value shh_changed(const int& param1) = 0;
virtual Json::Value transactionByHash(const std::string& param1, const int& param2) = 0; virtual bool shh_haveIdentity(const std::string& param1) = 0;
virtual Json::Value transactionByNumber(const int& param1, const int& param2) = 0; virtual int shh_newFilter(const Json::Value& param1) = 0;
virtual Json::Value uncleByHash(const std::string& param1, const int& param2) = 0; virtual std::string shh_newGroup(const std::string& param1, const std::string& param2) = 0;
virtual Json::Value uncleByNumber(const int& param1, const int& param2) = 0; virtual std::string shh_newIdentity() = 0;
virtual bool uninstallFilter(const int& param1) = 0; virtual bool shh_post(const Json::Value& param1) = 0;
virtual bool shh_uninstallFilter(const int& param1) = 0;
}; };
#endif //_ABSTRACTWEBTHREESTUBSERVER_H_ #endif //_ABSTRACTWEBTHREESTUBSERVER_H_

101
libweb3jsonrpc/spec.json

@ -1,54 +1,55 @@
[ [
{ "method": "coinbase", "params": [], "order": [], "returns" : "" }, { "method": "eth_coinbase", "params": [], "order": [], "returns" : "" },
{ "method": "setCoinbase", "params": [""], "order": [], "returns" : true }, { "method": "eth_setCoinbase", "params": [""], "order": [], "returns" : true },
{ "method": "listening", "params": [], "order": [], "returns" : false }, { "method": "eth_listening", "params": [], "order": [], "returns" : false },
{ "method": "setListening", "params": [false], "order" : [], "returns" : true }, { "method": "eth_setListening", "params": [false], "order" : [], "returns" : true },
{ "method": "mining", "params": [], "order": [], "returns" : false }, { "method": "eth_mining", "params": [], "order": [], "returns" : false },
{ "method": "setMining", "params": [false], "order" : [], "returns" : true }, { "method": "eth_setMining", "params": [false], "order" : [], "returns" : true },
{ "method": "gasPrice", "params": [], "order": [], "returns" : "" }, { "method": "eth_gasPrice", "params": [], "order": [], "returns" : "" },
{ "method": "accounts", "params": [], "order": [], "returns" : [] }, { "method": "eth_accounts", "params": [], "order": [], "returns" : [] },
{ "method": "peerCount", "params": [], "order": [], "returns" : 0 }, { "method": "eth_peerCount", "params": [], "order": [], "returns" : 0 },
{ "method": "defaultBlock", "params": [], "order": [], "returns" : 0}, { "method": "eth_defaultBlock", "params": [], "order": [], "returns" : 0},
{ "method": "setDefaultBlock", "params": [0], "order": [], "returns" : true}, { "method": "eth_setDefaultBlock", "params": [0], "order": [], "returns" : true},
{ "method": "number", "params": [], "order": [], "returns" : 0}, { "method": "eth_number", "params": [], "order": [], "returns" : 0},
{ "method": "balanceAt", "params": [""], "order": [], "returns" : ""}, { "method": "eth_balanceAt", "params": [""], "order": [], "returns" : ""},
{ "method": "stateAt", "params": ["", ""], "order": [], "returns": ""}, { "method": "eth_stateAt", "params": ["", ""], "order": [], "returns": ""},
{ "method": "countAt", "params": [""], "order": [], "returns" : 0.0}, { "method": "eth_countAt", "params": [""], "order": [], "returns" : 0.0},
{ "method": "codeAt", "params": [""], "order": [], "returns": ""}, { "method": "eth_codeAt", "params": [""], "order": [], "returns": ""},
{ "method": "transact", "params": [{}], "order": [], "returns": ""}, { "method": "eth_transact", "params": [{}], "order": [], "returns": ""},
{ "method": "call", "params": [{}], "order": [], "returns": ""}, { "method": "eth_call", "params": [{}], "order": [], "returns": ""},
{ "method": "blockByHash", "params": [""],"order": [], "returns": {}}, { "method": "eth_blockByHash", "params": [""],"order": [], "returns": {}},
{ "method": "blockByNumber", "params": [0],"order": [], "returns": {}}, { "method": "eth_blockByNumber", "params": [0],"order": [], "returns": {}},
{ "method": "transactionByHash", "params": ["", 0], "order": [], "returns": {}}, { "method": "eth_transactionByHash", "params": ["", 0], "order": [], "returns": {}},
{ "method": "transactionByNumber", "params": [0, 0], "order": [], "returns": {}}, { "method": "eth_transactionByNumber", "params": [0, 0], "order": [], "returns": {}},
{ "method": "uncleByHash", "params": ["", 0], "order": [], "returns": {}}, { "method": "eth_uncleByHash", "params": ["", 0], "order": [], "returns": {}},
{ "method": "uncleByNumber", "params": [0, 0], "order": [], "returns": {}}, { "method": "eth_uncleByNumber", "params": [0, 0], "order": [], "returns": {}},
{ "method": "compile", "params": [""], "order": [], "returns": ""}, { "method": "eth_lll", "params": [""], "order": [], "returns": ""},
{ "method": "eth_compile", "params": [""], "order": [], "returns": ""},
{ "method": "newFilter", "params": [{}], "order": [], "returns": 0},
{ "method": "newFilterString", "params": [""], "order": [], "returns": 0}, { "method": "eth_newFilter", "params": [{}], "order": [], "returns": 0},
{ "method": "uninstallFilter", "params": [0], "order": [], "returns": true}, { "method": "eth_newFilterString", "params": [""], "order": [], "returns": 0},
{ "method": "changed", "params": [0], "order": [], "returns": false}, { "method": "eth_uninstallFilter", "params": [0], "order": [], "returns": true},
{ "method": "getMessages", "params": [0], "order": [], "returns": []}, { "method": "eth_changed", "params": [0], "order": [], "returns": false},
{ "method": "eth_getMessages", "params": [0], "order": [], "returns": []},
{ "method": "put", "params": ["", "", ""], "order": [], "returns": true},
{ "method": "get", "params": ["", ""], "order": [], "returns": ""}, { "method": "db_put", "params": ["", "", ""], "order": [], "returns": true},
{ "method": "putString", "params": ["", "", ""], "order": [], "returns": true}, { "method": "db_get", "params": ["", ""], "order": [], "returns": ""},
{ "method": "getString", "params": ["", ""], "order": [], "returns": ""}, { "method": "db_putString", "params": ["", "", ""], "order": [], "returns": true},
{ "method": "db_getString", "params": ["", ""], "order": [], "returns": ""},
{ "method": "post", "params": [{}], "order": [], "returns": true},
{ "method": "newIdentity", "params": [], "order": [], "returns": ""}, { "method": "shh_post", "params": [{}], "order": [], "returns": true},
{ "method": "haveIdentity", "params": [""], "order": [], "returns": false}, { "method": "shh_newIdentity", "params": [], "order": [], "returns": ""},
{ "method": "newGroup", "params": ["", ""], "order": [], "returns": ""}, { "method": "shh_haveIdentity", "params": [""], "order": [], "returns": false},
{ "method": "addToGroup", "params": ["", ""], "order": [], "returns": ""}, { "method": "shh_newGroup", "params": ["", ""], "order": [], "returns": ""},
{ "method": "shh_addToGroup", "params": ["", ""], "order": [], "returns": ""},
{ "method": "shhNewFilter", "params": [{}], "order": [], "returns": 0},
{ "method": "shhUninstallFilter", "params": [0], "order": [], "returns": true}, { "method": "shh_newFilter", "params": [{}], "order": [], "returns": 0},
{ "method": "shhChanged", "params": [0], "order": [], "returns": []} { "method": "shh_uninstallFilter", "params": [0], "order": [], "returns": true},
{ "method": "shh_changed", "params": [0], "order": [], "returns": []}
] ]

35
libwhisper/Common.cpp

@ -22,11 +22,21 @@
#include "Common.h" #include "Common.h"
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include "Message.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::p2p; using namespace dev::p2p;
using namespace dev::shh; using namespace dev::shh;
Topic BuildTopic::toTopic() const
{
Topic ret;
ret.reserve(m_parts.size());
for (auto const& h: m_parts)
ret.push_back(TopicPart(h));
return ret;
}
BuildTopic& BuildTopic::shiftBytes(bytes const& _b) BuildTopic& BuildTopic::shiftBytes(bytes const& _b)
{ {
m_parts.push_back(dev::sha3(_b)); m_parts.push_back(dev::sha3(_b));
@ -40,19 +50,32 @@ h256 TopicFilter::sha3() const
return dev::sha3(s.out()); return dev::sha3(s.out());
} }
TopicMask BuildTopicMask::toTopicMask() const bool TopicFilter::matches(Envelope const& _e) const
{ {
TopicMask ret; for (TopicMask const& t: m_topicMasks)
if (m_parts.size())
for (auto i = 0; i < 32; ++i)
{ {
ret.first[i] = m_parts[i * m_parts.size() / 32][i]; if (_e.topics().size() == t.size())
ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; for (unsigned i = 0; i < t.size(); ++i)
if (((t[i].first ^ _e.topics()[i]) & t[i].second) != 0)
goto NEXT_TOPICMASK;
return true;
NEXT_TOPICMASK:;
} }
return false;
}
TopicMask BuildTopicMask::toTopicMask() const
{
TopicMask ret;
ret.reserve(m_parts.size());
for (auto const& h: m_parts)
ret.push_back(make_pair(TopicPart(h), h ? ~TopicPart() : TopicPart()));
return ret; return ret;
} }
/* /*
web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); }) web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); })
k = web3.shh.newIdentity() k = web3.shh.newIdentity()
web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")})
*/ */

18
libwhisper/Common.h

@ -59,7 +59,9 @@ enum WhisperPacket
PacketCount PacketCount
}; };
using Topic = h256; using TopicPart = FixedHash<4>;
using Topic = std::vector<TopicPart>;
class BuildTopic class BuildTopic
{ {
@ -73,7 +75,7 @@ public:
BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; } BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; }
operator Topic() const { return toTopic(); } operator Topic() const { return toTopic(); }
Topic toTopic() const { Topic ret; for (auto i = 0; i < 32; ++i) ret[i] = m_parts[i * m_parts.size() / 32][i]; return ret; } Topic toTopic() const;
protected: protected:
BuildTopic& shiftBytes(bytes const& _b); BuildTopic& shiftBytes(bytes const& _b);
@ -81,7 +83,7 @@ protected:
h256s m_parts; h256s m_parts;
}; };
using TopicMask = std::pair<Topic, Topic>; using TopicMask = std::vector<std::pair<TopicPart, TopicPart>>;
using TopicMasks = std::vector<TopicMask>; using TopicMasks = std::vector<TopicMask>;
class TopicFilter class TopicFilter
@ -90,7 +92,15 @@ public:
TopicFilter() {} TopicFilter() {}
TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {} TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {}
TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {}
TopicFilter(RLP const& _r): m_topicMasks((TopicMasks)_r) {} TopicFilter(RLP const& _r)//: m_topicMasks(_r.toVector<std::vector<>>())
{
for (RLP i: _r)
{
m_topicMasks.push_back(TopicMask());
for (RLP j: i)
m_topicMasks.back().push_back(j.toPair<FixedHash<4>, FixedHash<4>>());
}
}
void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } void streamRLP(RLPStream& _s) const { _s << m_topicMasks; }
h256 sha3() const; h256 sha3() const;

7
libwhisper/Interface.cpp

@ -34,10 +34,7 @@ using namespace dev::shh;
#endif #endif
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] " #define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
bool TopicFilter::matches(Envelope const& _e) const unsigned Interface::installWatch(TopicMask const& _mask)
{ {
for (TopicMask const& t: m_topicMasks) return installWatch(TopicFilter(_mask));
if (((t.first ^ _e.topic()) & t.second) == 0)
return true;
return false;
} }

2
libwhisper/Interface.h

@ -69,7 +69,7 @@ public:
virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0;
unsigned installWatch(TopicMask const& _mask) { return installWatch(TopicFilter(_mask)); } unsigned installWatch(TopicMask const& _mask);
virtual unsigned installWatch(TopicFilter const& _filter) = 0; virtual unsigned installWatch(TopicFilter const& _filter) = 0;
virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual unsigned installWatchOnId(h256 _filterId) = 0;
virtual void uninstallWatch(unsigned _watchId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0;

4
libwhisper/Message.cpp

@ -97,7 +97,7 @@ Message Envelope::open(Secret const& _s) const
unsigned Envelope::workProved() const unsigned Envelope::workProved() const
{ {
h256 d[2]; h256 d[2];
d[0] = sha3NoNonce(); d[0] = sha3(WithoutNonce);
d[1] = m_nonce; d[1] = m_nonce;
return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet(); return dev::sha3(bytesConstRef(d[0].data(), 64)).firstBitSet();
} }
@ -106,7 +106,7 @@ void Envelope::proveWork(unsigned _ms)
{ {
// PoW // PoW
h256 d[2]; h256 d[2];
d[0] = sha3NoNonce(); d[0] = sha3(WithoutNonce);
uint32_t& n = *(uint32_t*)&(d[1][28]); uint32_t& n = *(uint32_t*)&(d[1][28]);
unsigned bestBitSet = 0; unsigned bestBitSet = 0;
bytesConstRef chuck(d[0].data(), 64); bytesConstRef chuck(d[0].data(), 64);

15
libwhisper/Message.h

@ -39,6 +39,12 @@ namespace shh
class Message; class Message;
enum IncludeNonce
{
WithoutNonce = 0,
WithNonce = 1
};
class Envelope class Envelope
{ {
friend class Message; friend class Message;
@ -49,21 +55,20 @@ public:
{ {
m_expiry = _m[0].toInt<unsigned>(); m_expiry = _m[0].toInt<unsigned>();
m_ttl = _m[1].toInt<unsigned>(); m_ttl = _m[1].toInt<unsigned>();
m_topic = (Topic)_m[2]; m_topic = _m[2].toVector<FixedHash<4>>();
m_data = _m[3].toBytes(); m_data = _m[3].toBytes();
m_nonce = _m[4].toInt<u256>(); m_nonce = _m[4].toInt<u256>();
} }
operator bool() const { return !!m_expiry; } operator bool() const { return !!m_expiry; }
void streamRLP(RLPStream& _s, bool _withNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; } void streamRLP(RLPStream& _s, IncludeNonce _withNonce = WithNonce) const { _s.appendList(_withNonce ? 5 : 4) << m_expiry << m_ttl << m_topic << m_data; if (_withNonce) _s << m_nonce; }
h256 sha3() const { RLPStream s; streamRLP(s, true); return dev::sha3(s.out()); } h256 sha3(IncludeNonce _withNonce = WithNonce) const { RLPStream s; streamRLP(s, _withNonce); return dev::sha3(s.out()); }
h256 sha3NoNonce() const { RLPStream s; streamRLP(s, false); return dev::sha3(s.out()); }
unsigned sent() const { return m_expiry - m_ttl; } unsigned sent() const { return m_expiry - m_ttl; }
unsigned expiry() const { return m_expiry; } unsigned expiry() const { return m_expiry; }
unsigned ttl() const { return m_ttl; } unsigned ttl() const { return m_ttl; }
Topic const& topic() const { return m_topic; } Topic const& topics() const { return m_topic; }
bytes const& data() const { return m_data; } bytes const& data() const { return m_data; }
Message open(Secret const& _s = Secret()) const; Message open(Secret const& _s = Secret()) const;

7
libwhisper/WhisperHost.cpp

@ -21,6 +21,7 @@
#include "WhisperHost.h" #include "WhisperHost.h"
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libp2p/All.h> #include <libp2p/All.h>
using namespace std; using namespace std;
@ -48,14 +49,14 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const
{ {
UpgradeGuard ll(l); UpgradeGuard ll(l);
auto const& m = m_messages.at(_m); auto const& m = m_messages.at(_m);
cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); cnote << "streamRLP: " << m.expiry() << m.ttl() << m.topics() << toHex(m.data());
m.streamRLP(_s, true); m.streamRLP(_s);
} }
} }
void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p)
{ {
cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data()); cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topics() << toHex(_m.data());
if (_m.expiry() <= time(0)) if (_m.expiry() <= time(0))
return; return;

2
libwhisper/WhisperHost.h

@ -46,7 +46,7 @@ public:
WhisperHost(); WhisperHost();
virtual ~WhisperHost(); virtual ~WhisperHost();
unsigned protocolVersion() const { return 0; } unsigned protocolVersion() const { return 1; }
virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override;

4
libwhisper/WhisperPeer.cpp

@ -37,7 +37,7 @@ using namespace dev::shh;
WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i) WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i)
{ {
RLPStream s; RLPStream s;
sealAndSend(prep(s, StatusPacket, 1) << host()->protocolVersion()); sealAndSend(prep(s, StatusPacket, 1) << version());
} }
WhisperPeer::~WhisperPeer() WhisperPeer::~WhisperPeer()
@ -59,7 +59,7 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r)
clogS(NetMessageSummary) << "Status: " << protocolVersion; clogS(NetMessageSummary) << "Status: " << protocolVersion;
if (protocolVersion != host()->protocolVersion()) if (protocolVersion != version())
disable("Invalid protocol version."); disable("Invalid protocol version.");
if (session()->id() < host()->host()->id()) if (session()->id() < host()->host()->id())

2
libwhisper/WhisperPeer.h

@ -53,7 +53,7 @@ public:
virtual ~WhisperPeer(); virtual ~WhisperPeer();
static std::string name() { return "shh"; } static std::string name() { return "shh"; }
static u256 version() { return 1; } static u256 version() { return 2; }
static unsigned messageCount() { return PacketCount; } static unsigned messageCount() { return PacketCount; }
WhisperHost* host() const; WhisperHost* host() const;

2
lllc/CMakeLists.txt

@ -9,7 +9,7 @@ set(EXECUTABLE lllc)
add_executable(${EXECUTABLE} ${SRC_LIST}) add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")

2
lllc/main.cpp

@ -25,7 +25,7 @@
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include "BuildInfo.h" #include "BuildInfo.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;

2
neth/main.cpp

@ -30,7 +30,7 @@
#include <jsonrpc/connectors/httpserver.h> #include <jsonrpc/connectors/httpserver.h>
#endif #endif
#include <libdevcrypto/FileSystem.h> #include <libdevcrypto/FileSystem.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libethereum/All.h> #include <libethereum/All.h>
#if ETH_JSONRPC #if ETH_JSONRPC
#include <libweb3jsonrpc/WebThreeStubServer.h> #include <libweb3jsonrpc/WebThreeStubServer.h>

2
sc/CMakeLists.txt

@ -10,7 +10,7 @@ add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} serpent)
target_link_libraries(${EXECUTABLE} lll) target_link_libraries(${EXECUTABLE} lll)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")

45
solc/main.cpp

@ -26,12 +26,13 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevmcore/Instruction.h>
#include <libsolidity/Scanner.h> #include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h> #include <libsolidity/Parser.h>
#include <libsolidity/ASTPrinter.h> #include <libsolidity/ASTPrinter.h>
#include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h> #include <libsolidity/Exceptions.h>
#include <libsolidity/Compiler.h> #include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
using namespace std; using namespace std;
@ -42,6 +43,7 @@ void help()
{ {
cout << "Usage solc [OPTIONS] <file>" << endl cout << "Usage solc [OPTIONS] <file>" << endl
<< "Options:" << endl << "Options:" << endl
<< " -o,--optimize Optimize the bytecode for size." << endl
<< " -h,--help Show this help message and exit." << endl << " -h,--help Show this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl; << " -V,--version Show the version and exit." << endl;
exit(0); exit(0);
@ -58,10 +60,13 @@ void version()
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
string infile; string infile;
bool optimize = false;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
{ {
string arg = argv[i]; string arg = argv[i];
if (arg == "-h" || arg == "--help") if (arg == "-o" || arg == "--optimize")
optimize = true;
else if (arg == "-h" || arg == "--help")
help(); help();
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
version(); version();
@ -81,48 +86,34 @@ int main(int argc, char** argv)
else else
sourceCode = asString(dev::contents(infile)); sourceCode = asString(dev::contents(infile));
ASTPointer<ContractDefinition> ast; CompilerStack compiler;
shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(sourceCode));
Parser parser;
bytes instructions;
Compiler compiler;
try try
{ {
ast = parser.parse(scanner); compiler.compile(sourceCode, optimize);
NameAndTypeResolver resolver;
resolver.resolveNamesAndTypes(*ast.get());
cout << "Syntax tree for the contract:" << endl;
dev::solidity::ASTPrinter printer(ast, sourceCode);
printer.print(cout);
compiler.compileContract(*ast);
instructions = compiler.getAssembledBytecode();
} }
catch (ParserError const& exception) catch (ParserError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", compiler.getScanner());
return -1; return -1;
} }
catch (DeclarationError const& exception) catch (DeclarationError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", compiler.getScanner());
return -1; return -1;
} }
catch (TypeError const& exception) catch (TypeError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", compiler.getScanner());
return -1; return -1;
} }
catch (CompilerError const& exception) catch (CompilerError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", compiler.getScanner());
return -1; return -1;
} }
catch (InternalCompilerError const& exception) catch (InternalCompilerError const& exception)
{ {
cerr << "Internal compiler error: " << boost::diagnostic_information(exception) << endl; SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Internal compiler error", compiler.getScanner());
return -1; return -1;
} }
catch (Exception const& exception) catch (Exception const& exception)
@ -136,11 +127,15 @@ int main(int argc, char** argv)
return -1; return -1;
} }
cout << "Syntax tree for the contract:" << endl;
ASTPrinter printer(compiler.getAST(), sourceCode);
printer.print(cout);
cout << "EVM assembly:" << endl; cout << "EVM assembly:" << endl;
compiler.streamAssembly(cout); compiler.streamAssembly(cout);
cout << "Opcodes:" << endl; cout << "Opcodes:" << endl;
cout << eth::disassemble(instructions) << endl; cout << eth::disassemble(compiler.getBytecode()) << endl;
cout << "Binary: " << toHex(instructions) << endl; cout << "Binary: " << toHex(compiler.getBytecode()) << endl;
cout << "Interface specification: " << compiler.getInterface() << endl;
return 0; return 0;
} }

52
test/TestHelper.cpp

@ -27,8 +27,6 @@
#include <libethereum/Client.h> #include <libethereum/Client.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
//#define FILL_TESTS
using namespace std; using namespace std;
using namespace dev::eth; using namespace dev::eth;
@ -305,12 +303,57 @@ std::string getTestPath()
return testPath; return testPath;
} }
void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests)
{
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == testTypeFlag)
{
if (i + 1 >= boost::unit_test::framework::master_test_suite().argc)
{
cnote << "Missing filename\nUsage: testeth " << testTypeFlag << " <filename>\n";
return;
}
string filename = boost::unit_test::framework::master_test_suite().argv[i + 1];
int currentVerbosity = g_logVerbosity;
g_logVerbosity = 12;
try
{
cnote << "Testing user defined test: " << filename;
json_spirit::mValue v;
string s = asString(contents(filename));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v);
doTests(v, false);
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e));
g_logVerbosity = currentVerbosity;
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed Test with Exception: " << _e.what());
g_logVerbosity = currentVerbosity;
}
g_logVerbosity = currentVerbosity;
}
else
continue;
}
}
void executeTests(const string& _name, const string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests) void executeTests(const string& _name, const string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests)
{ {
string testPath = getTestPath(); string testPath = getTestPath();
testPath += _testPathAppendix; testPath += _testPathAppendix;
#ifdef FILL_TESTS for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--filltests")
{
try try
{ {
cnote << "Populating tests..."; cnote << "Populating tests...";
@ -331,7 +374,8 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun
{ {
BOOST_ERROR("Failed test with Exception: " << _e.what()); BOOST_ERROR("Failed test with Exception: " << _e.what());
} }
#endif }
}
try try
{ {

2
test/TestHelper.h

@ -57,7 +57,6 @@ public:
eth::State m_statePost; eth::State m_statePost;
eth::ExtVMFace m_environment; eth::ExtVMFace m_environment;
eth::Transaction m_transaction; eth::Transaction m_transaction;
bytes code;
private: private:
json_spirit::mObject& m_TestObject; json_spirit::mObject& m_TestObject;
@ -72,6 +71,7 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o);
void checkStorage(std::map<u256, u256> _expectedStore, std::map<u256, u256> _resultStore, Address _expectedAddr); void checkStorage(std::map<u256, u256> _expectedStore, std::map<u256, u256> _resultStore, Address _expectedAddr);
void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests); void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests);
std::string getTestPath(); std::string getTestPath();
void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests);
template<typename mapType> template<typename mapType>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)

15
test/createRandomTest.cpp

@ -31,7 +31,8 @@
#include <json_spirit/json_spirit_writer_template.h> #include <json_spirit/json_spirit_writer_template.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libevm/VM.h>
#include "vm.h" #include "vm.h"
using namespace std; using namespace std;
@ -134,18 +135,24 @@ void doMyTests(json_spirit::mValue& v)
o["pre"] = mValue(fev.exportState()); o["pre"] = mValue(fev.exportState());
fev.importExec(o["exec"].get_obj()); fev.importExec(o["exec"].get_obj());
if (!fev.code) if (fev.code.empty())
{ {
fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress));
fev.code = &fev.thisTxCode; fev.code = fev.thisTxCode;
} }
vm.reset(fev.gas); vm.reset(fev.gas);
bytes output; bytes output;
u256 gas;
try try
{ {
output = vm.go(fev).toBytes(); output = vm.go(fev).toBytes();
} }
catch (eth::VMException const& _e)
{
cnote << "VM did throw an exception: " << diagnostic_information(_e);
gas = 0;
}
catch (Exception const& _e) catch (Exception const& _e)
{ {
cnote << "VM did throw an exception: " << diagnostic_information(_e); cnote << "VM did throw an exception: " << diagnostic_information(_e);
@ -176,6 +183,6 @@ void doMyTests(json_spirit::mValue& v)
o["post"] = mValue(fev.exportState()); o["post"] = mValue(fev.exportState());
o["callcreates"] = fev.exportCallCreates(); o["callcreates"] = fev.exportCallCreates();
o["out"] = "0x" + toHex(output); o["out"] = "0x" + toHex(output);
fev.push(o, "gas", vm.gas()); fev.push(o, "gas", gas);
} }
} }

46
test/jsonrpc.cpp

@ -74,14 +74,14 @@ BOOST_FIXTURE_TEST_SUITE(environment, Setup)
BOOST_AUTO_TEST_CASE(jsonrpc_defaultBlock) BOOST_AUTO_TEST_CASE(jsonrpc_defaultBlock)
{ {
cnote << "Testing jsonrpc defaultBlock..."; cnote << "Testing jsonrpc defaultBlock...";
int defaultBlock = jsonrpcClient->defaultBlock(); int defaultBlock = jsonrpcClient->eth_defaultBlock();
BOOST_CHECK_EQUAL(defaultBlock, web3->ethereum()->getDefault()); BOOST_CHECK_EQUAL(defaultBlock, web3->ethereum()->getDefault());
} }
BOOST_AUTO_TEST_CASE(jsonrpc_gasPrice) BOOST_AUTO_TEST_CASE(jsonrpc_gasPrice)
{ {
cnote << "Testing jsonrpc gasPrice..."; cnote << "Testing jsonrpc gasPrice...";
string gasPrice = jsonrpcClient->gasPrice(); string gasPrice = jsonrpcClient->eth_gasPrice();
BOOST_CHECK_EQUAL(gasPrice, toJS(10 * dev::eth::szabo)); BOOST_CHECK_EQUAL(gasPrice, toJS(10 * dev::eth::szabo));
} }
@ -90,11 +90,11 @@ BOOST_AUTO_TEST_CASE(jsonrpc_isListening)
cnote << "Testing jsonrpc isListening..."; cnote << "Testing jsonrpc isListening...";
web3->startNetwork(); web3->startNetwork();
bool listeningOn = jsonrpcClient->listening(); bool listeningOn = jsonrpcClient->eth_listening();
BOOST_CHECK_EQUAL(listeningOn, web3->isNetworkStarted()); BOOST_CHECK_EQUAL(listeningOn, web3->isNetworkStarted());
web3->stopNetwork(); web3->stopNetwork();
bool listeningOff = jsonrpcClient->listening(); bool listeningOff = jsonrpcClient->eth_listening();
BOOST_CHECK_EQUAL(listeningOff, web3->isNetworkStarted()); BOOST_CHECK_EQUAL(listeningOff, web3->isNetworkStarted());
} }
@ -103,11 +103,11 @@ BOOST_AUTO_TEST_CASE(jsonrpc_isMining)
cnote << "Testing jsonrpc isMining..."; cnote << "Testing jsonrpc isMining...";
web3->ethereum()->startMining(); web3->ethereum()->startMining();
bool miningOn = jsonrpcClient->mining(); bool miningOn = jsonrpcClient->eth_mining();
BOOST_CHECK_EQUAL(miningOn, web3->ethereum()->isMining()); BOOST_CHECK_EQUAL(miningOn, web3->ethereum()->isMining());
web3->ethereum()->stopMining(); web3->ethereum()->stopMining();
bool miningOff = jsonrpcClient->mining(); bool miningOff = jsonrpcClient->eth_mining();
BOOST_CHECK_EQUAL(miningOff, web3->ethereum()->isMining()); BOOST_CHECK_EQUAL(miningOff, web3->ethereum()->isMining());
} }
@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_accounts)
cnote << "Testing jsonrpc accounts..."; cnote << "Testing jsonrpc accounts...";
std::vector <dev::KeyPair> keys = {KeyPair::create(), KeyPair::create()}; std::vector <dev::KeyPair> keys = {KeyPair::create(), KeyPair::create()};
jsonrpcServer->setAccounts(keys); jsonrpcServer->setAccounts(keys);
Json::Value k = jsonrpcClient->accounts(); Json::Value k = jsonrpcClient->eth_accounts();
jsonrpcServer->setAccounts({}); jsonrpcServer->setAccounts({});
BOOST_CHECK_EQUAL(k.isArray(), true); BOOST_CHECK_EQUAL(k.isArray(), true);
BOOST_CHECK_EQUAL(k.size(), keys.size()); BOOST_CHECK_EQUAL(k.size(), keys.size());
@ -133,10 +133,10 @@ BOOST_AUTO_TEST_CASE(jsonrpc_accounts)
BOOST_AUTO_TEST_CASE(jsonrpc_number) BOOST_AUTO_TEST_CASE(jsonrpc_number)
{ {
cnote << "Testing jsonrpc number2..."; cnote << "Testing jsonrpc number2...";
int number = jsonrpcClient->number(); int number = jsonrpcClient->eth_number();
BOOST_CHECK_EQUAL(number, web3->ethereum()->number() + 1); BOOST_CHECK_EQUAL(number, web3->ethereum()->number() + 1);
dev::eth::mine(*(web3->ethereum()), 1); dev::eth::mine(*(web3->ethereum()), 1);
int numberAfter = jsonrpcClient->number(); int numberAfter = jsonrpcClient->eth_number();
BOOST_CHECK_EQUAL(number + 1, numberAfter); BOOST_CHECK_EQUAL(number + 1, numberAfter);
BOOST_CHECK_EQUAL(numberAfter, web3->ethereum()->number() + 1); BOOST_CHECK_EQUAL(numberAfter, web3->ethereum()->number() + 1);
} }
@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_number)
BOOST_AUTO_TEST_CASE(jsonrpc_peerCount) BOOST_AUTO_TEST_CASE(jsonrpc_peerCount)
{ {
cnote << "Testing jsonrpc peerCount..."; cnote << "Testing jsonrpc peerCount...";
int peerCount = jsonrpcClient->peerCount(); int peerCount = jsonrpcClient->eth_peerCount();
BOOST_CHECK_EQUAL(web3->peerCount(), peerCount); BOOST_CHECK_EQUAL(web3->peerCount(), peerCount);
} }
@ -152,10 +152,10 @@ BOOST_AUTO_TEST_CASE(jsonrpc_setListening)
{ {
cnote << "Testing jsonrpc setListening..."; cnote << "Testing jsonrpc setListening...";
jsonrpcClient->setListening(true); jsonrpcClient->eth_setListening(true);
BOOST_CHECK_EQUAL(web3->isNetworkStarted(), true); BOOST_CHECK_EQUAL(web3->isNetworkStarted(), true);
jsonrpcClient->setListening(false); jsonrpcClient->eth_setListening(false);
BOOST_CHECK_EQUAL(web3->isNetworkStarted(), false); BOOST_CHECK_EQUAL(web3->isNetworkStarted(), false);
} }
@ -163,10 +163,10 @@ BOOST_AUTO_TEST_CASE(jsonrpc_setMining)
{ {
cnote << "Testing jsonrpc setMining..."; cnote << "Testing jsonrpc setMining...";
jsonrpcClient->setMining(true); jsonrpcClient->eth_setMining(true);
BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), true); BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), true);
jsonrpcClient->setMining(false); jsonrpcClient->eth_setMining(false);
BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), false); BOOST_CHECK_EQUAL(web3->ethereum()->isMining(), false);
} }
@ -175,14 +175,14 @@ BOOST_AUTO_TEST_CASE(jsonrpc_stateAt)
cnote << "Testing jsonrpc stateAt..."; cnote << "Testing jsonrpc stateAt...";
dev::KeyPair key = KeyPair::create(); dev::KeyPair key = KeyPair::create();
auto address = key.address(); auto address = key.address();
string stateAt = jsonrpcClient->stateAt(toJS(address), "0"); string stateAt = jsonrpcClient->eth_stateAt(toJS(address), "0");
BOOST_CHECK_EQUAL(toJS(web3->ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt); BOOST_CHECK_EQUAL(toJS(web3->ethereum()->stateAt(address, jsToU256("0"), 0)), stateAt);
} }
BOOST_AUTO_TEST_CASE(jsonrpc_transact) BOOST_AUTO_TEST_CASE(jsonrpc_transact)
{ {
cnote << "Testing jsonrpc transact..."; cnote << "Testing jsonrpc transact...";
string coinbase = jsonrpcClient->coinbase(); string coinbase = jsonrpcClient->eth_coinbase();
BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address()); BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address());
dev::KeyPair key = KeyPair::create(); dev::KeyPair key = KeyPair::create();
@ -190,14 +190,14 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact)
auto receiver = KeyPair::create(); auto receiver = KeyPair::create();
web3->ethereum()->setAddress(address); web3->ethereum()->setAddress(address);
coinbase = jsonrpcClient->coinbase(); coinbase = jsonrpcClient->eth_coinbase();
BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address()); BOOST_CHECK_EQUAL(jsToAddress(coinbase), web3->ethereum()->address());
BOOST_CHECK_EQUAL(jsToAddress(coinbase), address); BOOST_CHECK_EQUAL(jsToAddress(coinbase), address);
jsonrpcServer->setAccounts({key}); jsonrpcServer->setAccounts({key});
auto balance = web3->ethereum()->balanceAt(address, 0); auto balance = web3->ethereum()->balanceAt(address, 0);
string balanceString = jsonrpcClient->balanceAt(toJS(address)); string balanceString = jsonrpcClient->eth_balanceAt(toJS(address));
double countAt = jsonrpcClient->countAt(toJS(address)); double countAt = jsonrpcClient->eth_countAt(toJS(address));
BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address)); BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address));
BOOST_CHECK_EQUAL(countAt, 0); BOOST_CHECK_EQUAL(countAt, 0);
@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact)
dev::eth::mine(*(web3->ethereum()), 1); dev::eth::mine(*(web3->ethereum()), 1);
balance = web3->ethereum()->balanceAt(address, 0); balance = web3->ethereum()->balanceAt(address, 0);
balanceString = jsonrpcClient->balanceAt(toJS(address)); balanceString = jsonrpcClient->eth_balanceAt(toJS(address));
BOOST_CHECK_EQUAL(toJS(balance), balanceString); BOOST_CHECK_EQUAL(toJS(balance), balanceString);
BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "1500000000000000000"); BOOST_CHECK_EQUAL(jsToDecimal(balanceString), "1500000000000000000");
@ -223,13 +223,13 @@ BOOST_AUTO_TEST_CASE(jsonrpc_transact)
t["gas"] = toJS(gas); t["gas"] = toJS(gas);
t["gasPrice"] = toJS(gasPrice); t["gasPrice"] = toJS(gasPrice);
jsonrpcClient->transact(t); jsonrpcClient->eth_transact(t);
jsonrpcServer->setAccounts({}); jsonrpcServer->setAccounts({});
dev::eth::mine(*(web3->ethereum()), 1); dev::eth::mine(*(web3->ethereum()), 1);
countAt = jsonrpcClient->countAt(toJS(address)); countAt = jsonrpcClient->eth_countAt(toJS(address));
auto balance2 = web3->ethereum()->balanceAt(receiver.address()); auto balance2 = web3->ethereum()->balanceAt(receiver.address());
string balanceString2 = jsonrpcClient->balanceAt(toJS(receiver.address())); string balanceString2 = jsonrpcClient->eth_balanceAt(toJS(receiver.address()));
BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address)); BOOST_CHECK_EQUAL(countAt, (double)(uint64_t)web3->ethereum()->countAt(address));
BOOST_CHECK_EQUAL(countAt, 1); BOOST_CHECK_EQUAL(countAt, 1);

22
test/solidityCompiler.cpp

@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned boilerplateSize = 51; unsigned boilerplateSize = 42;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x0, // initialize local variable x
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2,
@ -100,8 +100,8 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 75; unsigned shift = 70;
unsigned boilerplateSize = 88; unsigned boilerplateSize = 83;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, // initialize return variable d byte(Instruction::PUSH1), 0x0, // initialize return variable d
byte(Instruction::DUP3), byte(Instruction::DUP3),
@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::JUMPDEST), // beginning of g
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), // initialized e and h byte(Instruction::DUP1), // initialized e and h
byte(Instruction::PUSH1), byte(0x20 + shift), // ret address byte(Instruction::PUSH1), byte(0x29 + shift), // ret address
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), byte(0x1 + shift), byte(Instruction::PUSH1), byte(0x1 + shift),
// stack here: ret e h 0x20 1 2 3 0x1 // stack here: ret e h 0x20 1 2 3 0x1
byte(Instruction::JUMP), byte(Instruction::JUMP),
@ -153,8 +153,8 @@ BOOST_AUTO_TEST_CASE(ifStatement)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 38; unsigned shift = 29;
unsigned boilerplateSize = 51; unsigned boilerplateSize = 42;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x0, byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), byte(Instruction::DUP1),
@ -195,8 +195,8 @@ BOOST_AUTO_TEST_CASE(loops)
"}\n"; "}\n";
bytes code = compileContract(sourceCode); bytes code = compileContract(sourceCode);
unsigned shift = 38; unsigned shift = 29;
unsigned boilerplateSize = 51; unsigned boilerplateSize = 42;
bytes expectation({byte(Instruction::JUMPDEST), bytes expectation({byte(Instruction::JUMPDEST),
byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST),
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0x1,

362
test/solidityEndToEndTest.cpp

@ -22,6 +22,7 @@
*/ */
#include <string> #include <string>
#include <tuple>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <libethereum/State.h> #include <libethereum/State.h>
#include <libethereum/Executive.h> #include <libethereum/Executive.h>
@ -41,31 +42,77 @@ class ExecutionFramework
public: public:
ExecutionFramework() { g_logVerbosity = 0; } ExecutionFramework() { g_logVerbosity = 0; }
bytes compileAndRun(std::string const& _sourceCode) bytes const& compileAndRun(string const& _sourceCode)
{ {
bytes code = dev::solidity::CompilerStack::compile(_sourceCode); bytes code = dev::solidity::CompilerStack::staticCompile(_sourceCode);
sendMessage(code, true); sendMessage(code, true);
BOOST_REQUIRE(!m_output.empty());
return m_output; return m_output;
} }
bytes callFunction(byte _index, bytes const& _data) bytes const& callContractFunction(byte _index, bytes const& _data = bytes())
{ {
sendMessage(bytes(1, _index) + _data, false); sendMessage(bytes(1, _index) + _data, false);
return m_output; return m_output;
} }
bytes callFunction(byte _index, u256 const& _argument1) template <class... Args>
bytes const& callContractFunction(byte _index, Args const&... _arguments)
{ {
callFunction(_index, toBigEndian(_argument1)); return callContractFunction(_index, argsToBigEndian(_arguments...));
return m_output; }
template <class CppFunction, class... Args>
void testSolidityAgainstCpp(byte _index, CppFunction const& _cppFunction, Args const&... _arguments)
{
bytes solidityResult = callContractFunction(_index, _arguments...);
bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...);
BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match."
"\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult));
}
template <class CppFunction, class... Args>
void testSolidityAgainstCppOnRange(byte _index, CppFunction const& _cppFunction,
u256 const& _rangeStart, u256 const& _rangeEnd)
{
for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument)
{
bytes solidityResult = callContractFunction(_index, argument);
bytes cppResult = callCppAndEncodeResult(_cppFunction, argument);
BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match."
"\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult) +
"\nArgument: " + toHex(toBigEndian(argument)));
}
} }
private: private:
template <class FirstArg, class... Args>
bytes argsToBigEndian(FirstArg const& _firstArg, Args const&... _followingArgs) const
{
return toBigEndian(_firstArg) + argsToBigEndian(_followingArgs...);
}
bytes argsToBigEndian() const { return bytes(); }
template <class CppFunction, class... Args>
auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments)
-> typename enable_if<is_void<decltype(_cppFunction(_arguments...))>::value, bytes>::type
{
_cppFunction(_arguments...);
return bytes();
}
template <class CppFunction, class... Args>
auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments)
-> typename enable_if<!is_void<decltype(_cppFunction(_arguments...))>::value, bytes>::type
{
return toBigEndian(_cppFunction(_arguments...));
}
void sendMessage(bytes const& _data, bool _isCreation) void sendMessage(bytes const& _data, bool _isCreation)
{ {
eth::Executive executive(m_state); eth::Executive executive(m_state);
eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data) eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
: eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data); : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
bytes transactionRLP = t.rlp(); bytes transactionRLP = t.rlp();
try try
{ {
@ -77,13 +124,17 @@ private:
{ {
BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address()));
m_contractAddress = executive.newAddress(); m_contractAddress = executive.newAddress();
BOOST_REQUIRE(m_contractAddress);
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
} }
else else
{
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address()));
}
BOOST_REQUIRE(executive.go()); BOOST_REQUIRE(executive.go());
executive.finalize(); executive.finalize();
m_output = executive.out().toBytes(); m_output = executive.out().toVector();
} }
Address m_contractAddress; Address m_contractAddress;
@ -93,27 +144,23 @@ private:
bytes m_output; bytes m_output;
}; };
BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest) BOOST_FIXTURE_TEST_SUITE(SolidityCompilerEndToEndTest, ExecutionFramework)
BOOST_AUTO_TEST_CASE(smoke_test) BOOST_AUTO_TEST_CASE(smoke_test)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n" " function f(uint a) returns(uint d) { return a * 7; }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode); testSolidityAgainstCppOnRange(0, [](u256 const& a) -> u256 { return a * 7; }, 0, 100);
u256 a = 0x200030004;
bytes result = framework.callFunction(0, a);
BOOST_CHECK(result == toBigEndian(a * 7));
} }
BOOST_AUTO_TEST_CASE(empty_contract) BOOST_AUTO_TEST_CASE(empty_contract)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode); BOOST_CHECK(callContractFunction(0, bytes()).empty());
BOOST_CHECK(framework.callFunction(0, bytes()).empty());
} }
BOOST_AUTO_TEST_CASE(recursive_calls) BOOST_AUTO_TEST_CASE(recursive_calls)
@ -124,13 +171,32 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
" else return n * f(n - 1);\n" " else return n * f(n - 1);\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode); function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1))); {
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); if (n <= 1)
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2))); return 1;
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6))); else
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); return n * recursive_calls_cpp(n - 1);
};
testSolidityAgainstCppOnRange(0, recursive_calls_cpp, 0, 5);
}
BOOST_AUTO_TEST_CASE(multiple_functions)
{
char const* sourceCode = "contract test {\n"
" function a() returns(uint n) { return 0; }\n"
" function b() returns(uint n) { return 1; }\n"
" function c() returns(uint n) { return 2; }\n"
" function f() returns(uint n) { return 3; }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction(0, bytes()) == toBigEndian(u256(0)));
BOOST_CHECK(callContractFunction(1, bytes()) == toBigEndian(u256(1)));
BOOST_CHECK(callContractFunction(2, bytes()) == toBigEndian(u256(2)));
BOOST_CHECK(callContractFunction(3, bytes()) == toBigEndian(u256(3)));
BOOST_CHECK(callContractFunction(4, bytes()) == bytes());
} }
BOOST_AUTO_TEST_CASE(while_loop) BOOST_AUTO_TEST_CASE(while_loop)
@ -142,13 +208,19 @@ BOOST_AUTO_TEST_CASE(while_loop)
" while (i <= n) nfac *= i++;\n" " while (i <= n) nfac *= i++;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1))); auto while_loop_cpp = [](u256 const& n) -> u256
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); {
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2))); u256 nfac = 1;
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6))); u256 i = 2;
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); while (i <= n)
nfac *= i++;
return nfac;
};
testSolidityAgainstCppOnRange(0, while_loop_cpp, 0, 5);
} }
BOOST_AUTO_TEST_CASE(break_outside_loop) BOOST_AUTO_TEST_CASE(break_outside_loop)
@ -159,9 +231,8 @@ BOOST_AUTO_TEST_CASE(break_outside_loop)
" break; continue; return 2;\n" " break; continue; return 2;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode); testSolidityAgainstCpp(0, [](u256 const&) -> u256 { return 2; }, u256(0));
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(2)));
} }
BOOST_AUTO_TEST_CASE(nested_loops) BOOST_AUTO_TEST_CASE(nested_loops)
@ -184,20 +255,33 @@ BOOST_AUTO_TEST_CASE(nested_loops)
" return x;\n" " return x;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0))); auto nested_loops_cpp = [](u256 n) -> u256
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); {
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(1))); while (n > 1)
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(2))); {
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(2))); if (n == 10)
BOOST_CHECK(framework.callFunction(0, u256(5)) == toBigEndian(u256(4))); break;
BOOST_CHECK(framework.callFunction(0, u256(6)) == toBigEndian(u256(5))); while (n > 5)
BOOST_CHECK(framework.callFunction(0, u256(7)) == toBigEndian(u256(5))); {
BOOST_CHECK(framework.callFunction(0, u256(8)) == toBigEndian(u256(7))); if (n == 8)
BOOST_CHECK(framework.callFunction(0, u256(9)) == toBigEndian(u256(8))); break;
BOOST_CHECK(framework.callFunction(0, u256(10)) == toBigEndian(u256(10))); n--;
BOOST_CHECK(framework.callFunction(0, u256(11)) == toBigEndian(u256(10))); if (n == 6)
continue;
return n;
}
n--;
if (n == 3)
continue;
break;
}
return n;
};
testSolidityAgainstCppOnRange(0, nested_loops_cpp, 0, 12);
} }
BOOST_AUTO_TEST_CASE(calling_other_functions) BOOST_AUTO_TEST_CASE(calling_other_functions)
@ -217,13 +301,36 @@ BOOST_AUTO_TEST_CASE(calling_other_functions)
" return 3 * x + 1;\n" " return 3 * x + 1;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0))); auto evenStep_cpp = [](u256 const& n) -> u256
BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1))); {
BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1))); return n / 2;
BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1))); };
BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1)));
auto oddStep_cpp = [](u256 const& n) -> u256
{
return 3 * n + 1;
};
auto collatz_cpp = [&evenStep_cpp, &oddStep_cpp](u256 n) -> u256
{
u256 y;
while ((y = n) > 1)
{
if (n % 2 == 0)
n = evenStep_cpp(n);
else
n = oddStep_cpp(n);
}
return y;
};
testSolidityAgainstCpp(2, collatz_cpp, u256(0));
testSolidityAgainstCpp(2, collatz_cpp, u256(1));
testSolidityAgainstCpp(2, collatz_cpp, u256(2));
testSolidityAgainstCpp(2, collatz_cpp, u256(8));
testSolidityAgainstCpp(2, collatz_cpp, u256(127));
} }
BOOST_AUTO_TEST_CASE(many_local_variables) BOOST_AUTO_TEST_CASE(many_local_variables)
@ -235,10 +342,30 @@ BOOST_AUTO_TEST_CASE(many_local_variables)
" y += b + x2;\n" " y += b + x2;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode); auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256
BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) {
== toBigEndian(u256(0x121121))); u256 a = 0x1;
u256 b = 0x10;
u256 c = 0x100;
u256 y = a + b + c + x1 + x2 + x3;
return y + b + x2;
};
testSolidityAgainstCpp(0, f, u256(0x1000), u256(0x10000), u256(0x100000));
}
BOOST_AUTO_TEST_CASE(packing_unpacking_types)
{
char const* sourceCode = "contract test {\n"
" function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n"
" if (a) y = 1;\n"
" y = y * 0x100000000 | ~b;\n"
" y = y * 0x10000000000000000 | ~c;\n"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0"))
== fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f"));
} }
BOOST_AUTO_TEST_CASE(multiple_return_values) BOOST_AUTO_TEST_CASE(multiple_return_values)
@ -248,9 +375,8 @@ BOOST_AUTO_TEST_CASE(multiple_return_values)
" y1 = x2; y2 = x1;\n" " y1 = x2; y2 = x1;\n"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode); BOOST_CHECK(callContractFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); == toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
} }
@ -262,13 +388,113 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
" return x;" " return x;"
" }\n" " }\n"
"}\n"; "}\n";
ExecutionFramework framework; compileAndRun(sourceCode);
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0))); auto short_circuiting_cpp = [](u256 n) -> u256
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8))); {
n == 0 || (n = 8) > 0;
return n;
};
testSolidityAgainstCppOnRange(0, short_circuiting_cpp, 0, 2);
}
BOOST_AUTO_TEST_CASE(high_bits_cleaning)
{
char const* sourceCode = "contract test {\n"
" function run() returns(uint256 y) {\n"
" uint32 x = uint32(0xffffffff) + 10;\n"
" if (x >= 0xffffffff) return 0;\n"
" return x;"
" }\n"
"}\n";
compileAndRun(sourceCode);
auto high_bits_cleaning_cpp = []() -> u256
{
uint32_t x = uint32_t(0xffffffff) + 10;
if (x >= 0xffffffff)
return 0;
return x;
};
testSolidityAgainstCpp(0, high_bits_cleaning_cpp);
}
BOOST_AUTO_TEST_CASE(sign_extension)
{
char const* sourceCode = "contract test {\n"
" function run() returns(uint256 y) {\n"
" int64 x = -int32(0xff);\n"
" if (x >= 0xff) return 0;\n"
" return -uint256(x);"
" }\n"
"}\n";
compileAndRun(sourceCode);
auto sign_extension_cpp = []() -> u256
{
int64_t x = -int32_t(0xff);
if (x >= 0xff)
return 0;
return u256(x) * -1;
};
testSolidityAgainstCpp(0, sign_extension_cpp);
}
BOOST_AUTO_TEST_CASE(small_unsigned_types)
{
char const* sourceCode = "contract test {\n"
" function run() returns(uint256 y) {\n"
" uint32 x = uint32(0xffffff) * 0xffffff;\n"
" return x / 0x100;"
" }\n"
"}\n";
compileAndRun(sourceCode);
auto small_unsigned_types_cpp = []() -> u256
{
uint32_t x = uint32_t(0xffffff) * 0xffffff;
return x / 0x100;
};
testSolidityAgainstCpp(0, small_unsigned_types_cpp);
}
BOOST_AUTO_TEST_CASE(small_signed_types)
{
char const* sourceCode = "contract test {\n"
" function run() returns(int256 y) {\n"
" return -int32(10) * -int64(20);\n"
" }\n"
"}\n";
compileAndRun(sourceCode);
auto small_signed_types_cpp = []() -> u256
{
return -int32_t(10) * -int64_t(20);
};
testSolidityAgainstCpp(0, small_signed_types_cpp);
} }
//@todo test smaller types BOOST_AUTO_TEST_CASE(state_smoke_test)
{
char const* sourceCode = "contract test {\n"
" uint256 value1;\n"
" uint256 value2;\n"
" function get(uint8 which) returns (uint256 value) {\n"
" if (which == 0) return value1;\n"
" else return value2;\n"
" }\n"
" function set(uint8 which, uint256 value) {\n"
" if (which == 0) value1 = value;\n"
" else value2 = value;\n"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0)));
BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0)));
BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x1234))) == bytes());
BOOST_CHECK(callContractFunction(1, bytes(1, 0x01) + toBigEndian(u256(0x8765))) == bytes());
BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x1234)));
BOOST_CHECK(callContractFunction(0, bytes(1, 0x01)) == toBigEndian(u256(0x8765)));
BOOST_CHECK(callContractFunction(1, bytes(1, 0x00) + toBigEndian(u256(0x3))) == bytes());
BOOST_CHECK(callContractFunction(0, bytes(1, 0x00)) == toBigEndian(u256(0x3)));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

111
test/solidityExpressionCompiler.cpp

@ -154,10 +154,10 @@ BOOST_AUTO_TEST_CASE(comparison)
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT), byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::LT),
byte(eth::Instruction::EQ), byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO)}); byte(eth::Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
@ -166,22 +166,22 @@ BOOST_AUTO_TEST_CASE(comparison)
BOOST_AUTO_TEST_CASE(short_circuiting) BOOST_AUTO_TEST_CASE(short_circuiting)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f() { var x = (10 + 8 >= 4 || 2 != 9) != true; }" " function f() { var x = true != (4 <= 8 + 10 || 9 != 2); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0xa, bytes expectation({byte(eth::Instruction::PUSH1), 0xa,
byte(eth::Instruction::PUSH1), 0x8, byte(eth::Instruction::PUSH1), 0x8,
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT), byte(eth::Instruction::GT),
byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4 byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4
byte(eth::Instruction::DUP1), byte(eth::Instruction::DUP1),
byte(eth::Instruction::PUSH1), 0x14, byte(eth::Instruction::PUSH1), 0x20,
byte(eth::Instruction::JUMPI), // short-circuit if it is true byte(eth::Instruction::JUMPI), // short-circuit if it is true
byte(eth::Instruction::POP), byte(eth::Instruction::POP),
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::EQ), byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO), // after this we have 2 != 9 byte(eth::Instruction::ISZERO), // after this we have 2 != 9
byte(eth::Instruction::JUMPDEST), byte(eth::Instruction::JUMPDEST),
@ -194,13 +194,14 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
BOOST_AUTO_TEST_CASE(arithmetics) BOOST_AUTO_TEST_CASE(arithmetics)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }" " function f() { var x = ((((((((9 ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1, bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x3, byte(eth::Instruction::PUSH1), 0x3,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::PUSH1), 0x5, byte(eth::Instruction::PUSH1), 0x5,
byte(eth::Instruction::PUSH1), 0x6, byte(eth::Instruction::PUSH1), 0x6,
@ -210,12 +211,11 @@ BOOST_AUTO_TEST_CASE(arithmetics)
byte(eth::Instruction::XOR), byte(eth::Instruction::XOR),
byte(eth::Instruction::AND), byte(eth::Instruction::AND),
byte(eth::Instruction::OR), byte(eth::Instruction::OR),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB), byte(eth::Instruction::SUB),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
byte(eth::Instruction::SWAP1), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::MOD), byte(eth::Instruction::MOD),
byte(eth::Instruction::SWAP1), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::DIV), byte(eth::Instruction::DIV),
byte(eth::Instruction::MUL)}); byte(eth::Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
@ -224,15 +224,15 @@ BOOST_AUTO_TEST_CASE(arithmetics)
BOOST_AUTO_TEST_CASE(unary_operators) BOOST_AUTO_TEST_CASE(unary_operators)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f() { var x = !(~+-1 == 2); }" " function f() { var x = !(~+- 1 == 2); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1, bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x0, byte(eth::Instruction::PUSH1), 0x0,
byte(eth::Instruction::SUB), byte(eth::Instruction::SUB),
byte(eth::Instruction::NOT), byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::EQ), byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO)}); byte(eth::Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
@ -241,7 +241,7 @@ BOOST_AUTO_TEST_CASE(unary_operators)
BOOST_AUTO_TEST_CASE(unary_inc_dec) BOOST_AUTO_TEST_CASE(unary_inc_dec)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f(uint a) { var x = ((a++ ^ ++a) ^ a--) ^ --a; }" " function f(uint a) { var x = --a ^ (a-- ^ (++a ^ a++)); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}});
@ -296,16 +296,15 @@ BOOST_AUTO_TEST_CASE(assignment)
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b // Stack: a, b
bytes expectation({byte(eth::Instruction::DUP1), bytes expectation({byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::DUP3), byte(eth::Instruction::DUP2),
byte(eth::Instruction::SWAP1), byte(eth::Instruction::DUP4),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
// Stack here: a b a+b // Stack here: a b 2 a+b
byte(eth::Instruction::SWAP2), byte(eth::Instruction::SWAP3),
byte(eth::Instruction::POP), byte(eth::Instruction::POP),
byte(eth::Instruction::DUP2), byte(eth::Instruction::DUP3),
// Stack here: a+b b a+b // Stack here: a+b b 2 a+b
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::MUL)}); byte(eth::Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
@ -320,21 +319,20 @@ BOOST_AUTO_TEST_CASE(function_call)
{{"test", "f", "a"}, {"test", "f", "b"}}); {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b // Stack: a, b
bytes expectation({byte(eth::Instruction::PUSH1), 0x0a, bytes expectation({byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::DUP3), byte(eth::Instruction::PUSH1), 0x12,
byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::DUP5),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
// Stack here: a b <ret label> (a+1) // Stack here: a b 2 <ret label> (a+1)
byte(eth::Instruction::DUP3), byte(eth::Instruction::DUP4),
byte(eth::Instruction::PUSH1), 0x14, byte(eth::Instruction::PUSH1), 0x19,
byte(eth::Instruction::JUMP), byte(eth::Instruction::JUMP),
byte(eth::Instruction::JUMPDEST), byte(eth::Instruction::JUMPDEST),
// Stack here: a b g(a+1, b) // Stack here: a b 2 g(a+1, b)
byte(eth::Instruction::PUSH1), 0x02,
byte(eth::Instruction::MUL), byte(eth::Instruction::MUL),
// Stack here: a b g(a+1, b)*2 // Stack here: a b g(a+1, b)*2
byte(eth::Instruction::DUP3), byte(eth::Instruction::DUP3),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
// Stack here: a b a+g(a+1, b)*2 // Stack here: a b a+g(a+1, b)*2
byte(eth::Instruction::SWAP2), byte(eth::Instruction::SWAP2),
@ -344,6 +342,45 @@ BOOST_AUTO_TEST_CASE(function_call)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }
BOOST_AUTO_TEST_CASE(negative_literals_8bits)
{
// these all fit in 8 bits
char const* sourceCode = "contract test {\n"
" function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) +
bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) +
bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::ADD),
byte(eth::Instruction::ADD),
byte(eth::Instruction::ADD),
byte(eth::Instruction::ADD)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(negative_literals_16bits)
{
// -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible
// from the SIGNEXTEND opcodes
char const* sourceCode = "contract test {\n"
" function f() { int64 x = int64(-1 + -129); }\n"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) +
bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::SIGNEXTEND),
byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x01,
byte(eth::Instruction::SIGNEXTEND)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

214
test/solidityJSONInterfaceTest.cpp

@ -0,0 +1,214 @@
/*
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 Marek Kotewicz <marek@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>
namespace dev
{
namespace solidity
{
namespace test
{
class InterfaceChecker
{
public:
bool checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
{
m_compilerStack.parse(_code);
std::string generatedInterfaceString = m_compilerStack.getInterface();
Json::Value generatedInterface;
m_reader.parse(generatedInterfaceString, generatedInterface);
Json::Value expectedInterface;
m_reader.parse(_expectedInterfaceString, expectedInterface);
return expectedInterface == generatedInterface;
}
private:
CompilerStack m_compilerStack;
Json::Reader m_reader;
};
BOOST_FIXTURE_TEST_SUITE(SolidityCompilerJSONInterfaceOutput, InterfaceChecker)
BOOST_AUTO_TEST_CASE(basic_test)
{
char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n"
"}\n";
char const* interface = R"([
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(empty_contract)
{
char const* sourceCode = "contract test {\n"
"}\n";
char const* interface = "[]";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(multiple_methods)
{
char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n"
" function g(uint b) returns(uint e) { return b * 8; }\n"
"}\n";
char const* interface = R"([
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
},
{
"name": "g",
"inputs": [
{
"name": "b",
"type": "uint256"
}
],
"outputs": [
{
"name": "e",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(multiple_params)
{
char const* sourceCode = "contract test {\n"
" function f(uint a, uint b) returns(uint d) { return a + b; }\n"
"}\n";
char const* interface = R"([
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
},
{
"name": "b",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_CASE(multiple_methods_order)
{
// methods are expected to be in alpabetical order
char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n"
" function c(uint b) returns(uint e) { return b * 8; }\n"
"}\n";
char const* interface = R"([
{
"name": "c",
"inputs": [
{
"name": "b",
"type": "uint256"
}
],
"outputs": [
{
"name": "e",
"type": "uint256"
}
]
},
{
"name": "f",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
BOOST_CHECK(checkInterface(sourceCode, interface));
}
BOOST_AUTO_TEST_SUITE_END()
}
}
}

16
test/solidityNameAndTypeResolution.cpp

@ -162,6 +162,22 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
} }
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
{
char const* text = "contract test {\n"
" function f() { uint32(2) == int64(2); }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid)
{
char const* text = "contract test {\n"
" function f() { int32(2) == uint64(2); }"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion) BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
{ {
char const* text = "contract test {\n" char const* text = "contract test {\n"

26
test/solidityScanner.cpp

@ -97,6 +97,27 @@ BOOST_AUTO_TEST_CASE(hex_numbers)
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
} }
BOOST_AUTO_TEST_CASE(negative_numbers)
{
Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9");
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(locations) BOOST_AUTO_TEST_CASE(locations)
{ {
Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment")); Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment"));
@ -109,11 +130,8 @@ BOOST_AUTO_TEST_CASE(locations)
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25);
BOOST_CHECK_EQUAL(scanner.next(), Token::SUB);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 27);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45);

717
test/stPreCompiledContractsFiller.json

@ -0,0 +1,717 @@
{
"CallEcrecover0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallEcrecover0_gas500": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 500 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallEcrecover0_Gas499": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 499 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallEcrecover0_0input": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code": "{ [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallEcrecover1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallEcrecover2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 1000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallEcrecover3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) [[ 2 ]] (CALL 1000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallSha256_0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "0x600160005260206000602060006000600260fff1600051600055",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallSha256_1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ [[ 2 ]] (CALL 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallSha256_2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallSha256_3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallSha256_4": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallSha256_4_gas99": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallSha256_5": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 500 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallRipemd160_0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "0x600160005260206000602060006000600360fff1600051600055",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallRipemd160_1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ [[ 2 ]] (CALL 500 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallRipemd160_2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallRipemd160_3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallRipemd160_4": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallRipemd160_4_gas99": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"CallRipemd160_5": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "20000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 500 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
}

1334
test/stSystemOperationsTestFiller.json

File diff suppressed because it is too large

53
test/state.cpp

@ -43,7 +43,6 @@ namespace dev { namespace test {
void doStateTests(json_spirit::mValue& v, bool _fillin) void doStateTests(json_spirit::mValue& v, bool _fillin)
{ {
cout << "start state test\n";
for (auto& i: v.get_obj()) for (auto& i: v.get_obj())
{ {
cnote << i.first; cnote << i.first;
@ -55,12 +54,6 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
ImportTest importer(o, _fillin); ImportTest importer(o, _fillin);
if (_fillin)
{
importer.code = importer.m_statePre.code(importer.m_environment.myAddress);
importer.m_environment.code = &importer.code;
}
State theState = importer.m_statePre; State theState = importer.m_statePre;
bytes tx = importer.m_transaction.rlp(); bytes tx = importer.m_transaction.rlp();
bytes output; bytes output;
@ -124,12 +117,48 @@ BOOST_AUTO_TEST_CASE(stSystemOperationsTest)
dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests); dev::test::executeTests("stSystemOperationsTest", "/StateTests", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(tmp) BOOST_AUTO_TEST_CASE(stPreCompiledContracts)
{
dev::test::executeTests("stPreCompiledContracts", "/StateTests", dev::test::doStateTests);
}
BOOST_AUTO_TEST_CASE(stCreateTest)
{
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--createtest")
{
if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
{
cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n";
return;
}
try
{
cnote << "Populating tests...";
json_spirit::mValue v;
string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1]));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty.");
json_spirit::read_string(s, v);
dev::test::doStateTests(v, true);
writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true)));
}
catch (Exception const& _e)
{
BOOST_ERROR("Failed state test with Exception: " << diagnostic_information(_e));
}
catch (std::exception const& _e)
{
BOOST_ERROR("Failed state test with Exception: " << _e.what());
}
}
}
}
BOOST_AUTO_TEST_CASE(userDefinedFileState)
{ {
int currentVerbosity = g_logVerbosity; dev::test::userDefinedTest("--statetest", dev::test::doStateTests);
g_logVerbosity = 12;
dev::test::executeTests("tmp", "/StateTests", dev::test::doStateTests);
g_logVerbosity = currentVerbosity;
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

44
test/tmpFiller.json

@ -1,44 +0,0 @@
{
"ABAcalls0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }",
"storage": {}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : " { [[ (PC) ]] (ADD 1 (CALL 500 0x095e7baea6a6c7c4c2dfeb977efac326af552d87 23 0 0 0 0)) } ",
"nonce" : "0",
"storage" : {
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "10000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
}
}

61
test/vm.cpp

@ -20,6 +20,7 @@
* vm test functions. * vm test functions.
*/ */
#include <boost/filesystem.hpp>
#include "vm.h" #include "vm.h"
using namespace std; using namespace std;
@ -29,7 +30,7 @@ using namespace dev::eth;
using namespace dev::test; using namespace dev::test;
FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix.
ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {} ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, _depth) {}
h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&) h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc const&)
{ {
@ -195,11 +196,11 @@ void FakeExtVM::importExec(mObject& _o)
gas = toInt(_o["gas"]); gas = toInt(_o["gas"]);
thisTxCode.clear(); thisTxCode.clear();
code = &thisTxCode; code = thisTxCode;
thisTxCode = importCode(_o); thisTxCode = importCode(_o);
if (_o["code"].type() != str_type && _o["code"].type() != array_type) if (_o["code"].type() != str_type && _o["code"].type() != array_type)
code.reset(); code.clear();
thisTxData.clear(); thisTxData.clear();
thisTxData = importData(_o); thisTxData = importData(_o);
@ -289,27 +290,35 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
o["pre"] = mValue(fev.exportState()); o["pre"] = mValue(fev.exportState());
fev.importExec(o["exec"].get_obj()); fev.importExec(o["exec"].get_obj());
if (!fev.code) if (fev.code.empty())
{ {
fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress)); fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress));
fev.code = &fev.thisTxCode; fev.code = fev.thisTxCode;
} }
bytes output; bytes output;
VM vm(fev.gas); VM vm(fev.gas);
u256 gas;
try try
{ {
output = vm.go(fev, fev.simpleTrace()).toVector(); output = vm.go(fev, fev.simpleTrace()).toVector();
gas = vm.gas();
}
catch (VMException const& _e)
{
cnote << "VM did throw an exception: " << diagnostic_information(_e);
gas = 0;
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
cnote << "VM did throw an exception: " << diagnostic_information(_e); cnote << "VM did throw an exception: " << diagnostic_information(_e);
//BOOST_ERROR("Failed VM Test with Exception: " << e.what()); BOOST_ERROR("Failed VM Test with Exception: " << _e.what());
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
cnote << "VM did throw an exception: " << _e.what(); cnote << "VM did throw an exception: " << _e.what();
//BOOST_ERROR("Failed VM Test with Exception: " << e.what()); BOOST_ERROR("Failed VM Test with Exception: " << _e.what());
} }
// delete null entries in storage for the sake of comparison // delete null entries in storage for the sake of comparison
@ -336,7 +345,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
o["post"] = mValue(fev.exportState()); o["post"] = mValue(fev.exportState());
o["callcreates"] = fev.exportCallCreates(); o["callcreates"] = fev.exportCallCreates();
o["out"] = "0x" + toHex(output); o["out"] = "0x" + toHex(output);
fev.push(o, "gas", vm.gas()); fev.push(o, "gas", gas);
} }
else else
{ {
@ -351,7 +360,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
checkOutput(output, o); checkOutput(output, o);
BOOST_CHECK_EQUAL(toInt(o["gas"]), vm.gas()); BOOST_CHECK_EQUAL(toInt(o["gas"]), gas);
auto& expectedAddrs = test.addresses; auto& expectedAddrs = test.addresses;
auto& resultAddrs = fev.addresses; auto& resultAddrs = fev.addresses;
@ -423,32 +432,42 @@ BOOST_AUTO_TEST_CASE(vmPushDupSwapTest)
dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests); dev::test::executeTests("vmPushDupSwapTest", "/VMTests", dev::test::doVMTests);
} }
BOOST_AUTO_TEST_CASE(userDefinedFile) BOOST_AUTO_TEST_CASE(vmRandom)
{ {
if (boost::unit_test::framework::master_test_suite().argc == 2) string testPath = getTestPath();
testPath += "/VMTests/RandomTests";
vector<boost::filesystem::path> testFiles;
boost::filesystem::directory_iterator iterator(testPath);
for(; iterator != boost::filesystem::directory_iterator(); ++iterator)
if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json")
testFiles.push_back(iterator->path());
for (auto& path: testFiles)
{ {
string filename = boost::unit_test::framework::master_test_suite().argv[1];
int currentVerbosity = g_logVerbosity;
g_logVerbosity = 12;
try try
{ {
cnote << "Testing VM..." << "user defined test"; cnote << "Testing ..." << path.filename();
json_spirit::mValue v; json_spirit::mValue v;
string s = asString(contents(filename)); string s = asString(dev::contents(path.string()));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
dev::test::doVMTests(v, false); doVMTests(v, false);
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e));
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); BOOST_ERROR("Failed test with Exception: " << _e.what());
} }
g_logVerbosity = currentVerbosity;
} }
} }
BOOST_AUTO_TEST_CASE(userDefinedFileVM)
{
dev::test::userDefinedTest("--vmtest", dev::test::doVMTests);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save