Browse Source

Merge branch 'develop-evmcc' into pr-jit

cl-refactor
Paweł Bylica 10 years ago
parent
commit
85c373adca
  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. 2
      evmcc/CMakeLists.txt
  9. 34
      evmcc/evmcc.cpp
  10. 96
      exp/main.cpp
  11. 2
      iethxi/MainWin.cpp
  12. 2
      libdevcore/Common.cpp
  13. 8
      libdevcore/CommonData.cpp
  14. 2
      libdevcore/CommonIO.cpp
  15. 1
      libdevcore/Log.h
  16. 9
      libdevcore/RLP.h
  17. 3
      libdevcrypto/Common.cpp
  18. 31
      libdevcrypto/EC.cpp
  19. 2
      libethcore/CommonEth.cpp
  20. 11
      libethereum/Executive.cpp
  21. 2
      libethereum/Executive.h
  22. 2
      libethereum/ExtVM.h
  23. 22
      libethereum/State.cpp
  24. 2
      libethereum/TransactionReceipt.h
  25. 2
      libevm/CMakeLists.txt
  26. 2
      libevm/ExtVMFace.cpp
  27. 8
      libevm/ExtVMFace.h
  28. 3
      libevm/FeeStructure.cpp
  29. 3
      libevm/FeeStructure.h
  30. 31
      libevm/VM.h
  31. 81
      libevmcore/Assembly.cpp
  32. 4
      libevmcore/Assembly.h
  33. 2
      libevmcore/CMakeLists.txt
  34. 36
      libevmcore/Exceptions.h
  35. 337
      libevmcore/Instruction.cpp
  36. 8
      libevmcore/Instruction.h
  37. 337
      libevmface/Instruction.cpp
  38. 2
      libevmjit/CMakeLists.txt
  39. 33
      libevmjit/Compiler.cpp
  40. 6
      libevmjit/Compiler.h
  41. 26
      libevmjit/ExecutionEngine.cpp
  42. 2
      libevmjit/ExecutionEngine.h
  43. 125
      libevmjit/Ext.cpp
  44. 7
      libevmjit/Ext.h
  45. 2
      libevmjit/GasMeter.cpp
  46. 2
      libevmjit/GasMeter.h
  47. 18
      libevmjit/Memory.cpp
  48. 2
      libevmjit/Memory.h
  49. 10
      libevmjit/Runtime.cpp
  50. 4
      libevmjit/Runtime.h
  51. 2
      libevmjit/Utils.cpp
  52. 4
      libevmjit/Utils.h
  53. 2
      libevmjit/VM.cpp
  54. 109
      libjsqrc/main.js
  55. 8
      libjsqrc/qt.js
  56. 2
      libjsqrc/setup.js
  57. 1
      liblll/All.h
  58. 2
      liblll/CMakeLists.txt
  59. 2
      liblll/CodeFragment.cpp
  60. 4
      liblll/CodeFragment.h
  61. 3
      liblll/Exceptions.h
  62. 2
      libpyserpent/CMakeLists.txt
  63. 30
      libqethereum/QEthereum.cpp
  64. 2
      libqethereum/QmlEthereum.cpp
  65. 2
      libserpent/CMakeLists.txt
  66. 3
      libserpent/compiler.cpp
  67. 33
      libsolidity/AST.cpp
  68. 13
      libsolidity/AST.h
  69. 8
      libsolidity/ASTPrinter.cpp
  70. 4
      libsolidity/ASTPrinter.h
  71. 10
      libsolidity/CMakeLists.txt
  72. 65
      libsolidity/Compiler.cpp
  73. 4
      libsolidity/Compiler.h
  74. 36
      libsolidity/CompilerContext.cpp
  75. 31
      libsolidity/CompilerContext.h
  76. 99
      libsolidity/CompilerStack.cpp
  77. 41
      libsolidity/CompilerStack.h
  78. 234
      libsolidity/ExpressionCompiler.cpp
  79. 66
      libsolidity/ExpressionCompiler.h
  80. 106
      libsolidity/Scanner.cpp
  81. 2
      libsolidity/Scanner.h
  82. 84
      libsolidity/Token.h
  83. 75
      libsolidity/Types.cpp
  84. 21
      libsolidity/Types.h
  85. 101
      libweb3jsonrpc/WebThreeStubServer.cpp
  86. 87
      libweb3jsonrpc/WebThreeStubServer.h
  87. 343
      libweb3jsonrpc/abstractwebthreestubserver.h
  88. 101
      libweb3jsonrpc/spec.json
  89. 35
      libwhisper/Common.cpp
  90. 18
      libwhisper/Common.h
  91. 7
      libwhisper/Interface.cpp
  92. 2
      libwhisper/Interface.h
  93. 4
      libwhisper/Message.cpp
  94. 15
      libwhisper/Message.h
  95. 7
      libwhisper/WhisperHost.cpp
  96. 2
      libwhisper/WhisperHost.h
  97. 4
      libwhisper/WhisperPeer.cpp
  98. 2
      libwhisper/WhisperPeer.h
  99. 2
      lllc/CMakeLists.txt
  100. 2
      lllc/main.cpp

2
CMakeLists.txt

@ -115,7 +115,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>

2
evmcc/CMakeLists.txt

@ -13,7 +13,7 @@ target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} ethereum)
target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} evmjit) target_link_libraries(${EXECUTABLE} evmjit)
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")

34
evmcc/evmcc.cpp

@ -14,7 +14,8 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libevm/ExtVMFace.h>
#include <libevmjit/Compiler.h> #include <libevmjit/Compiler.h>
#include <libevmjit/ExecutionEngine.h> #include <libevmjit/ExecutionEngine.h>
@ -31,9 +32,12 @@ void parseProgramOptions(int _argc, char** _argv, boost::program_options::variab
("gas,g", opt::value<size_t>(), "set initial gas for execution") ("gas,g", opt::value<size_t>(), "set initial gas for execution")
("disassemble,d", "dissassemble the code") ("disassemble,d", "dissassemble the code")
("dump-cfg", "dump control flow graph to graphviz file") ("dump-cfg", "dump control flow graph to graphviz file")
("optimize-stack,os", "optimize stack use between basic blocks") ("dont-optimize", "turn off optimizations")
("optimize-stack", "optimize stack use between basic blocks (default: on)")
("rewrite-switch", "rewrite LLVM switch to branches (default: on)")
("output-ll", opt::value<std::string>(), "dump generated LLVM IR to file") ("output-ll", opt::value<std::string>(), "dump generated LLVM IR to file")
("output-bc", opt::value<std::string>(), "dump generated LLVM bitcode to file") ("output-bc", opt::value<std::string>(), "dump generated LLVM bitcode to file")
("show-logs", "output LOG statements to stderr")
("verbose,V", "enable verbose output"); ("verbose,V", "enable verbose output");
opt::options_description implicitOpts("Input files"); opt::options_description implicitOpts("Input files");
@ -118,10 +122,12 @@ int main(int argc, char** argv)
eth::jit::Compiler::Options compilerOptions; eth::jit::Compiler::Options compilerOptions;
compilerOptions.dumpCFG = options.count("dump-cfg") > 0; compilerOptions.dumpCFG = options.count("dump-cfg") > 0;
compilerOptions.optimizeStack = options.count("optimize-stack") > 0; bool optimize = options.count("dont-optimize") == 0;
compilerOptions.optimizeStack = optimize || options.count("optimize-stack") > 0;
compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0;
auto compiler = eth::jit::Compiler(compilerOptions); auto compiler = eth::jit::Compiler(compilerOptions);
auto module = compiler.compile({bytecode.data(), bytecode.size()}); auto module = compiler.compile(bytecode);
auto compilationEndTime = std::chrono::high_resolution_clock::now(); auto compilationEndTime = std::chrono::high_resolution_clock::now();
@ -156,7 +162,6 @@ int main(int argc, char** argv)
ofs.close(); ofs.close();
} }
if (options.count("verbose")) if (options.count("verbose"))
{ {
std::cerr << "*** Compilation time: " std::cerr << "*** Compilation time: "
@ -168,7 +173,24 @@ int main(int argc, char** argv)
{ {
auto engine = eth::jit::ExecutionEngine(); auto engine = eth::jit::ExecutionEngine();
u256 gas = initialGas; u256 gas = initialGas;
auto result = engine.run(std::move(module), gas);
// Create fake ExtVM interface
eth::ExtVMFace ext;
ext.myAddress = Address(1122334455667788);
ext.caller = Address(0xfacefacefaceface);
ext.origin = Address(101010101010101010);
ext.value = 0xabcd;
ext.gasPrice = 1002;
ext.previousBlock.hash = u256(1003);
ext.currentBlock.coinbaseAddress = Address(1004);
ext.currentBlock.timestamp = 1005;
ext.currentBlock.number = 1006;
ext.currentBlock.difficulty = 1007;
ext.currentBlock.gasLimit = 1008;
ext.data = std::string("Hello the Beautiful World of Ethereum!");
ext.code = { 0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf };
auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0, ext);
return result; return result;
} }
} }

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)

31
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 derMaxEncodingLength = 72; 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);
byte dersig[derMaxEncodingLength]; byte dersig[c_derMaxEncodingLength];
size_t cssz = DSAConvertSignatureFormat(dersig, derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363); size_t cssz = DSAConvertSignatureFormat(dersig, c_derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363);
assert(cssz <= 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];
auto 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];
auto 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 "Transaction.h" #include "Transaction.h"
#include "Manifest.h" #include "Manifest.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"
@ -555,10 +556,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)
{ {
@ -1196,12 +1199,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))
{ {
auto vmObj = VMFace::create(getVMKind(), *_gas); auto vmObj = VMFace::create(getVMKind(), *_gas);
@ -1242,12 +1248,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 "VMFace.h" #include "VMFace.h"
@ -184,14 +184,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;
@ -679,7 +680,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;
@ -687,7 +688,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();
@ -721,18 +722,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);
}

2
libevmjit/CMakeLists.txt

@ -18,7 +18,7 @@ include_directories(..)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} evm)
target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} evmcore)
if ("${TARGET_PLATFORM}" STREQUAL "w64") if ("${TARGET_PLATFORM}" STREQUAL "w64")

33
libevmjit/Compiler.cpp

@ -13,7 +13,7 @@
#include <llvm/PassManager.h> #include <llvm/PassManager.h>
#include <llvm/Transforms/Scalar.h> #include <llvm/Transforms/Scalar.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include "Type.h" #include "Type.h"
#include "Memory.h" #include "Memory.h"
@ -39,7 +39,7 @@ Compiler::Compiler(Options const& _options):
Type::init(m_builder.getContext()); Type::init(m_builder.getContext());
} }
void Compiler::createBasicBlocks(bytesConstRef _bytecode) void Compiler::createBasicBlocks(bytes const& _bytecode)
{ {
std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end
@ -151,7 +151,7 @@ void Compiler::createBasicBlocks(bytesConstRef _bytecode)
m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second);
} }
std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef _bytecode) std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode)
{ {
auto module = std::unique_ptr<llvm::Module>(new llvm::Module("main", m_builder.getContext())); auto module = std::unique_ptr<llvm::Module>(new llvm::Module("main", m_builder.getContext()));
@ -247,7 +247,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef _bytecode)
} }
void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager,
Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock)
{ {
if (!_nextBasicBlock) // this is the last block in the code if (!_nextBasicBlock) // this is the last block in the code
@ -508,7 +508,11 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod
case Instruction::POP: case Instruction::POP:
{ {
stack.pop(); auto val = stack.pop();
static_cast<void>(val);
// Generate a dummy use of val to make sure that a get(0) will be emitted at this point,
// so that StackTooSmall will be thrown
// m_builder.CreateICmpEQ(val, val, "dummy");
break; break;
} }
@ -791,6 +795,25 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod
break; break;
} }
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
case Instruction::LOG3:
case Instruction::LOG4:
{
auto beginIdx = stack.pop();
auto numBytes = stack.pop();
_memory.require(beginIdx, numBytes);
std::array<llvm::Value*,4> topics;
auto numTopics = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::LOG0);
for (size_t i = 0; i < numTopics; ++i)
topics[i] = stack.pop();
_ext.log(beginIdx, numBytes, numTopics, topics);
break;
}
default: // Invalid instruction - runtime exception default: // Invalid instruction - runtime exception
{ {
_runtimeManager.raiseException(ReturnCode::BadInstruction); _runtimeManager.raiseException(ReturnCode::BadInstruction);

6
libevmjit/Compiler.h

@ -40,13 +40,13 @@ public:
Compiler(Options const& _options); Compiler(Options const& _options);
std::unique_ptr<llvm::Module> compile(bytesConstRef _bytecode); std::unique_ptr<llvm::Module> compile(bytes const& _bytecode);
private: private:
void createBasicBlocks(bytesConstRef _bytecode); void createBasicBlocks(bytes const& _bytecode);
void compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock);
void removeDeadBlocks(); void removeDeadBlocks();

26
libevmjit/ExecutionEngine.cpp

@ -37,10 +37,9 @@ namespace jit
ExecutionEngine::ExecutionEngine() ExecutionEngine::ExecutionEngine()
{ {
} }
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtVMFace* _ext) int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, bool _outputLogs, ExtVMFace& _ext)
{ {
auto module = _module.get(); // Keep ownership of the module in _module auto module = _module.get(); // Keep ownership of the module in _module
@ -83,34 +82,13 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
clog(JIT) << "Module finalization time: " clog(JIT) << "Module finalization time: "
<< std::chrono::duration_cast<std::chrono::microseconds>(finalizationEndTime - finalizationStartTime).count(); << std::chrono::duration_cast<std::chrono::microseconds>(finalizationEndTime - finalizationStartTime).count();
// Create fake ExtVM interface
if (!_ext)
{
_ext = new ExtVMFace;
_ext->myAddress = Address(1122334455667788);
_ext->caller = Address(0xfacefacefaceface);
_ext->origin = Address(101010101010101010);
_ext->value = 0xabcd;
_ext->gasPrice = 1002;
_ext->previousBlock.hash = u256(1003);
_ext->currentBlock.coinbaseAddress = Address(1004);
_ext->currentBlock.timestamp = 1005;
_ext->currentBlock.number = 1006;
_ext->currentBlock.difficulty = 1007;
_ext->currentBlock.gasLimit = 1008;
std::string calldata = "Hello the Beautiful World of Ethereum!";
_ext->data = calldata;
unsigned char fakecode[] = {0x0d, 0x0e, 0x0a, 0x0d, 0x0b, 0x0e, 0xe, 0xf};
_ext->code = decltype(_ext->code)(fakecode, 8);
}
auto entryFunc = module->getFunction("main"); auto entryFunc = module->getFunction("main");
if (!entryFunc) if (!entryFunc)
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found")); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("main function not found"));
ReturnCode returnCode; ReturnCode returnCode;
std::jmp_buf buf; std::jmp_buf buf;
Runtime runtime(_gas, *_ext, buf); Runtime runtime(_gas, _ext, buf, _outputLogs);
auto r = setjmp(buf); auto r = setjmp(buf);
if (r == 0) if (r == 0)
{ {

2
libevmjit/ExecutionEngine.h

@ -18,7 +18,7 @@ class ExecutionEngine
public: public:
ExecutionEngine(); ExecutionEngine();
int run(std::unique_ptr<llvm::Module> module, u256& _gas, ExtVMFace* _ext = nullptr); int run(std::unique_ptr<llvm::Module> module, u256& _gas, bool _outputLogs, ExtVMFace& _ext);
bytes returnData; bytes returnData;
}; };

125
libevmjit/Ext.cpp

@ -59,6 +59,11 @@ Ext::Ext(RuntimeManager& _runtimeManager):
m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module); m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module);
m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module); m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module);
m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module); m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module);
m_log0 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_log0", module);
m_log1 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_log1", module);
m_log2 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 5}, false), Linkage::ExternalLinkage, "ext_log2", module);
m_log3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 6}, false), Linkage::ExternalLinkage, "ext_log3", module);
m_log4 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 7}, false), Linkage::ExternalLinkage, "ext_log4", module);
} }
llvm::Value* Ext::store(llvm::Value* _index) llvm::Value* Ext::store(llvm::Value* _index)
@ -160,6 +165,21 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr)
return m_builder.CreateLoad(m_args[1]); return m_builder.CreateLoad(m_args[1]);
} }
void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array<llvm::Value*,4> const& _topics)
{
static llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5};
static llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4};
args[0] = getRuntimeManager().getRuntimePtr();
m_builder.CreateStore(_memIdx, m_args[0]);
m_builder.CreateStore(_numBytes, m_args[1]);
for (size_t i = 0; i < _numTopics; ++i)
m_builder.CreateStore(_topics[i], args[i + 3]);
m_builder.CreateCall(funcs[_numTopics], llvm::ArrayRef<llvm::Value*>(args, _numTopics + 3));
}
} }
@ -289,6 +309,111 @@ extern "C"
*o_ret = eth2llvm(u256(code.size())); *o_ret = eth2llvm(u256(code.size()));
} }
void ext_show_bytes(bytesConstRef _bytes)
{
for (auto b : _bytes)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned>(b) << " ";
std::cerr << std::endl;
}
EXPORT void ext_log0(Runtime* _rt, i256* _memIdx, i256* _numBytes)
{
auto&& ext = _rt->getExt();
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
ext.log({}, dataRef);
if (_rt->outputLogs())
{
std::cerr << "LOG: ";
ext_show_bytes(dataRef);
}
}
EXPORT void ext_log1(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1)
{
auto&& ext = _rt->getExt();
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
auto topic1 = llvm2eth(*_topic1);
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
ext.log({topic1}, dataRef);
if (_rt->outputLogs())
{
std::cerr << "LOG [" << topic1 << "]: ";
ext_show_bytes(dataRef);
}
}
EXPORT void ext_log2(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2)
{
auto&& ext = _rt->getExt();
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
auto topic1 = llvm2eth(*_topic1);
auto topic2 = llvm2eth(*_topic2);
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
ext.log({topic1, topic2}, dataRef);
if (_rt->outputLogs())
{
std::cerr << "LOG [" << topic1 << "][" << topic2 << "]: ";
ext_show_bytes(dataRef);
}
}
EXPORT void ext_log3(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3)
{
auto&& ext = _rt->getExt();
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
auto topic1 = llvm2eth(*_topic1);
auto topic2 = llvm2eth(*_topic2);
auto topic3 = llvm2eth(*_topic3);
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
ext.log({topic1, topic2, topic3}, dataRef);
if (_rt->outputLogs())
{
std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "]: ";
ext_show_bytes(dataRef);
}
}
EXPORT void ext_log4(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3, i256* _topic4)
{
auto&& ext = _rt->getExt();
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
auto topic1 = llvm2eth(*_topic1);
auto topic2 = llvm2eth(*_topic2);
auto topic3 = llvm2eth(*_topic3);
auto topic4 = llvm2eth(*_topic4);
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
ext.log({topic1, topic2, topic3, topic4}, dataRef);
if (_rt->outputLogs())
{
std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "][" << topic4 << "]: ";
ext_show_bytes(dataRef);
}
}
} }
} }
} }

7
libevmjit/Ext.h

@ -31,8 +31,10 @@ public:
llvm::Value* codeAt(llvm::Value* _addr); llvm::Value* codeAt(llvm::Value* _addr);
llvm::Value* codesizeAt(llvm::Value* _addr); llvm::Value* codesizeAt(llvm::Value* _addr);
void log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array<llvm::Value*,4> const& _topics);
private: private:
llvm::Value* m_args[2]; llvm::Value* m_args[2];
llvm::Value* m_arg2; llvm::Value* m_arg2;
llvm::Value* m_arg3; llvm::Value* m_arg3;
@ -53,6 +55,11 @@ private:
llvm::Function* m_exp; llvm::Function* m_exp;
llvm::Function* m_codeAt; llvm::Function* m_codeAt;
llvm::Function* m_codesizeAt; llvm::Function* m_codesizeAt;
llvm::Function* m_log0;
llvm::Function* m_log1;
llvm::Function* m_log2;
llvm::Function* m_log3;
llvm::Function* m_log4;
}; };

2
libevmjit/GasMeter.cpp

@ -5,7 +5,7 @@
#include <llvm/IR/Function.h> #include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h> #include <llvm/IR/IntrinsicInst.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include <libevm/FeeStructure.h> #include <libevm/FeeStructure.h>
#include "Type.h" #include "Type.h"

2
libevmjit/GasMeter.h

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
#include "CompilerHelper.h" #include "CompilerHelper.h"

18
libevmjit/Memory.cpp

@ -147,24 +147,18 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet
llvm::Value* Memory::loadWord(llvm::Value* _addr) llvm::Value* Memory::loadWord(llvm::Value* _addr)
{ {
auto value = m_builder.CreateCall(m_loadWord, _addr); auto value = m_builder.CreateCall(m_loadWord, _addr);
dump(0);
return value; return value;
} }
void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{ {
m_builder.CreateCall2(m_storeWord, _addr, _word); m_builder.CreateCall2(m_storeWord, _addr, _word);
dump(0);
} }
void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{ {
auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
m_builder.CreateCall2(m_storeByte, _addr, byte); m_builder.CreateCall2(m_storeByte, _addr, byte);
dump(0);
} }
llvm::Value* Memory::getData() llvm::Value* Memory::getData()
@ -205,18 +199,6 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value*
m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0); m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0);
} }
void Memory::dump(uint64_t _begin, uint64_t _end)
{
if (getenv("EVMCC_DEBUG_MEMORY") == nullptr)
return;
auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin);
auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end);
std::vector<llvm::Value*> args = {beginVal, endVal};
m_builder.CreateCall(m_memDump, llvm::ArrayRef<llvm::Value*>(args));
}
} }
} }
} }

2
libevmjit/Memory.h

@ -27,8 +27,6 @@ public:
/// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory. /// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory.
void require(llvm::Value* _offset, llvm::Value* _size); void require(llvm::Value* _offset, llvm::Value* _size);
void dump(uint64_t _begin, uint64_t _end = 0);
private: private:
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter);
llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager);

10
libevmjit/Runtime.cpp

@ -58,8 +58,9 @@ llvm::Twine getName(RuntimeData::Index _index)
} }
} }
Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf): Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs):
m_ext(_ext) m_ext(_ext),
m_outputLogs(_outputLogs)
{ {
set(RuntimeData::Gas, _gas); set(RuntimeData::Gas, _gas);
set(RuntimeData::Address, fromAddress(_ext.myAddress)); set(RuntimeData::Address, fromAddress(_ext.myAddress));
@ -101,6 +102,11 @@ bytesConstRef Runtime::getReturnData() const
return {m_memory.data() + offset, size}; return {m_memory.data() + offset, size};
} }
bool Runtime::outputLogs() const
{
return m_outputLogs;
}
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder)
{ {

4
libevmjit/Runtime.h

@ -63,7 +63,7 @@ using MemoryImpl = bytes;
class Runtime class Runtime
{ {
public: public:
Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf); Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs);
Runtime(const Runtime&) = delete; Runtime(const Runtime&) = delete;
void operator=(const Runtime&) = delete; void operator=(const Runtime&) = delete;
@ -77,6 +77,7 @@ public:
u256 getGas() const; u256 getGas() const;
bytesConstRef getReturnData() const; bytesConstRef getReturnData() const;
decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; } decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; }
bool outputLogs() const;
private: private:
void set(RuntimeData::Index _index, u256 _value); void set(RuntimeData::Index _index, u256 _value);
@ -86,6 +87,7 @@ private:
StackImpl m_stack; StackImpl m_stack;
MemoryImpl m_memory; MemoryImpl m_memory;
ExtVMFace& m_ext; ExtVMFace& m_ext;
bool m_outputLogs; ///< write LOG statements to console
}; };
class RuntimeManager: public CompilerHelper class RuntimeManager: public CompilerHelper

2
libevmjit/Utils.cpp

@ -35,7 +35,7 @@ i256 eth2llvm(u256 _u)
return i; return i;
} }
u256 readPushData(const byte*& _curr, const byte* _end) u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end)
{ {
auto pushInst = *_curr; auto pushInst = *_curr;
assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32);

4
libevmjit/Utils.h

@ -5,7 +5,7 @@
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libevmface/Instruction.h> #include <libevmcore/Instruction.h>
namespace dev namespace dev
{ {
@ -33,7 +33,7 @@ i256 eth2llvm(u256);
/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it /// Reads PUSH data from pointed fragment of bytecode and constructs number out of it
/// Reading out of bytecode means reading 0 /// Reading out of bytecode means reading 0
/// @param _curr is updates and points the last real byte read /// @param _curr is updates and points the last real byte read
u256 readPushData(const byte*& _curr, const byte* _end); u256 readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end);
#define ANY_PUSH PUSH1: \ #define ANY_PUSH PUSH1: \
case Instruction::PUSH2: \ case Instruction::PUSH2: \

2
libevmjit/VM.cpp

@ -20,7 +20,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t)
auto module = Compiler(defaultOptions).compile(_ext.code); auto module = Compiler(defaultOptions).compile(_ext.code);
ExecutionEngine engine; ExecutionEngine engine;
auto exitCode = engine.run(std::move(module), m_gas, &_ext); auto exitCode = engine.run(std::move(module), m_gas, false, _ext);
switch (static_cast<ReturnCode>(exitCode)) switch (static_cast<ReturnCode>(exitCode))
{ {

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;

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

Loading…
Cancel
Save