From 11d34902bd7a33eca88324074bcb51a89c73a5ee Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Dec 2014 21:45:16 +0000 Subject: [PATCH 01/59] Fixed uncles allowed. --- evmjit | 2 +- libethereum/State.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evmjit b/evmjit index 1b490244b..66d5a2b5c 160000 --- a/evmjit +++ b/evmjit @@ -1 +1 @@ -Subproject commit 1b490244bf4864b96448d56a7cd20f3d5b0a0b9b +Subproject commit 66d5a2b5cdf1361dcf0205b191dd12be090ed224 diff --git a/libethereum/State.cpp b/libethereum/State.cpp index e02b06bcd..f4114a148 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -563,7 +563,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const* _bc, bool _checkNonce) if (_bc) { BlockInfo uncleParent(_bc->block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 6) + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) BOOST_THROW_EXCEPTION(UncleTooOld()); uncle.verifyParent(uncleParent); } From 78cbce595d5711c85561fbcf1bf56995d7fd4bc1 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 12:01:35 +0000 Subject: [PATCH 02/59] Possible fix for #660. --- libethcore/Exceptions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index c6f35763e..9bafb04d8 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,7 +26,11 @@ using namespace std; using namespace dev; using namespace dev::eth; -#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); +#if _MSC_VER +#define thread_local __declspec( thread ) +#endif + +#define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } From 5ad8633c12995d1cf77af39775167c55ed888389 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 12:06:38 +0000 Subject: [PATCH 03/59] Add mergeMaster script. --- mergeMaster.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 mergeMaster.sh diff --git a/mergeMaster.sh b/mergeMaster.sh new file mode 100755 index 000000000..a55502799 --- /dev/null +++ b/mergeMaster.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +git checkout master && git merge --no-ff $1+ && git push && git tag -f $1 && git push --tags -f + From 7775503c168bf9ac2f76e9133a3ce45398004b93 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 13 Jan 2015 12:20:07 +0000 Subject: [PATCH 04/59] Warnings fixes. --- libdevcrypto/CryptoPP.cpp | 3 +++ libsolidity/SourceReferenceFormatter.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 766ca485d..225f36dec 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -198,6 +198,9 @@ bool Secp256k1::verifySecret(Secret const& _s, Public& _p) void Secp256k1::agree(Secret const& _s, Public const& _r, h256& o_s) { + (void)_s; + (void)_r; + (void)o_s; ECDH::Domain d(m_oid); assert(d.AgreedValueLength() == sizeof(o_s)); byte remote[65] = {0x04}; diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h index 8e3f126f0..98f1c745d 100644 --- a/libsolidity/SourceReferenceFormatter.h +++ b/libsolidity/SourceReferenceFormatter.h @@ -28,7 +28,7 @@ namespace dev { -class Exception; // forward +struct Exception; // forward namespace solidity { From 92b76d49458fe654731d7162e05ff292cd9ea360 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 13 Jan 2015 13:36:21 +0100 Subject: [PATCH 05/59] new vps address --- extdep/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extdep/CMakeLists.txt b/extdep/CMakeLists.txt index 19cd00f7b..fdee34602 100644 --- a/extdep/CMakeLists.txt +++ b/extdep/CMakeLists.txt @@ -7,7 +7,7 @@ include(eth_download.cmake) # all dependencies will be installed into this directory, separated by platform string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) set(ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/install/${_system_name}") -set(ETH_DEPENDENCY_SERVER "http://poc-7.ethdev.com/precompiled/${_system_name}") +set(ETH_DEPENDENCY_SERVER "http://build.ethdev.com/builds/${_system_name}-precompiled") file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/lib) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/include) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/bin) From ed775c31c75fce8d72c67d6f97fb6a37a36f11bb Mon Sep 17 00:00:00 2001 From: caktux Date: Mon, 19 Jan 2015 21:23:16 -0500 Subject: [PATCH 06/59] apply 565e3f1 and 8a3eac3 --- libdevcore/Exceptions.h | 2 +- libethcore/Exceptions.cpp | 11 +- neth/main.cpp | 272 +++++++++++++++++++++----------------- 3 files changed, 162 insertions(+), 123 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 5d03c195f..840fe3031 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -30,7 +30,7 @@ namespace dev { // base class for all exceptions -struct Exception: virtual std::exception, virtual boost::exception {}; +struct Exception: virtual std::exception, virtual boost::exception { mutable std::string m_message; }; struct BadHexCharacter: virtual Exception {}; struct RLPException: virtual Exception {}; diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index 9bafb04d8..7dfc28334 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,11 +26,14 @@ using namespace std; using namespace dev; using namespace dev::eth; -#if _MSC_VER -#define thread_local __declspec( thread ) -#endif - +#if ALL_COMPILERS_ARE_CPP11 #define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str(); +#elsif USE_BOOST_TLS +static boost::thread_specific_ptr g_exceptionMessage; +#define ETH_RETURN_STRING(S) if (!g_exceptionMessage.get()); g_exceptionMessage.reset(new string); *g_exceptionMessage.get() = S; return g_exceptionMessage.get()->c_str(); +#else +#define ETH_RETURN_STRING(S) m_message = S; return m_message.c_str(); +#endif const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } diff --git a/neth/main.cpp b/neth/main.cpp index 8552177ce..06be53393 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -63,54 +64,54 @@ void help() { cout << "Usage neth [OPTIONS] " << endl - << "Options:" << endl - << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl - << " -c,--client-name Add a name to your client's version string (default: blank)." << endl - << " -d,--db-path Load database from path (default: ~/.ethereum " << endl - << " /Etherum or Library/Application Support/Ethereum)." << endl - << " -h,--help Show this help message and exit." << endl + << "Options:" << endl + << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl + << " -c,--client-name Add a name to your client's version string (default: blank)." << endl + << " -d,--db-path Load database from path (default: ~/.ethereum " << endl + << " /Etherum or Library/Application Support/Ethereum)." << endl + << " -h,--help Show this help message and exit." << endl #if ETH_JSONRPC - << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl - << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl + << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl + << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl #endif - << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl - << " -m,--mining Enable mining (default: off)" << endl - << " -n,--upnp Use upnp for NAT (default: on)." << endl - << " -o,--mode Start a full node or a peer node (Default: full)." << endl - << " -p,--port Connect to remote port (default: 30303)." << endl - << " -r,--remote Connect to remote host (default: none)." << endl - << " -s,--secret Set the secret key for use with send command (default: auto)." << endl - << " -u,--public-ip Force public ip to given (default; auto)." << endl - << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl - << " -x,--peers Attempt to connect to given number of peers (default: 5)." << endl - << " -V,--version Show the version and exit." << endl; - exit(0); + << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl + << " -m,--mining Enable mining (default: off)" << endl + << " -n,--upnp Use upnp for NAT (default: on)." << endl + << " -o,--mode Start a full node or a peer node (Default: full)." << endl + << " -p,--port Connect to remote port (default: 30303)." << endl + << " -r,--remote Connect to remote host (default: none)." << endl + << " -s,--secret Set the secret key for use with send command (default: auto)." << endl + << " -u,--public-ip Force public ip to given (default; auto)." << endl + << " -v,--verbosity <0..9> Set the log verbosity from 0 to 9 (tmp forced to 1)." << endl + << " -x,--peers Attempt to connect to given number of peers (default: 5)." << endl + << " -V,--version Show the version and exit." << endl; + exit(0); } void interactiveHelp() { cout - << "Commands:" << endl - << " netstart Starts the network sybsystem on a specific port." << endl - << " netstop Stops the network subsystem." << endl + << "Commands:" << endl + << " netstart Starts the network sybsystem on a specific port." << endl + << " netstop Stops the network subsystem." << endl #if ETH_JSONRPC - << " jsonstart Starts the JSON-RPC server." << endl - << " jsonstop Stops the JSON-RPC server." << endl + << " jsonstart Starts the JSON-RPC server." << endl + << " jsonstop Stops the JSON-RPC server." << endl #endif - << " connect Connects to a specific peer." << endl - << " minestart Starts mining." << endl - << " minestop Stops mining." << endl - << " address Gives the current address." << endl - << " secret Gives the current secret" << endl - << " block Gives the current block height." << endl - << " balance Gives the current balance." << endl - << " peers List the peers that are connected" << endl - << " transact Execute a given transaction." << endl - << " send Execute a given transaction with current secret." << endl - << " contract Create a new contract with current secret." << endl - << " inspect Dumps a contract to /.evm." << endl - << " reset Resets ncurses windows" << endl - << " exit Exits the application." << endl; + << " connect Connects to a specific peer." << endl + << " minestart Starts mining." << endl + << " minestop Stops mining." << endl + << " address Gives the current address." << endl + << " secret Gives the current secret" << endl + << " block Gives the current block height." << endl + << " balance Gives the current balance." << endl + << " peers List the peers that are connected" << endl + << " transact Execute a given transaction." << endl + << " send Execute a given transaction with current secret." << endl + << " contract Create a new contract with current secret." << endl + << " inspect Dumps a contract to /.evm." << endl + << " reset Resets ncurses windows" << endl + << " exit Exits the application." << endl; } string credits() @@ -121,17 +122,8 @@ string credits() << " Code by Gav Wood & , (c) 2013, 2014." << endl << " Based on a design by Vitalik Buterin." << endl << endl; - string vs = toString(dev::Version); - vs = vs.substr(vs.find_first_of('.') + 1)[0]; - int pocnumber = stoi(vs); - string m_servers; - if (pocnumber == 5) - m_servers = "54.72.69.180"; - else - m_servers = "54.76.56.74"; - ccout << "Type 'netstart 30303' to start networking" << endl; - ccout << "Type 'connect " << m_servers << " 30303' to connect" << endl; + ccout << "Type 'connect " << Host::pocHost() << " 30303' to connect" << endl; ccout << "Type 'exit' to quit" << endl << endl; return ccout.str(); } @@ -139,12 +131,13 @@ string credits() void version() { cout << "neth version " << dev::Version << endl; + cout << "Network protocol version: " << dev::eth::c_protocolVersion << endl; + cout << "Client database version: " << dev::eth::c_databaseVersion << endl; cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; exit(0); } Address c_config = Address("661005d2720d855f1d9976f88bb10c1a3398c77f"); - string pretty(h160 _a, dev::eth::State _st) { string ns; @@ -161,6 +154,13 @@ string pretty(h160 _a, dev::eth::State _st) return ns; } +bool g_exit = false; + +void sighandler(int) +{ + g_exit = true; +} + namespace nc { @@ -298,13 +298,17 @@ int main(int argc, char** argv) string remoteHost; unsigned short remotePort = 30303; string dbPath; - bool mining = false; + unsigned mining = ~(unsigned)0; + NodeMode mode = NodeMode::Full; unsigned peers = 5; #if ETH_JSONRPC int jsonrpc = 8080; #endif string publicIP; + bool bootstrap = false; bool upnp = true; + bool useLocal = false; + bool forceMining = false; string clientName; // Init defaults @@ -365,14 +369,21 @@ int main(int argc, char** argv) { string m = argv[++i]; if (isTrue(m)) - mining = true; + mining = ~(unsigned)0; else if (isFalse(m)) - mining = false; + mining = 0; + else if (int i = stoi(m)) + mining = i; else { - cerr << "Unknown mining option: " << m << endl; + cerr << "Unknown -m/--mining option: " << m << endl; + return -1; } } + else if (arg == "-b" || arg == "--bootstrap") + bootstrap = true; + else if (arg == "-f" || arg == "--force-mining") + forceMining = true; #if ETH_JSONRPC else if ((arg == "-j" || arg == "--json-rpc")) jsonrpc = jsonrpc ? jsonrpc : 8080; @@ -394,12 +405,50 @@ int main(int argc, char** argv) if (!clientName.empty()) clientName += "/"; - WebThreeDirect web3("NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), dbPath); - Client& c = *web3.ethereum(); + cout << credits(); + + NetworkPreferences netPrefs(listenPort, publicIP, upnp, useLocal); + dev::WebThreeDirect web3( + "NEthereum(++)/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), + dbPath, + false, + mode == NodeMode::Full ? set{"eth", "shh"} : set(), + netPrefs + ); + web3.setIdealPeerCount(peers); + eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr; + + if (c) + { + c->setForceMining(forceMining); + c->setAddress(coinbase); + } - c.setForceMining(true); + auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp"); + web3.restoreNodes(&nodesState); - cout << credits(); + web3.startNetwork(); + + if (bootstrap) + web3.connect(Host::pocHost()); + if (remoteHost.size()) + web3.connect(remoteHost, remotePort); + +#if ETH_JSONRPC + shared_ptr jsonrpcServer; + unique_ptr jsonrpcConnector; + if (jsonrpc > -1) + { + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); + jsonrpcServer->setIdentities({us}); + jsonrpcServer->StartListening(); + } +#endif + + signal(SIGABRT, &sighandler); + signal(SIGTERM, &sighandler); + signal(SIGINT, &sighandler); std::ostringstream ccout; @@ -461,28 +510,6 @@ int main(int argc, char** argv) wmove(mainwin, 1, 4); - if (!remoteHost.empty()) - { - web3.setIdealPeerCount(peers); - web3.setNetworkPreferences(NetworkPreferences(listenPort, publicIP, upnp)); - web3.startNetwork(); - web3.connect(remoteHost, remotePort); - } - if (mining) - c.startMining(); - -#if ETH_JSONRPC - shared_ptr jsonrpcServer; - unique_ptr jsonrpcConnector; - if (jsonrpc > -1) - { - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); - jsonrpcServer->setIdentities({us}); - jsonrpcServer->StartListening(); - } -#endif - while (true) { wclrtobot(consolewin); @@ -532,13 +559,25 @@ int main(int argc, char** argv) { web3.stopNetwork(); } - else if (cmd == "minestart") + else if (c && cmd == "minestart") + { + c->startMining(); + } + else if (c && cmd == "minestop") { - c.startMining(); + c->stopMining(); } - else if (cmd == "minestop") + else if (c && cmd == "mineforce") { - c.stopMining(); + string enable; + iss >> enable; + c->setForceMining(isTrue(enable)); + } + else if (cmd == "verbosity") + { + if (iss.peek() != -1) + iss >> g_logVerbosity; + cout << "Verbosity: " << g_logVerbosity << endl; } #if ETH_JSONRPC else if (cmd == "jsonport") @@ -575,7 +614,7 @@ int main(int argc, char** argv) } else if (cmd == "block") { - unsigned n = c.blockChain().details().number; + unsigned n = c->blockChain().details().number; ccout << "Current block # "; ccout << toString(n) << endl; } @@ -588,13 +627,13 @@ int main(int argc, char** argv) } else if (cmd == "balance") { - u256 balance = c.balanceAt(us.address()); + u256 balance = c->balanceAt(us.address()); ccout << "Current balance:" << endl; ccout << toString(balance) << endl; } else if (cmd == "transact") { - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); @@ -663,7 +702,7 @@ int main(int argc, char** argv) { Secret secret = h256(fromHex(sechex)); Address dest = h160(fromHex(fields[0])); - c.transact(secret, amount, dest, data, gas, gasPrice); + c->transact(secret, amount, dest, data, gas, gasPrice); } } } @@ -696,19 +735,19 @@ int main(int argc, char** argv) } else { - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(fields[0])); - c.transact(us.secret(), amount, dest, bytes(), minGas); + c->transact(us.secret(), amount, dest, bytes(), minGas); } } } else if (cmd == "contract") { - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); @@ -768,7 +807,7 @@ int main(int argc, char** argv) cwarn << "Minimum gas amount is" << minGas; else { - c.transact(us.secret(), endowment, init, gas); + c->transact(us.secret(), endowment, init, gas); } } } @@ -786,10 +825,10 @@ int main(int argc, char** argv) try { - auto storage = c.storageAt(address); + auto storage = c->storageAt(address); for (auto const& i: storage) s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; - s << endl << disassemble(c.codeAt(address)) << endl; + s << endl << disassemble(c->codeAt(address)) << endl; string outFile = getDataDir() + "/" + rechex + ".evm"; ofstream ofs; @@ -824,7 +863,7 @@ int main(int argc, char** argv) // Lock to prevent corrupt block-chain errors - auto const& bc = c.blockChain(); + auto const& bc = c->blockChain(); ccout << "Genesis hash: " << bc.genesisHash() << endl; // Blocks @@ -838,11 +877,11 @@ int main(int argc, char** argv) auto b = bc.block(h); for (auto const& i: RLP(b)[1]) { - Transaction t(i[0].data()); + Transaction t(i.data()); auto s = t.receiveAddress() ? boost::format(" %1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + (c->codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % toString(t.receiveAddress()) % toString(formatBalance(t.value())) % toString((unsigned)t.nonce()) : @@ -862,12 +901,12 @@ int main(int argc, char** argv) // Pending y = 1; - for (Transaction const& t: c.pending()) + for (Transaction const& t: c->pending()) { auto s = t.receiveAddress() ? boost::format("%1% %2%> %3%: %4% [%5%]") % toString(t.safeSender()) % - (c.codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % + (c->codeAt(t.receiveAddress(), 0).size() ? '*' : '-') % toString(t.receiveAddress()) % toString(formatBalance(t.value())) % toString((unsigned)t.nonce()) : @@ -877,7 +916,7 @@ int main(int argc, char** argv) toString(formatBalance(t.value())) % toString((unsigned)t.nonce()); mvwaddnstr(pendingwin, y++, x, s.str().c_str(), qwidth); - if (y > height * 1 / 5 - 4) + if (y > height * 1 / 5 - 2) break; } @@ -885,27 +924,27 @@ int main(int argc, char** argv) // Contracts and addresses y = 1; int cc = 1; - auto acs = c.addresses(); + auto acs = c->addresses(); for (auto const& i: acs) - if (c.codeAt(i, 0).size()) + if (c->codeAt(i, 0).size()) { auto s = boost::format("%1%%2% : %3% [%4%]") % toString(i) % - pretty(i, c.postState()) % - toString(formatBalance(c.balanceAt(i))) % - toString((unsigned)c.countAt(i, 0)); + pretty(i, c->postState()) % + toString(formatBalance(c->balanceAt(i))) % + toString((unsigned)c->countAt(i, 0)); mvwaddnstr(contractswin, cc++, x, s.str().c_str(), qwidth); if (cc > qheight - 2) break; } for (auto const& i: acs) - if (c.codeAt(i, 0).empty()) + if (c->codeAt(i, 0).empty()) { auto s = boost::format("%1%%2% : %3% [%4%]") % toString(i) % - pretty(i, c.postState()) % - toString(formatBalance(c.balanceAt(i))) % - toString((unsigned)c.countAt(i, 0)); + pretty(i, c->postState()) % + toString(formatBalance(c->balanceAt(i))) % + toString((unsigned)c->countAt(i, 0)); mvwaddnstr(addswin, y++, x, s.str().c_str(), width / 2 - 4); if (y > height * 3 / 5 - 4) break; @@ -935,21 +974,18 @@ int main(int argc, char** argv) // Balance stringstream ssb; - u256 balance = c.balanceAt(us.address()); - Address coinsAddr = right160(c.stateAt(c_config, 1)); - Address gavCoin = right160(c.stateAt(coinsAddr, c.stateAt(coinsAddr, 1))); - u256 totalGavCoinBalance = c.stateAt(gavCoin, (u160)us.address()); - ssb << "Balance: " << formatBalance(balance) << " | " << totalGavCoinBalance << " GAV"; + u256 balance = c->balanceAt(us.address()); + ssb << "Balance: " << formatBalance(balance); mvwprintw(consolewin, 0, x, ssb.str().c_str()); // Block mvwprintw(blockswin, 0, x, "Block # "); - unsigned n = c.blockChain().details().number; + unsigned n = c->blockChain().details().number; mvwprintw(blockswin, 0, 10, toString(n).c_str()); // Pending string pc; - pc = "Pending: " + toString(c.pending().size()); + pc = "Pending: " + toString(c->pending().size()); mvwprintw(pendingwin, 0, x, pc.c_str()); // Contracts @@ -962,10 +998,10 @@ int main(int argc, char** argv) mvwprintw(peerswin, 0, 9, toString(web3.peers().size()).c_str()); // Mining flag - if (c.isMining()) + if (c->isMining()) { mvwprintw(consolewin, qheight - 1, width / 4 - 11, "Mining ON"); - dev::eth::MineProgress p = c.miningProgress(); + dev::eth::MineProgress p = c->miningProgress(); auto speed = boost::format("%2% kH/s @ %1%s") % (p.ms / 1000) % (p.ms ? p.hashes / p.ms : 0); mvwprintw(consolewin, qheight - 2, width / 4 - speed.str().length() - 2, speed.str().c_str()); } From 3f6c914c5971f4e7d1bdcfd7b50d731cd55c3adc Mon Sep 17 00:00:00 2001 From: caktux Date: Mon, 19 Jan 2015 23:08:24 -0500 Subject: [PATCH 07/59] fix warning and #823 --- neth/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neth/main.cpp b/neth/main.cpp index 06be53393..96fc52de5 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -433,6 +433,8 @@ int main(int argc, char** argv) web3.connect(Host::pocHost()); if (remoteHost.size()) web3.connect(remoteHost, remotePort); + if (mining) + c->startMining(); #if ETH_JSONRPC shared_ptr jsonrpcServer; From 808b646de39c6774da3e254f0a28e1144a231db1 Mon Sep 17 00:00:00 2001 From: caktux Date: Thu, 22 Jan 2015 23:39:20 -0500 Subject: [PATCH 08/59] build status table by OS and branch --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cfa223a56..7b9a78e6c 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,11 @@ ## Ethereum C++ Client. -[![Build -Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build -Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop - By Gav Wood, 2014. -[![Build -+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) master [![Build -+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) develop + | Linux | OSX | Windows +----------|---------|-----|-------- +develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) +master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) [![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) From 34ada783f10437c137b3ed0347731de1729ca3a8 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 13 Feb 2015 14:49:32 +0300 Subject: [PATCH 09/59] Suicide Tests --- test/stTransactionTestFiller.json | 144 +++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 3 deletions(-) diff --git a/test/stTransactionTestFiller.json b/test/stTransactionTestFiller.json index 214a0ae7c..bece551a3 100644 --- a/test/stTransactionTestFiller.json +++ b/test/stTransactionTestFiller.json @@ -208,7 +208,7 @@ } }, - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "1000000", "code" : "{ (CALL 5000 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b 1 0 0 0 0) }", "nonce" : "0", @@ -216,7 +216,7 @@ } }, - "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "0", "code" : "{[[1]]55}", "nonce" : "0", @@ -523,6 +523,144 @@ } }, + "SuicidesAndInternlCallSuicidesOOG" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10", + "code" : "{(SUICIDE 0) (CALL 19 0 1 0 0 0 0) }", + "nonce" : "0", + "storage" : { + } + }, + + "0000000000000000000000000000000000000000" : { + "balance" : "0", + "code" : "{(SUICIDE 1)}", + "nonce" : "0", + "storage" : { + } + } + + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "SuicidesAndInternlCallSuicides" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10", + "code" : "{(SUICIDE 0) (CALL 200 0 1 0 0 0 0) }", + "nonce" : "0", + "storage" : { + } + }, + + "0000000000000000000000000000000000000000" : { + "balance" : "0", + "code" : "{(SUICIDE 1)}", + "nonce" : "0", + "storage" : { + } + } + + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "1700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "SuicidesAndSendMoneyToItself" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000", + "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", + "nonce" : "0", + "storage" : { + } + } + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "1700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + "TransactionNonceCheck" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", @@ -994,7 +1132,7 @@ } }, - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "0", "code" : "{(MSTORE 0 0x600c600055) (CREATE 0 27 5)}", "nonce" : "0", From b1077bfd297fd5aa4579865347e5c8e373b833bf Mon Sep 17 00:00:00 2001 From: winsvega Date: Mon, 16 Feb 2015 20:04:11 +0300 Subject: [PATCH 10/59] Test Correction WrongAddress removed new suicides --- test/stTransactionTestFiller.json | 96 +++++++++++++++++++++++++++++-- test/ttTransactionTestFiller.json | 15 ----- 2 files changed, 92 insertions(+), 19 deletions(-) diff --git a/test/stTransactionTestFiller.json b/test/stTransactionTestFiller.json index bece551a3..73026608d 100644 --- a/test/stTransactionTestFiller.json +++ b/test/stTransactionTestFiller.json @@ -544,7 +544,7 @@ "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10", - "code" : "{(SUICIDE 0) (CALL 19 0 1 0 0 0 0) }", + "code" : "{(CALL 0 0 1 0 0 0 0) (SUICIDE 0)}", "nonce" : "0", "storage" : { } @@ -593,7 +593,7 @@ "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10", - "code" : "{(SUICIDE 0) (CALL 200 0 1 0 0 0 0) }", + "code" : "{(CALL 20 0 1 0 0 0 0) (SUICIDE 0)}", "nonce" : "0", "storage" : { } @@ -612,7 +612,7 @@ "transaction" : { "data" : "", - "gasLimit" : "1700", + "gasLimit" : "700", "gasPrice" : "1", "nonce" : "", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -621,7 +621,55 @@ } }, - "SuicidesAndSendMoneyToItself" : { + "SuicidesStopAfterSuicide" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000", + "code" : "{(SUICIDE 0) (CALL 0 2000 0 0 0 0 0) }", + "nonce" : "0", + "storage" : { + } + }, + + "0000000000000000000000000000000000000000" : { + "balance" : "1110", + "code" : "{(SUICIDE 1)}", + "nonce" : "0", + "storage" : { + } + } + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "3700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "c94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + + "SuicidesAndSendMoneyToItselfEtherDestroyed" : { "env" : { "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", "currentDifficulty" : "45678256", @@ -661,6 +709,46 @@ } }, + "SuicidesMixingCoinbase" : { + "env" : { + "currentCoinbase" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "7000", + "code" : "", + "nonce" : "0", + "storage" : { + } + }, + + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000", + "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", + "nonce" : "0", + "storage" : { + } + } + }, + + "transaction" : + { + "data" : "", + "gasLimit" : "1700", + "gasPrice" : "1", + "nonce" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10" + } + }, + "TransactionNonceCheck" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", diff --git a/test/ttTransactionTestFiller.json b/test/ttTransactionTestFiller.json index e9ae27188..78615bb45 100644 --- a/test/ttTransactionTestFiller.json +++ b/test/ttTransactionTestFiller.json @@ -241,21 +241,6 @@ } }, - "WrongAddress" : { - "transaction" : - { - "data" : "", - "gasLimit" : "", - "gasPrice" : "", - "nonce" : "", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d8v", - "value" : "", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - } - }, - "AddressMoreThan20" : { "transaction" : { From 4fbeff27d613a4e13452489acd6cfc5e94e8f620 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 17 Feb 2015 20:00:30 +0100 Subject: [PATCH 11/59] Squashed 'libjsqrc/ethereumjs/' changes from 82cc5f6..9a85b09 9a85b09 version upgrade ec6f9b3 added transactionCount && uncleCount methods b96a7aa gulp cleanup d6128f2 coveralls badge points to master efee649 coveralls badge 339f565 travis coveralls 27d53dd travis coveralls 001077e Merge pull request #59 from cubedro/master 9902977 updated dist af7c26b check request.status in httpsync.js to prevent throwing errors when undefined ad8112c Merge pull request #15 from ethereum/master d1e6b20 updated README c184728 version upgrade 3d652e8 fixed web3.reset() 26561e4 fixed #51 03661d3 eth_polling_timeout const 9e806cc Merge branch 'master' into develop 82d32bb providermanager -> requestmanager a86fccf web3 refactor (in progress) c29f4a1 filters refactor 9d84609 Merge branch 'master' of https://github.com/ethereum/ethereum.js 859a199 Merge pull request #55 from ethereum/develop fd5146d Merge pull request #12 from debris/master git-subtree-dir: libjsqrc/ethereumjs git-subtree-split: 9a85b098a082f9ed38bcf92ab5ee6ba64489d7cf --- .gitignore | 1 + .travis.yml | 2 +- README.md | 8 +- bower.json | 2 +- dist/ethereum.js | 712 +++++++++++++++++++++++++---------------- dist/ethereum.js.map | 26 +- dist/ethereum.min.js | 2 +- gulpfile.js | 97 ++---- index.js | 4 - lib/const.js | 3 +- lib/contract.js | 5 +- lib/db.js | 35 ++ lib/eth.js | 85 +++++ lib/filter.js | 142 ++++---- lib/httpsync.js | 8 +- lib/providermanager.js | 102 ------ lib/requestmanager.js | 103 ++++++ lib/shh.js | 37 +++ lib/watches.js | 49 +++ lib/web3.js | 177 +++------- package.json | 18 +- test/eth.methods.js | 2 + test/filter.methods.js | 27 ++ test/web3.methods.js | 11 + 24 files changed, 991 insertions(+), 667 deletions(-) create mode 100644 lib/db.js create mode 100644 lib/eth.js delete mode 100644 lib/providermanager.js create mode 100644 lib/requestmanager.js create mode 100644 lib/shh.js create mode 100644 lib/watches.js create mode 100644 test/filter.methods.js diff --git a/.gitignore b/.gitignore index 399b6dc88..c2dd6b86d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # git config --global core.excludesfile ~/.gitignore_global *.swp +/coverage /tmp */**/*un~ *un~ diff --git a/.travis.yml b/.travis.yml index 83b21d840..558fd1537 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,5 @@ script: - "jshint *.js lib" after_script: - npm run-script build - - npm test + - npm run-script test-coveralls diff --git a/README.md b/README.md index 02988fe73..0a8bd092d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API) which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js -[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url] +[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url][![Coverage Status][coveralls-image]][coveralls-url] @@ -30,9 +30,9 @@ Require the library: var web3 = require('web3'); -Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider) +Set a provider (QtSyncProvider, HttpSyncProvider) - var web3.setProvider(new web3.providers.WebSocketProvider('ws://localhost:40404/eth')); + web3.setProvider(new web3.providers.HttpSyncProvider()); There you go, now you can use it: @@ -93,4 +93,6 @@ ethereum -ws -loglevel=4 [dep-url]: https://david-dm.org/ethereum/ethereum.js [dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg [dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies +[coveralls-image]: https://coveralls.io/repos/ethereum/ethereum.js/badge.svg?branch=master +[coveralls-url]: https://coveralls.io/r/ethereum/ethereum.js?branch=master diff --git a/bower.json b/bower.json index 168f1b39a..b9a048718 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.13", + "version": "0.0.15", "description": "Ethereum Compatible JavaScript API", "main": ["./dist/ethereum.js", "./dist/ethereum.min.js"], "dependencies": { diff --git a/dist/ethereum.js b/dist/ethereum.js index 4c36a7c71..712e5d259 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -210,7 +210,7 @@ module.exports = { }; -},{"./const":2,"./formatters":6,"./types":11,"./utils":12,"./web3":13}],2:[function(require,module,exports){ +},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -264,7 +264,8 @@ module.exports = { ETH_PADDING: 32, ETH_SIGNATURE_LENGTH: 4, ETH_UNITS: ETH_UNITS, - ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, + ETH_POLLING_TIMEOUT: 1000 }; @@ -295,6 +296,7 @@ var web3 = require('./web3'); var abi = require('./abi'); var utils = require('./utils'); var eventImpl = require('./event'); +var filter = require('./filter'); var exportNatspecGlobals = function (vars) { // it's used byt natspec.js @@ -416,11 +418,11 @@ var addEventsToContract = function (contract, desc, address) { var signature = abi.eventSignatureFromAscii(e.name); var event = eventImpl.inputParser(address, signature, e); var o = event.apply(null, params); - o._onWatchEventResult = function (data) { + var outputFormatter = function (data) { var parser = eventImpl.outputParser(e); return parser(data); }; - return web3.eth.watch(o); + return web3.eth.watch(o, undefined, undefined, outputFormatter); }; // this property should be used by eth.filter to check if object is an event @@ -487,7 +489,131 @@ var contract = function (address, desc) { module.exports = contract; -},{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(require,module,exports){ +},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file db.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.db api methods +var methods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +module.exports = { + methods: methods +}; + +},{}],5:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file eth.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.eth api methods +var methods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var transactionCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber'; + }; + + var uncleCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber'; + }; + + return [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'flush', call: 'eth_flush' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' }, + { name: 'transactionCount', call: transactionCountCall }, + { name: 'uncleCount', call: uncleCountCall } + ]; +}; + +/// @returns an array of objects describing web3.eth api properties +var properties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +module.exports = { + methods: methods, + properties: properties +}; + + +},{}],6:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -624,7 +750,7 @@ module.exports = { }; -},{"./abi":1,"./utils":12}],5:[function(require,module,exports){ +},{"./abi":1,"./utils":15}],7:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -650,84 +776,96 @@ module.exports = { * @date 2014 */ -var web3 = require('./web3'); // jshint ignore:line - -/// should be used when we want to watch something -/// it's using inner polling mechanism and is notified about changes -/// TODO: change 'options' name cause it may be not the best matching one, since we have events -var Filter = function(options, impl) { - - if (typeof options !== "string") { - - // topics property is deprecated, warn about it! - if (options.topics) { - console.warn('"topics" is deprecated, use "topic" instead'); - } - - this._onWatchResult = options._onWatchEventResult; - - // evaluate lazy properties - options = { - to: options.to, - topic: options.topic, - earliest: options.earliest, - latest: options.latest, - max: options.max, - skip: options.skip, - address: options.address - }; - +/// Should be called to check if filter implementation is valid +/// @returns true if it is, otherwise false +var implementationIsValid = function (i) { + return !!i && + typeof i.newFilter === 'function' && + typeof i.getMessages === 'function' && + typeof i.uninstallFilter === 'function' && + typeof i.startPolling === 'function' && + typeof i.stopPolling === 'function'; +}; + +/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones +/// @param should be string or object +/// @returns options string or object +var getOptions = function (options) { + if (typeof options === 'string') { + return options; + } + + options = options || {}; + + if (options.topics) { + console.warn('"topics" is deprecated, is "topic" instead'); } - - this.impl = impl; - this.callbacks = []; - this.id = impl.newFilter(options); - web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this)); + // evaluate lazy properties + return { + to: options.to, + topic: options.topic, + earliest: options.earliest, + latest: options.latest, + max: options.max, + skip: options.skip, + address: options.address + }; }; -/// alias for changed* -Filter.prototype.arrived = function(callback) { - this.changed(callback); -}; -Filter.prototype.happened = function(callback) { - this.changed(callback); -}; +/// Should be used when we want to watch something +/// it's using inner polling mechanism and is notified about changes +/// @param options are filter options +/// @param implementation, an abstract polling implementation +/// @param formatter (optional), callback function which formats output before 'real' callback +var filter = function(options, implementation, formatter) { + if (!implementationIsValid(implementation)) { + console.error('filter implemenation is invalid'); + return; + } -/// gets called when there is new eth/shh message -Filter.prototype.changed = function(callback) { - this.callbacks.push(callback); -}; + options = getOptions(options); + var callbacks = []; + var filterId = implementation.newFilter(options); + var onMessages = function (messages) { + messages.forEach(function (message) { + messages = formatter ? formatter(message) : message; + callbacks.forEach(function (callback) { + callback(message); + }); + }); + }; -/// trigger calling new message from people -Filter.prototype.trigger = function(messages) { - for (var i = 0; i < this.callbacks.length; i++) { - for (var j = 0; j < messages.length; j++) { - var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j]; - this.callbacks[i].call(this, message); - } - } -}; + implementation.startPolling(filterId, onMessages, implementation.uninstallFilter); -/// should be called to uninstall current filter -Filter.prototype.uninstall = function() { - this.impl.uninstallFilter(this.id); - web3.provider.stopPolling(this.id); -}; + var changed = function (callback) { + callbacks.push(callback); + }; -/// should be called to manually trigger getting latest messages from the client -Filter.prototype.messages = function() { - return this.impl.getMessages(this.id); -}; + var messages = function () { + return implementation.getMessages(filterId); + }; + + var uninstall = function (callback) { + implementation.stopPolling(filterId); + implementation.uninstallFilter(filterId); + callbacks = []; + }; -/// alias for messages -Filter.prototype.logs = function () { - return this.messages(); + return { + changed: changed, + arrived: changed, + happened: changed, + messages: messages, + logs: messages, + uninstall: uninstall + }; }; -module.exports = Filter; +module.exports = filter; + -},{"./web3":13}],6:[function(require,module,exports){ +},{}],8:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -883,7 +1021,7 @@ module.exports = { }; -},{"./const":2,"./utils":12}],7:[function(require,module,exports){ +},{"./const":2,"./utils":15}],9:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -918,20 +1056,22 @@ var HttpSyncProvider = function (host) { HttpSyncProvider.prototype.send = function (payload) { //var data = formatJsonRpcObject(payload); - + var request = new XMLHttpRequest(); request.open('POST', this.host, false); request.send(JSON.stringify(payload)); - - // check request.status + var result = request.responseText; + // check request.status + if(request.status !== 200) + return; return JSON.parse(result); }; module.exports = HttpSyncProvider; -},{}],8:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -998,7 +1138,42 @@ module.exports = { -},{}],9:[function(require,module,exports){ +},{}],11:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file qtsync.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +var QtSyncProvider = function () { +}; + +QtSyncProvider.prototype.send = function (payload) { + var result = navigator.qt.callMethod(JSON.stringify(payload)); + return JSON.parse(result); +}; + +module.exports = QtSyncProvider; + + +},{}],12:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1015,7 +1190,7 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file providermanager.js +/** @file requestmanager.js * @authors: * Jeffrey Wilcke * Marek Kotewicz @@ -1024,85 +1199,86 @@ module.exports = { * @date 2014 */ -var web3 = require('./web3'); var jsonrpc = require('./jsonrpc'); - +var c = require('./const'); /** - * Provider manager object prototype * It's responsible for passing messages to providers - * If no provider is set it's responsible for queuing requests * It's also responsible for polling the ethereum node for incoming messages - * Default poll timeout is 12 seconds - * If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling, - * and provider manager polling mechanism is not used + * Default poll timeout is 1 second */ -var ProviderManager = function() { - this.polls = []; - this.provider = undefined; +var requestManager = function() { + var polls = []; + var provider; - var self = this; - var poll = function () { - self.polls.forEach(function (data) { - var result = self.send(data.data); - - if (!(result instanceof Array) || result.length === 0) { - return; - } + var send = function (data) { + var payload = jsonrpc.toPayload(data.method, data.params); + + if (!provider) { + console.error('provider is not set'); + return null; + } - data.callback(result); - }); + var result = provider.send(payload); - setTimeout(poll, 1000); + if (!jsonrpc.isValidResponse(result)) { + console.log(result); + return null; + } + + return result.result; }; - poll(); -}; - -/// sends outgoing requests -/// @params data - an object with at least 'method' property -ProviderManager.prototype.send = function(data) { - var payload = jsonrpc.toPayload(data.method, data.params); - - if (this.provider === undefined) { - console.error('provider is not set'); - return null; - } - var result = this.provider.send(payload); + var setProvider = function (p) { + provider = p; + }; - if (!jsonrpc.isValidResponse(result)) { - console.log(result); - return null; - } + var startPolling = function (data, pollId, callback, uninstall) { + polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); + }; - return result.result; -}; + var stopPolling = function (pollId) { + for (var i = polls.length; i--;) { + var poll = polls[i]; + if (poll.id === pollId) { + polls.splice(i, 1); + } + } + }; -/// setups provider, which will be used for sending messages -ProviderManager.prototype.set = function(provider) { - this.provider = provider; -}; + var reset = function () { + polls.forEach(function (poll) { + poll.uninstall(poll.id); + }); + polls = []; + }; -/// this method is only used, when we do not have native qt bindings and have to do polling on our own -/// should be callled, on start watching for eth/shh changes -ProviderManager.prototype.startPolling = function (data, pollId, callback) { - this.polls.push({data: data, id: pollId, callback: callback}); -}; + var poll = function () { + polls.forEach(function (data) { + var result = send(data.data); + if (!(result instanceof Array) || result.length === 0) { + return; + } + data.callback(result); + }); + setTimeout(poll, c.ETH_POLLING_TIMEOUT); + }; + + poll(); -/// should be called to stop polling for certain watch changes -ProviderManager.prototype.stopPolling = function (pollId) { - for (var i = this.polls.length; i--;) { - var poll = this.polls[i]; - if (poll.id === pollId) { - this.polls.splice(i, 1); - } - } + return { + send: send, + setProvider: setProvider, + startPolling: startPolling, + stopPolling: stopPolling, + reset: reset + }; }; -module.exports = ProviderManager; +module.exports = requestManager; -},{"./jsonrpc":8,"./web3":13}],10:[function(require,module,exports){ +},{"./const":2,"./jsonrpc":10}],13:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1119,25 +1295,29 @@ module.exports = ProviderManager; You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file qtsync.js +/** @file shh.js * @authors: * Marek Kotewicz - * Marian Oancea - * @date 2014 + * @date 2015 */ -var QtSyncProvider = function () { +/// @returns an array of objects describing web3.shh api methods +var methods = function () { + return [ + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } + ]; }; -QtSyncProvider.prototype.send = function (payload) { - var result = navigator.qt.callMethod(JSON.stringify(payload)); - return JSON.parse(result); +module.exports = { + methods: methods }; -module.exports = QtSyncProvider; - -},{}],11:[function(require,module,exports){ +},{}],14:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1218,7 +1398,7 @@ module.exports = { }; -},{"./formatters":6}],12:[function(require,module,exports){ +},{"./formatters":8}],15:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1362,7 +1542,7 @@ module.exports = { }; -},{"./const":2}],13:[function(require,module,exports){ +},{"./const":2}],16:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1379,100 +1559,14 @@ module.exports = { You should have received a copy of the GNU Lesser General Public License along with ethereum.js. If not, see . */ -/** @file web3.js +/** @file watches.js * @authors: - * Jeffrey Wilcke * Marek Kotewicz - * Marian Oancea - * Gav Wood - * @date 2014 + * @date 2015 */ -if ("build" !== 'build') {/* - var BigNumber = require('bignumber.js'); -*/} - -var utils = require('./utils'); - -/// @returns an array of objects describing web3 api methods -var web3Methods = function () { - return [ - { name: 'sha3', call: 'web3_sha3' } - ]; -}; - -/// @returns an array of objects describing web3.eth api methods -var ethMethods = function () { - var blockCall = function (args) { - return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; - }; - - var transactionCall = function (args) { - return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; - }; - - var uncleCall = function (args) { - return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; - }; - - var methods = [ - { name: 'balanceAt', call: 'eth_balanceAt' }, - { name: 'stateAt', call: 'eth_stateAt' }, - { name: 'storageAt', call: 'eth_storageAt' }, - { name: 'countAt', call: 'eth_countAt'}, - { name: 'codeAt', call: 'eth_codeAt' }, - { name: 'transact', call: 'eth_transact' }, - { name: 'call', call: 'eth_call' }, - { name: 'block', call: blockCall }, - { name: 'transaction', call: transactionCall }, - { name: 'uncle', call: uncleCall }, - { name: 'compilers', call: 'eth_compilers' }, - { name: 'flush', call: 'eth_flush' }, - { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' }, - { name: 'serpent', call: 'eth_serpent' }, - { name: 'logs', call: 'eth_logs' } - ]; - return methods; -}; - -/// @returns an array of objects describing web3.eth api properties -var ethProperties = function () { - return [ - { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, - { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, - { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, - { name: 'gasPrice', getter: 'eth_gasPrice' }, - { name: 'accounts', getter: 'eth_accounts' }, - { name: 'peerCount', getter: 'eth_peerCount' }, - { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, - { name: 'number', getter: 'eth_number'} - ]; -}; - -/// @returns an array of objects describing web3.db api methods -var dbMethods = function () { - return [ - { name: 'put', call: 'db_put' }, - { name: 'get', call: 'db_get' }, - { name: 'putString', call: 'db_putString' }, - { name: 'getString', call: 'db_getString' } - ]; -}; - -/// @returns an array of objects describing web3.shh api methods -var shhMethods = function () { - return [ - { name: 'post', call: 'shh_post' }, - { name: 'newIdentity', call: 'shh_newIdentity' }, - { name: 'haveIdentity', call: 'shh_haveIdentity' }, - { name: 'newGroup', call: 'shh_newGroup' }, - { name: 'addToGroup', call: 'shh_addToGroup' } - ]; -}; - /// @returns an array of objects describing web3.eth.watch api methods -var ethWatchMethods = function () { +var eth = function () { var newFilter = function (args) { return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; }; @@ -1485,7 +1579,7 @@ var ethWatchMethods = function () { }; /// @returns an array of objects describing web3.shh.watch api methods -var shhWatchMethods = function () { +var shh = function () { return [ { name: 'newFilter', call: 'shh_newFilter' }, { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, @@ -1493,6 +1587,57 @@ var shhWatchMethods = function () { ]; }; +module.exports = { + eth: eth, + shh: shh +}; + + +},{}],17:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file web3.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +if ("build" !== 'build') {/* + var BigNumber = require('bignumber.js'); +*/} + +var eth = require('./eth'); +var db = require('./db'); +var shh = require('./shh'); +var watches = require('./watches'); +var filter = require('./filter'); +var utils = require('./utils'); +var requestManager = require('./requestmanager'); + +/// @returns an array of objects describing web3 api methods +var web3Methods = function () { + return [ + { name: 'sha3', call: 'web3_sha3' } + ]; +}; + /// creates methods in a given object based on method description on input /// setups api calls for these methods var setupMethods = function (obj, methods) { @@ -1500,7 +1645,7 @@ var setupMethods = function (obj, methods) { obj[method.name] = function () { var args = Array.prototype.slice.call(arguments); var call = typeof method.call === 'function' ? method.call(args) : method.call; - return web3.provider.send({ + return web3.manager.send({ method: call, params: args }); @@ -1514,14 +1659,14 @@ var setupProperties = function (obj, properties) { properties.forEach(function (property) { var proto = {}; proto.get = function () { - return web3.provider.send({ + return web3.manager.send({ method: property.getter }); }; if (property.setter) { proto.set = function (val) { - return web3.provider.send({ + return web3.manager.send({ method: property.setter, params: [val] }); @@ -1531,10 +1676,30 @@ var setupProperties = function (obj, properties) { }); }; +var startPolling = function (method, id, callback, uninstall) { + web3.manager.startPolling({ + method: method, + params: [id] + }, id, callback, uninstall); +}; + +var stopPolling = function (id) { + web3.manager.stopPolling(id); +}; + +var ethWatch = { + startPolling: startPolling.bind(null, 'eth_changed'), + stopPolling: stopPolling +}; + +var shhWatch = { + startPolling: startPolling.bind(null, 'shh_changed'), + stopPolling: stopPolling +}; + /// setups web3 object, and it's in-browser executed methods var web3 = { - _callbacks: {}, - _events: {}, + manager: requestManager(), providers: {}, /// @returns ascii string representation of hex value prefixed with 0x @@ -1573,11 +1738,12 @@ var web3 = { /// @param filter may be a string, object or event /// @param indexed is optional, this is an object with optional event indexed params /// @param options is optional, this is an object with optional event options ('max'...) - watch: function (filter, indexed, options) { - if (filter._isEvent) { - return filter(indexed, options); + /// TODO: fix it, 4 params? no way + watch: function (fil, indexed, options, formatter) { + if (fil._isEvent) { + return fil(indexed, options); } - return new web3.filter(filter, ethWatch); + return filter(fil, ethWatch, formatter); } }, @@ -1586,54 +1752,44 @@ var web3 = { /// shh object prototype shh: { - /// @param filter may be a string, object or event - watch: function (filter, indexed) { - return new web3.filter(filter, shhWatch); + watch: function (fil) { + return filter(fil, shhWatch); } }, + setProvider: function (provider) { + web3.manager.setProvider(provider); + }, + + /// Should be called to reset state of web3 object + /// Resets everything except manager + reset: function () { + web3.manager.reset(); + } }; /// setups all api methods setupMethods(web3, web3Methods()); -setupMethods(web3.eth, ethMethods()); -setupProperties(web3.eth, ethProperties()); -setupMethods(web3.db, dbMethods()); -setupMethods(web3.shh, shhMethods()); - -var ethWatch = { - changed: 'eth_changed' -}; - -setupMethods(ethWatch, ethWatchMethods()); - -var shhWatch = { - changed: 'shh_changed' -}; - -setupMethods(shhWatch, shhWatchMethods()); - -web3.setProvider = function(provider) { - web3.provider.set(provider); -}; +setupMethods(web3.eth, eth.methods()); +setupProperties(web3.eth, eth.properties()); +setupMethods(web3.db, db.methods()); +setupMethods(web3.shh, shh.methods()); +setupMethods(ethWatch, watches.eth()); +setupMethods(shhWatch, watches.shh()); module.exports = web3; -},{"./utils":12}],"web3":[function(require,module,exports){ +},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],"web3":[function(require,module,exports){ var web3 = require('./lib/web3'); -var ProviderManager = require('./lib/providermanager'); -web3.provider = new ProviderManager(); -web3.filter = require('./lib/filter'); web3.providers.HttpSyncProvider = require('./lib/httpsync'); web3.providers.QtSyncProvider = require('./lib/qtsync'); web3.eth.contract = require('./lib/contract'); web3.abi = require('./lib/abi'); - module.exports = web3; -},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"]) +},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]) //# sourceMappingURL=ethereum.js.map \ No newline at end of file diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index e441da86c..8c25b78c4 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -5,37 +5,45 @@ "lib/abi.js", "lib/const.js", "lib/contract.js", + "lib/db.js", + "lib/eth.js", "lib/event.js", "lib/filter.js", "lib/formatters.js", "lib/httpsync.js", "lib/jsonrpc.js", - "lib/providermanager.js", "lib/qtsync.js", + "lib/requestmanager.js", + "lib/shh.js", "lib/types.js", "lib/utils.js", + "lib/watches.js", "lib/web3.js", "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "sourceRoot": "", "sourcesContent": [ "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o.\n*/\n/** @file abi.js\n * @authors:\n * Marek Kotewicz \n * Gav Wood \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar utils = require('./utils');\nvar types = require('./types');\nvar c = require('./const');\nvar f = require('./formatters');\n\nvar displayTypeError = function (type) {\n console.error('parser does not support type: ' + type);\n};\n\n/// This method should be called if we want to check if givent type is an array type\n/// @returns true if it is, otherwise false\nvar arrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\nvar dynamicTypeBytes = function (type, value) {\n // TODO: decide what to do with array of strings\n if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.\n return f.formatInputInt(value.length); \n return \"\";\n};\n\nvar inputTypes = types.inputTypes(); \n\n/// Formats input params to bytes\n/// @param abi contract method inputs\n/// @param array of params that will be formatted to bytes\n/// @returns bytes representation of input params\nvar formatInput = function (inputs, params) {\n var bytes = \"\";\n var padding = c.ETH_PADDING * 2;\n\n /// first we iterate in search for dynamic \n inputs.forEach(function (input, index) {\n bytes += dynamicTypeBytes(input.type, params[index]);\n });\n\n inputs.forEach(function (input, i) {\n var typeMatch = false;\n for (var j = 0; j < inputTypes.length && !typeMatch; j++) {\n typeMatch = inputTypes[j].type(inputs[i].type, params[i]);\n }\n if (!typeMatch) {\n displayTypeError(inputs[i].type);\n }\n\n var formatter = inputTypes[j - 1].format;\n var toAppend = \"\";\n\n if (arrayType(inputs[i].type))\n toAppend = params[i].reduce(function (acc, curr) {\n return acc + formatter(curr);\n }, \"\");\n else\n toAppend = formatter(params[i]);\n\n bytes += toAppend; \n });\n return bytes;\n};\n\nvar dynamicBytesLength = function (type) {\n if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.\n return c.ETH_PADDING * 2;\n return 0;\n};\n\nvar outputTypes = types.outputTypes(); \n\n/// Formats output bytes back to param list\n/// @param contract abi method outputs\n/// @param bytes representtion of output \n/// @returns array of output params \nvar formatOutput = function (outs, output) {\n \n output = output.slice(2);\n var result = [];\n var padding = c.ETH_PADDING * 2;\n\n var dynamicPartLength = outs.reduce(function (acc, curr) {\n return acc + dynamicBytesLength(curr.type);\n }, 0);\n \n var dynamicPart = output.slice(0, dynamicPartLength);\n output = output.slice(dynamicPartLength);\n\n outs.forEach(function (out, i) {\n var typeMatch = false;\n for (var j = 0; j < outputTypes.length && !typeMatch; j++) {\n typeMatch = outputTypes[j].type(outs[i].type);\n }\n\n if (!typeMatch) {\n displayTypeError(outs[i].type);\n }\n\n var formatter = outputTypes[j - 1].format;\n if (arrayType(outs[i].type)) {\n var size = f.formatOutputUInt(dynamicPart.slice(0, padding));\n dynamicPart = dynamicPart.slice(padding);\n var array = [];\n for (var k = 0; k < size; k++) {\n array.push(formatter(output.slice(0, padding))); \n output = output.slice(padding);\n }\n result.push(array);\n }\n else if (types.prefixedType('string')(outs[i].type)) {\n dynamicPart = dynamicPart.slice(padding); \n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n } else {\n result.push(formatter(output.slice(0, padding)));\n output = output.slice(padding);\n }\n });\n\n return result;\n};\n\n/// @param json abi for contract\n/// @returns input parser object for given json abi\n/// TODO: refactor creating the parser, do not double logic from contract\nvar inputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n var displayName = utils.extractDisplayName(method.name); \n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n return formatInput(method.inputs, params);\n };\n \n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/// @param json abi for contract\n/// @returns output parser for given json abi\nvar outputParser = function (json) {\n var parser = {};\n json.forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name); \n var typeName = utils.extractTypeName(method.name);\n\n var impl = function (output) {\n return formatOutput(method.outputs, output);\n };\n\n if (parser[displayName] === undefined) {\n parser[displayName] = impl;\n }\n\n parser[displayName][typeName] = impl;\n });\n\n return parser;\n};\n\n/// @param function/event name for which we want to get signature\n/// @returns signature of function/event with given name\nvar signatureFromAscii = function (name) {\n return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2);\n};\n\nvar eventSignatureFromAscii = function (name) {\n return web3.sha3(web3.fromAscii(name));\n};\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n formatInput: formatInput,\n formatOutput: formatOutput,\n signatureFromAscii: signatureFromAscii,\n eventSignatureFromAscii: eventSignatureFromAscii\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file const.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar abi = require('./abi');\nvar utils = require('./utils');\nvar eventImpl = require('./event');\n\nvar exportNatspecGlobals = function (vars) {\n // it's used byt natspec.js\n // TODO: figure out better way to solve this\n web3._currentContractAbi = vars.abi;\n web3._currentContractAddress = vars.address;\n web3._currentContractMethodName = vars.method;\n web3._currentContractMethodParams = vars.params;\n};\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransact = false;\n contract._options = options;\n return contract;\n };\n\n contract.transact = function (options) {\n contract._isTransact = true;\n contract._options = options;\n return contract;\n };\n\n contract._options = {};\n ['gas', 'gasPrice', 'value', 'from'].forEach(function(p) {\n contract[p] = function (v) {\n contract._options[p] = v;\n return contract;\n };\n });\n\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n // create contract functions\n utils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.signatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = signature + parsed;\n \n var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransact = null;\n\n if (isTransact) {\n \n exportNatspecGlobals({\n abi: desc,\n address: address,\n method: method.name,\n params: params\n });\n\n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.transact(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topic', {\n get: function() {\n return utils.filterEvents(desc).map(function (e) {\n return abi.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n utils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, signature, e);\n var o = event.apply(null, params);\n o._onWatchEventResult = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.watch(o); \n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object\n *\n * myContract.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * myContract.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * myContract.transact().myMethod('this is test string param for transact'); // myMethod transact\n *\n * @param address - address of the contract, which should be called\n * @param desc - abi json description of the contract, which is being created\n * @returns contract object\n */\n\nvar contract = function (address, desc) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n desc.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, desc, address);\n addEventRelatedPropertiesToContract(result, desc, address);\n addEventsToContract(result, desc, address);\n\n return result;\n};\n\nmodule.exports = contract;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file const.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },\n ETH_POLLING_TIMEOUT: 1000\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar abi = require('./abi');\nvar utils = require('./utils');\nvar eventImpl = require('./event');\nvar filter = require('./filter');\n\nvar exportNatspecGlobals = function (vars) {\n // it's used byt natspec.js\n // TODO: figure out better way to solve this\n web3._currentContractAbi = vars.abi;\n web3._currentContractAddress = vars.address;\n web3._currentContractMethodName = vars.method;\n web3._currentContractMethodParams = vars.params;\n};\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransact = false;\n contract._options = options;\n return contract;\n };\n\n contract.transact = function (options) {\n contract._isTransact = true;\n contract._options = options;\n return contract;\n };\n\n contract._options = {};\n ['gas', 'gasPrice', 'value', 'from'].forEach(function(p) {\n contract[p] = function (v) {\n contract._options[p] = v;\n return contract;\n };\n });\n\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n // create contract functions\n utils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.signatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = signature + parsed;\n \n var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransact = null;\n\n if (isTransact) {\n \n exportNatspecGlobals({\n abi: desc,\n address: address,\n method: method.name,\n params: params\n });\n\n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.transact(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topic', {\n get: function() {\n return utils.filterEvents(desc).map(function (e) {\n return abi.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n utils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, signature, e);\n var o = event.apply(null, params);\n var outputFormatter = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.watch(o, undefined, undefined, outputFormatter);\n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object\n *\n * myContract.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * myContract.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * myContract.transact().myMethod('this is test string param for transact'); // myMethod transact\n *\n * @param address - address of the contract, which should be called\n * @param desc - abi json description of the contract, which is being created\n * @returns contract object\n */\n\nvar contract = function (address, desc) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n desc.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, desc, address);\n addEventRelatedPropertiesToContract(result, desc, address);\n addEventsToContract(result, desc, address);\n\n return result;\n};\n\nmodule.exports = contract;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.db api methods\nvar methods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nmodule.exports = {\n methods: methods\n};\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file eth.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.eth api methods\nvar methods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var transactionCountCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber';\n };\n\n var uncleCountCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber';\n };\n\n return [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'flush', call: 'eth_flush' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' },\n { name: 'transactionCount', call: transactionCountCall },\n { name: 'uncleCount', call: uncleCountCall }\n ];\n};\n\n/// @returns an array of objects describing web3.eth api properties\nvar properties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('./abi');\nvar utils = require('./utils');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, signature, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topic = [];\n o.topic.push(signature);\n if (indexed) {\n o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexed.splice(0, 1)[0];\n else\n value = notIndexed.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n args: {}\n };\n\n if (!output.topic) {\n return result;\n }\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var signature = abi.eventSignatureFromAscii(events[i].name); \n if (signature === payload.topic[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar web3 = require('./web3'); // jshint ignore:line\n\n/// should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// TODO: change 'options' name cause it may be not the best matching one, since we have events\nvar Filter = function(options, impl) {\n\n if (typeof options !== \"string\") {\n\n // topics property is deprecated, warn about it!\n if (options.topics) {\n console.warn('\"topics\" is deprecated, use \"topic\" instead');\n }\n \n this._onWatchResult = options._onWatchEventResult;\n\n // evaluate lazy properties\n options = {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n\n }\n \n this.impl = impl;\n this.callbacks = [];\n\n this.id = impl.newFilter(options);\n web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));\n};\n\n/// alias for changed*\nFilter.prototype.arrived = function(callback) {\n this.changed(callback);\n};\nFilter.prototype.happened = function(callback) {\n this.changed(callback);\n};\n\n/// gets called when there is new eth/shh message\nFilter.prototype.changed = function(callback) {\n this.callbacks.push(callback);\n};\n\n/// trigger calling new message from people\nFilter.prototype.trigger = function(messages) {\n for (var i = 0; i < this.callbacks.length; i++) {\n for (var j = 0; j < messages.length; j++) {\n var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];\n this.callbacks[i].call(this, message);\n }\n }\n};\n\n/// should be called to uninstall current filter\nFilter.prototype.uninstall = function() {\n this.impl.uninstallFilter(this.id);\n web3.provider.stopPolling(this.id);\n};\n\n/// should be called to manually trigger getting latest messages from the client\nFilter.prototype.messages = function() {\n return this.impl.getMessages(this.id);\n};\n\n/// alias for messages\nFilter.prototype.logs = function () {\n return this.messages();\n};\n\nmodule.exports = Filter;\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\n/// Should be called to check if filter implementation is valid\n/// @returns true if it is, otherwise false\nvar implementationIsValid = function (i) {\n return !!i && \n typeof i.newFilter === 'function' && \n typeof i.getMessages === 'function' && \n typeof i.uninstallFilter === 'function' &&\n typeof i.startPolling === 'function' &&\n typeof i.stopPolling === 'function';\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n if (typeof options === 'string') {\n return options;\n } \n\n options = options || {};\n\n if (options.topics) {\n console.warn('\"topics\" is deprecated, is \"topic\" instead');\n }\n\n // evaluate lazy properties\n return {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n};\n\n/// Should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// @param options are filter options\n/// @param implementation, an abstract polling implementation\n/// @param formatter (optional), callback function which formats output before 'real' callback \nvar filter = function(options, implementation, formatter) {\n if (!implementationIsValid(implementation)) {\n console.error('filter implemenation is invalid');\n return;\n }\n\n options = getOptions(options);\n var callbacks = [];\n var filterId = implementation.newFilter(options);\n var onMessages = function (messages) {\n messages.forEach(function (message) {\n messages = formatter ? formatter(message) : message;\n callbacks.forEach(function (callback) {\n callback(message);\n });\n });\n };\n\n implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);\n\n var changed = function (callback) {\n callbacks.push(callback);\n };\n\n var messages = function () {\n return implementation.getMessages(filterId);\n };\n \n var uninstall = function (callback) {\n implementation.stopPolling(filterId);\n implementation.uninstallFilter(filterId);\n callbacks = [];\n };\n\n return {\n changed: changed,\n arrived: changed,\n happened: changed,\n messages: messages,\n logs: messages,\n uninstall: uninstall\n };\n};\n\nmodule.exports = filter;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file formatters.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar utils = require('./utils');\nvar c = require('./const');\n\n/// @param string string to be padded\n/// @param number of characters that result string should have\n/// @param sign, by default 0\n/// @returns right aligned string\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/// Formats input value to byte representation of int\n/// If value is negative, return it's two's complement\n/// If the value is floating point, round it down\n/// @returns right-aligned byte representation of int\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n if (value instanceof BigNumber || typeof value === 'number') {\n if (typeof value === 'number')\n value = new BigNumber(value);\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n value = value.round();\n\n if (value.lessThan(0)) \n value = new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(value).plus(1);\n value = value.toString(16);\n }\n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else if (typeof value === 'string')\n value = formatInputInt(new BigNumber(value));\n else\n value = (+value).toString(16);\n return padLeft(value, padding);\n};\n\n/// Formats input value to byte representation of string\n/// @returns left-algined byte representation of string\nvar formatInputString = function (value) {\n return utils.fromAscii(value, c.ETH_PADDING).substr(2);\n};\n\n/// Formats input value to byte representation of bool\n/// @returns right-aligned byte representation bool\nvar formatInputBool = function (value) {\n return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n};\n\n/// Formats input value to byte representation of real\n/// Values are multiplied by 2^m and encoded as integers\n/// @returns byte representation of real\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); \n};\n\n\n/// Check if input value is negative\n/// @param value is hex format\n/// @returns true if it is negative, otherwise false\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/// Formats input right-aligned input bytes to int\n/// @returns right-aligned input bytes formatted to int\nvar formatOutputInt = function (value) {\n value = value || \"0\";\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/// Formats big right-aligned input bytes to uint\n/// @returns right-aligned input bytes formatted to uint\nvar formatOutputUInt = function (value) {\n value = value || \"0\";\n return new BigNumber(value, 16);\n};\n\n/// @returns input bytes formatted to real\nvar formatOutputReal = function (value) {\n return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns input bytes formatted to ureal\nvar formatOutputUReal = function (value) {\n return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns right-aligned input bytes formatted to hex\nvar formatOutputHash = function (value) {\n return \"0x\" + value;\n};\n\n/// @returns right-aligned input bytes formatted to bool\nvar formatOutputBool = function (value) {\n return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/// @returns left-aligned input bytes formatted to ascii string\nvar formatOutputString = function (value) {\n return utils.toAscii(value);\n};\n\n/// @returns right-aligned input bytes formatted to address\nvar formatOutputAddress = function (value) {\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputString: formatInputString,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputHash: formatOutputHash,\n formatOutputBool: formatOutputBool,\n formatOutputString: formatOutputString,\n formatOutputAddress: formatOutputAddress\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://localhost:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n \n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n \n // check request.status\n var result = request.responseText;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://localhost:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n\n var result = request.responseText;\n // check request.status\n if(request.status !== 200)\n return;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar messageId = 1;\n\n/// Should be called to valid json create payload object\n/// @param method of jsonrpc call, required\n/// @param params, an array of method params, optional\n/// @returns valid jsonrpc payload object\nvar toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: messageId++\n }; \n};\n\n/// Should be called to check if jsonrpc response is valid\n/// @returns true if response is valid, otherwise false \nvar isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/// Should be called to create batch payload object\n/// @param messages, an array of objects with method (required) and params (optional) fields\nvar toBatchPayload = function (messages) {\n return messages.map(function (message) {\n return toPayload(message.method, message.params);\n }); \n};\n\nmodule.exports = {\n toPayload: toPayload,\n isValidResponse: isValidResponse,\n toBatchPayload: toBatchPayload\n};\n\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file providermanager.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar jsonrpc = require('./jsonrpc');\n\n\n/**\n * Provider manager object prototype\n * It's responsible for passing messages to providers\n * If no provider is set it's responsible for queuing requests\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 12 seconds\n * If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling,\n * and provider manager polling mechanism is not used\n */\nvar ProviderManager = function() {\n this.polls = [];\n this.provider = undefined;\n\n var self = this;\n var poll = function () {\n self.polls.forEach(function (data) {\n var result = self.send(data.data);\n\n if (!(result instanceof Array) || result.length === 0) {\n return;\n }\n\n data.callback(result);\n });\n\n setTimeout(poll, 1000);\n };\n poll();\n};\n\n/// sends outgoing requests\n/// @params data - an object with at least 'method' property\nProviderManager.prototype.send = function(data) {\n var payload = jsonrpc.toPayload(data.method, data.params);\n\n if (this.provider === undefined) {\n console.error('provider is not set');\n return null; \n }\n\n var result = this.provider.send(payload);\n\n if (!jsonrpc.isValidResponse(result)) {\n console.log(result);\n return null;\n }\n\n return result.result;\n};\n\n/// setups provider, which will be used for sending messages\nProviderManager.prototype.set = function(provider) {\n this.provider = provider;\n};\n\n/// this method is only used, when we do not have native qt bindings and have to do polling on our own\n/// should be callled, on start watching for eth/shh changes\nProviderManager.prototype.startPolling = function (data, pollId, callback) {\n this.polls.push({data: data, id: pollId, callback: callback});\n};\n\n/// should be called to stop polling for certain watch changes\nProviderManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\nmodule.exports = ProviderManager;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qtsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nvar QtSyncProvider = function () {\n};\n\nQtSyncProvider.prototype.send = function (payload) {\n var result = navigator.qt.callMethod(JSON.stringify(payload));\n return JSON.parse(result);\n};\n\nmodule.exports = QtSyncProvider;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file requestmanager.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar jsonrpc = require('./jsonrpc');\nvar c = require('./const');\n\n/**\n * It's responsible for passing messages to providers\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 1 second\n */\nvar requestManager = function() {\n var polls = [];\n var provider;\n\n var send = function (data) {\n var payload = jsonrpc.toPayload(data.method, data.params);\n \n if (!provider) {\n console.error('provider is not set');\n return null;\n }\n\n var result = provider.send(payload);\n\n if (!jsonrpc.isValidResponse(result)) {\n console.log(result);\n return null;\n }\n \n return result.result;\n };\n\n var setProvider = function (p) {\n provider = p;\n };\n\n var startPolling = function (data, pollId, callback, uninstall) {\n polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});\n };\n\n var stopPolling = function (pollId) {\n for (var i = polls.length; i--;) {\n var poll = polls[i];\n if (poll.id === pollId) {\n polls.splice(i, 1);\n }\n }\n };\n\n var reset = function () {\n polls.forEach(function (poll) {\n poll.uninstall(poll.id); \n });\n polls = [];\n };\n\n var poll = function () {\n polls.forEach(function (data) {\n var result = send(data.data);\n if (!(result instanceof Array) || result.length === 0) {\n return;\n }\n data.callback(result);\n });\n setTimeout(poll, c.ETH_POLLING_TIMEOUT);\n };\n \n poll();\n\n return {\n send: send,\n setProvider: setProvider,\n startPolling: startPolling,\n stopPolling: stopPolling,\n reset: reset\n };\n};\n\nmodule.exports = requestManager;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file shh.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.shh api methods\nvar methods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\nmodule.exports = {\n methods: methods\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file types.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar f = require('./formatters');\n\n/// @param expected type prefix (string)\n/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false\nvar prefixedType = function (prefix) {\n return function (type) {\n return type.indexOf(prefix) === 0;\n };\n};\n\n/// @param expected type name (string)\n/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false\nvar namedType = function (name) {\n return function (type) {\n return name === type;\n };\n};\n\n/// Setups input formatters for solidity types\n/// @returns an array of input formatters \nvar inputTypes = function () {\n \n return [\n { type: prefixedType('uint'), format: f.formatInputInt },\n { type: prefixedType('int'), format: f.formatInputInt },\n { type: prefixedType('hash'), format: f.formatInputInt },\n { type: prefixedType('string'), format: f.formatInputString }, \n { type: prefixedType('real'), format: f.formatInputReal },\n { type: prefixedType('ureal'), format: f.formatInputReal },\n { type: namedType('address'), format: f.formatInputInt },\n { type: namedType('bool'), format: f.formatInputBool }\n ];\n};\n\n/// Setups output formaters for solidity types\n/// @returns an array of output formatters\nvar outputTypes = function () {\n\n return [\n { type: prefixedType('uint'), format: f.formatOutputUInt },\n { type: prefixedType('int'), format: f.formatOutputInt },\n { type: prefixedType('hash'), format: f.formatOutputHash },\n { type: prefixedType('string'), format: f.formatOutputString },\n { type: prefixedType('real'), format: f.formatOutputReal },\n { type: prefixedType('ureal'), format: f.formatOutputUReal },\n { type: namedType('address'), format: f.formatOutputAddress },\n { type: namedType('bool'), format: f.formatOutputBool }\n ];\n};\n\nmodule.exports = {\n prefixedType: prefixedType,\n namedType: namedType,\n inputTypes: inputTypes,\n outputTypes: outputTypes\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file utils.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar c = require('./const');\n\n/// Finds first index of array element matching pattern\n/// @param array\n/// @param callback pattern\n/// @returns index of element\nvar findIndex = function (array, callback) {\n var end = false;\n var i = 0;\n for (; i < array.length && !end; i++) {\n end = callback(array[i]);\n }\n return end ? i - 1 : -1;\n};\n\n/// @returns ascii string representation of hex value prefixed with 0x\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \nvar toHex = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/// @returns hex representation (prefixed by 0x) of ascii string\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHex(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/// @returns display name for function/event eg. multiply(uint256) -> multiply\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/// Filters all function from input abi\n/// @returns abi array with filtered objects of type 'function'\nvar filterFunctions = function (json) {\n return json.filter(function (current) {\n return current.type === 'function'; \n }); \n};\n\n/// Filters all events form input abi\n/// @returns abi array with filtered objects of type 'event'\nvar filterEvents = function (json) {\n return json.filter(function (current) {\n return current.type === 'event';\n });\n};\n\n/// used to transform value/string to eth string\n/// TODO: use BigNumber.js to parse int\n/// TODO: add tests for it!\nvar toEth = function (str) {\n var val = typeof str === \"string\" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;\n var unit = 0;\n var units = c.ETH_UNITS;\n while (val > 3000 && unit < units.length - 1)\n {\n val /= 1000;\n unit++;\n }\n var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);\n var replaceFunction = function($0, $1, $2) {\n return $1 + ',' + $2;\n };\n\n while (true) {\n var o = s;\n s = s.replace(/(\\d)(\\d\\d\\d[\\.\\,])/, replaceFunction);\n if (o === s)\n break;\n }\n return s + ' ' + units[unit];\n};\n\nmodule.exports = {\n findIndex: findIndex,\n toAscii: toAscii,\n fromAscii: fromAscii,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n filterFunctions: filterFunctions,\n filterEvents: filterEvents,\n toEth: toEth\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js');\n*/}\n\nvar utils = require('./utils');\n\n/// @returns an array of objects describing web3 api methods\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\n/// @returns an array of objects describing web3.eth api methods\nvar ethMethods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var methods = [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'flush', call: 'eth_flush' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' }\n ];\n return methods;\n};\n\n/// @returns an array of objects describing web3.eth api properties\nvar ethProperties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\n/// @returns an array of objects describing web3.db api methods\nvar dbMethods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\n/// @returns an array of objects describing web3.shh api methods\nvar shhMethods = function () {\n return [\n { name: 'post', call: 'shh_post' },\n { name: 'newIdentity', call: 'shh_newIdentity' },\n { name: 'haveIdentity', call: 'shh_haveIdentity' },\n { name: 'newGroup', call: 'shh_newGroup' },\n { name: 'addToGroup', call: 'shh_addToGroup' }\n ];\n};\n\n/// @returns an array of objects describing web3.eth.watch api methods\nvar ethWatchMethods = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shhWatchMethods = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessages', call: 'shh_getMessages' }\n ];\n};\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n var args = Array.prototype.slice.call(arguments);\n var call = typeof method.call === 'function' ? method.call(args) : method.call;\n return web3.provider.send({\n method: call,\n params: args\n });\n };\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return web3.provider.send({\n method: property.getter\n });\n };\n\n if (property.setter) {\n proto.set = function (val) {\n return web3.provider.send({\n method: property.setter,\n params: [val]\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {\n _callbacks: {},\n _events: {},\n providers: {},\n\n /// @returns ascii string representation of hex value prefixed with 0x\n toAscii: utils.toAscii,\n\n /// @returns hex representation (prefixed by 0x) of ascii string\n fromAscii: utils.fromAscii,\n\n /// @returns decimal representaton of hex value prefixed by 0x\n toDecimal: function (val) {\n // remove 0x and place 0, if it's required\n val = val.length > 2 ? val.substring(2) : \"0\";\n return (new BigNumber(val, 16).toString(10));\n },\n\n /// @returns hex representation (prefixed by 0x) of decimal value\n fromDecimal: function (val) {\n return \"0x\" + (new BigNumber(val).toString(16));\n },\n\n /// used to transform value/string to eth string\n toEth: utils.toEth,\n\n /// eth object prototype\n eth: {\n contractFromAbi: function (abi) {\n return function(addr) {\n // Default to address of Config. TODO: rremove prior to genesis.\n addr = addr || '0xc6d9d2cd449a754c494264e1809c50e34d64562b';\n var ret = web3.eth.contract(addr, abi);\n ret.address = addr;\n return ret;\n };\n },\n\n /// @param filter may be a string, object or event\n /// @param indexed is optional, this is an object with optional event indexed params\n /// @param options is optional, this is an object with optional event options ('max'...)\n watch: function (filter, indexed, options) {\n if (filter._isEvent) {\n return filter(indexed, options);\n }\n return new web3.filter(filter, ethWatch);\n }\n },\n\n /// db object prototype\n db: {},\n\n /// shh object prototype\n shh: {\n \n /// @param filter may be a string, object or event\n watch: function (filter, indexed) {\n return new web3.filter(filter, shhWatch);\n }\n },\n};\n\n/// setups all api methods\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, ethMethods());\nsetupProperties(web3.eth, ethProperties());\nsetupMethods(web3.db, dbMethods());\nsetupMethods(web3.shh, shhMethods());\n\nvar ethWatch = {\n changed: 'eth_changed'\n};\n\nsetupMethods(ethWatch, ethWatchMethods());\n\nvar shhWatch = {\n changed: 'shh_changed'\n};\n\nsetupMethods(shhWatch, shhWatchMethods());\n\nweb3.setProvider = function(provider) {\n web3.provider.set(provider);\n};\n\nmodule.exports = web3;\n\n", - "var web3 = require('./lib/web3');\nvar ProviderManager = require('./lib/providermanager');\nweb3.provider = new ProviderManager();\nweb3.filter = require('./lib/filter');\nweb3.providers.HttpSyncProvider = require('./lib/httpsync');\nweb3.providers.QtSyncProvider = require('./lib/qtsync');\nweb3.eth.contract = require('./lib/contract');\nweb3.abi = require('./lib/abi');\n\n\nmodule.exports = web3;\n" + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file watches.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.eth.watch api methods\nvar eth = function () {\n var newFilter = function (args) {\n return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter';\n };\n\n return [\n { name: 'newFilter', call: newFilter },\n { name: 'uninstallFilter', call: 'eth_uninstallFilter' },\n { name: 'getMessages', call: 'eth_filterLogs' }\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shh = function () {\n return [\n { name: 'newFilter', call: 'shh_newFilter' },\n { name: 'uninstallFilter', call: 'shh_uninstallFilter' },\n { name: 'getMessages', call: 'shh_getMessages' }\n ];\n};\n\nmodule.exports = {\n eth: eth,\n shh: shh\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js');\n*/}\n\nvar eth = require('./eth');\nvar db = require('./db');\nvar shh = require('./shh');\nvar watches = require('./watches');\nvar filter = require('./filter');\nvar utils = require('./utils');\nvar requestManager = require('./requestmanager');\n\n/// @returns an array of objects describing web3 api methods\nvar web3Methods = function () {\n return [\n { name: 'sha3', call: 'web3_sha3' }\n ];\n};\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n obj[method.name] = function () {\n var args = Array.prototype.slice.call(arguments);\n var call = typeof method.call === 'function' ? method.call(args) : method.call;\n return web3.manager.send({\n method: call,\n params: args\n });\n };\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n var proto = {};\n proto.get = function () {\n return web3.manager.send({\n method: property.getter\n });\n };\n\n if (property.setter) {\n proto.set = function (val) {\n return web3.manager.send({\n method: property.setter,\n params: [val]\n });\n };\n }\n Object.defineProperty(obj, property.name, proto);\n });\n};\n\nvar startPolling = function (method, id, callback, uninstall) {\n web3.manager.startPolling({\n method: method, \n params: [id]\n }, id, callback, uninstall); \n};\n\nvar stopPolling = function (id) {\n web3.manager.stopPolling(id);\n};\n\nvar ethWatch = {\n startPolling: startPolling.bind(null, 'eth_changed'), \n stopPolling: stopPolling\n};\n\nvar shhWatch = {\n startPolling: startPolling.bind(null, 'shh_changed'), \n stopPolling: stopPolling\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {\n manager: requestManager(),\n providers: {},\n\n /// @returns ascii string representation of hex value prefixed with 0x\n toAscii: utils.toAscii,\n\n /// @returns hex representation (prefixed by 0x) of ascii string\n fromAscii: utils.fromAscii,\n\n /// @returns decimal representaton of hex value prefixed by 0x\n toDecimal: function (val) {\n // remove 0x and place 0, if it's required\n val = val.length > 2 ? val.substring(2) : \"0\";\n return (new BigNumber(val, 16).toString(10));\n },\n\n /// @returns hex representation (prefixed by 0x) of decimal value\n fromDecimal: function (val) {\n return \"0x\" + (new BigNumber(val).toString(16));\n },\n\n /// used to transform value/string to eth string\n toEth: utils.toEth,\n\n /// eth object prototype\n eth: {\n contractFromAbi: function (abi) {\n return function(addr) {\n // Default to address of Config. TODO: rremove prior to genesis.\n addr = addr || '0xc6d9d2cd449a754c494264e1809c50e34d64562b';\n var ret = web3.eth.contract(addr, abi);\n ret.address = addr;\n return ret;\n };\n },\n\n /// @param filter may be a string, object or event\n /// @param indexed is optional, this is an object with optional event indexed params\n /// @param options is optional, this is an object with optional event options ('max'...)\n /// TODO: fix it, 4 params? no way\n watch: function (fil, indexed, options, formatter) {\n if (fil._isEvent) {\n return fil(indexed, options);\n }\n return filter(fil, ethWatch, formatter);\n }\n },\n\n /// db object prototype\n db: {},\n\n /// shh object prototype\n shh: {\n /// @param filter may be a string, object or event\n watch: function (fil) {\n return filter(fil, shhWatch);\n }\n },\n setProvider: function (provider) {\n web3.manager.setProvider(provider);\n },\n \n /// Should be called to reset state of web3 object\n /// Resets everything except manager\n reset: function () {\n web3.manager.reset(); \n }\n};\n\n/// setups all api methods\nsetupMethods(web3, web3Methods());\nsetupMethods(web3.eth, eth.methods());\nsetupProperties(web3.eth, eth.properties());\nsetupMethods(web3.db, db.methods());\nsetupMethods(web3.shh, shh.methods());\nsetupMethods(ethWatch, watches.eth());\nsetupMethods(shhWatch, watches.shh());\n\nmodule.exports = web3;\n\n", + "var web3 = require('./lib/web3');\nweb3.providers.HttpSyncProvider = require('./lib/httpsync');\nweb3.providers.QtSyncProvider = require('./lib/qtsync');\nweb3.eth.contract = require('./lib/contract');\nweb3.abi = require('./lib/abi');\n\nmodule.exports = web3;\n" ] } \ No newline at end of file diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index df408d3e4..bb8a10c35 100644 --- a/dist/ethereum.min.js +++ b/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(e,n,r){function i(a,u){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(o)return o(a,!0);var f=new Error("Cannot find module '"+a+"'");throw f.code="MODULE_NOT_FOUND",f}var c=n[a]={exports:{}};e[a][0].call(c.exports,function(t){var n=e[a][1][t];return i(n?n:t)},c,c.exports,t,e,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;av;v++)g.push(h(e.slice(0,r))),e=e.slice(r);n.push(g)}else i.prefixedType("string")(t[f].type)?(c=c.slice(r),n.push(h(e.slice(0,r))),e=e.slice(r)):(n.push(h(e.slice(0,r))),e=e.slice(r))}),n},d=function(t){var e={};return t.forEach(function(t){var n=r.extractDisplayName(t.name),i=r.extractTypeName(t.name),o=function(){var e=Array.prototype.slice.call(arguments);return l(t.inputs,e)};void 0===e[n]&&(e[n]=o),e[n][i]=o}),e},g=function(t){var e={};return t.forEach(function(t){var n=r.extractDisplayName(t.name),i=r.extractTypeName(t.name),o=function(e){return h(t.outputs,e)};void 0===e[n]&&(e[n]=o),e[n][i]=o}),e},v=function(t){return n.sha3(n.fromAscii(t)).slice(0,2+2*o.ETH_SIGNATURE_LENGTH)},y=function(t){return n.sha3(n.fromAscii(t))};e.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":6,"./types":11,"./utils":12,"./web3":13}],2:[function(t,e){var n=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:n,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN}}},{}],3:[function(t,e){var n=t("./web3"),r=t("./abi"),i=t("./utils"),o=t("./event"),a=function(t){n._currentContractAbi=t.abi,n._currentContractAddress=t.address,n._currentContractMethodName=t.method,n._currentContractMethodParams=t.params},u=function(t){t.call=function(e){return t._isTransact=!1,t._options=e,t},t.transact=function(e){return t._isTransact=!0,t._options=e,t},t._options={},["gas","gasPrice","value","from"].forEach(function(e){t[e]=function(n){return t._options[e]=n,t}})},s=function(t,e,o){var u=r.inputParser(e),s=r.outputParser(e);i.filterFunctions(e).forEach(function(f){var c=i.extractDisplayName(f.name),l=i.extractTypeName(f.name),p=function(){var i=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(f.name),m=u[c][l].apply(null,i),h=t._options||{};h.to=o,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!f.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return a({abi:e,address:o,method:f.name,params:i}),void n.eth.transact(h);var v=n.eth.call(h),y=s[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},f=function(t,e,n){t.address=n,t._onWatchEventResult=function(t){var n=event.getMatchingEvent(i.filterEvents(e)),r=o.outputParser(n);return r(t)},Object.defineProperty(t,"topic",{get:function(){return i.filterEvents(e).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,e,a){i.filterEvents(e).forEach(function(e){var u=function(){var t=Array.prototype.slice.call(arguments),i=r.eventSignatureFromAscii(e.name),u=o.inputParser(a,i,e),s=u.apply(null,t);return s._onWatchEventResult=function(t){var n=o.outputParser(e);return n(t)},n.eth.watch(s)};u._isEvent=!0;var s=i.extractDisplayName(e.name),f=i.extractTypeName(e.name);void 0===t[s]&&(t[s]=u),t[s][f]=u})},l=function(t,e){e.forEach(function(t){if(-1===t.name.indexOf("(")){var e=t.name,n=t.inputs.map(function(t){return t.type}).join();t.name=e+"("+n+")"}});var n={};return u(n),s(n,e,t),f(n,e,t),c(n,e,t),n};e.exports=l},{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(t,e){var n=t("./abi"),r=t("./utils"),i=function(t,e){return t.filter(function(t){return t.indexed===e})},o=function(t,e){var n=r.findIndex(t,function(t){return t.name===e});return-1===n?void console.error("indexed param with name "+e+" not found"):t[n]},a=function(t,e){return Object.keys(e).map(function(r){var a=[o(i(t.inputs,!0),r)],u=e[r];return u instanceof Array?u.map(function(t){return n.formatInput(a,[t])}):n.formatInput(a,[u])})},u=function(t,e,n){return function(r,i){var o=i||{};return o.address=t,o.topic=[],o.topic.push(e),r&&(o.topic=o.topic.concat(a(n,r))),o}},s=function(t,e,n){e.slice(),n.slice();return t.reduce(function(t,r){var i;return i=r.indexed?e.splice(0,1)[0]:n.splice(0,1)[0],t[r.name]=i,t},{})},f=function(t){return function(e){var o={event:r.extractDisplayName(t.name),number:e.number,args:{}};if(!e.topic)return o;var a=i(t.inputs,!0),u="0x"+e.topic.slice(1,e.topic.length).map(function(t){return t.slice(2)}).join(""),f=n.formatOutput(a,u),c=i(t.inputs,!1),l=n.formatOutput(c,e.data);return o.args=s(t.inputs,f,l),o}},c=function(t,e){for(var r=0;rn;n+=2){var i=parseInt(t.substr(n,2),16);if(0===i)break;e+=String.fromCharCode(i)}return e},o=function(t){for(var e="",n=0;n3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:n.toEth,eth:{contractFromAbi:function(t){return function(e){e=e||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var n=p.eth.contract(e,t);return n.address=e,n}},watch:function(t,e,n){return t._isEvent?t(e,n):new p.filter(t,m)}},db:{},shh:{watch:function(t){return new p.filter(t,h)}}};c(p,r()),c(p.eth,i()),l(p.eth,o()),c(p.db,a()),c(p.shh,u());var m={changed:"eth_changed"};c(m,s());var h={changed:"shh_changed"};c(h,f()),p.setProvider=function(t){p.provider.set(t)},e.exports=p},{"./utils":12}],web3:[function(t,e){var n=t("./lib/web3"),r=t("./lib/providermanager");n.provider=new r,n.filter=t("./lib/filter"),n.providers.HttpSyncProvider=t("./lib/httpsync"),n.providers.QtSyncProvider=t("./lib/qtsync"),n.eth.contract=t("./lib/contract"),n.abi=t("./lib/abi"),e.exports=n},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"]); \ No newline at end of file +require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index f8f6c96ce..61f7c9ebc 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -15,90 +15,55 @@ var unreach = require('unreachable-branch-transform'); var source = require('vinyl-source-stream'); var exorcist = require('exorcist'); var bower = require('bower'); +var streamify = require('gulp-streamify'); var DEST = './dist/'; - -var build = function(src, dst, ugly) { - var result = browserify({ - debug: true, - insert_global_vars: false, - detectGlobals: false, - bundleExternal: false - }) - .require('./' + src + '.js', {expose: 'web3'}) - .add('./' + src + '.js') - .transform('envify', { - NODE_ENV: 'build' - }) - .transform('unreachable-branch-transform'); - - if (ugly) { - result = result.transform('uglifyify', { - mangle: false, - compress: { - dead_code: false, - conditionals: true, - unused: false, - hoist_funs: true, - hoist_vars: true, - negate_iife: false - }, - beautify: true, - warnings: true - }); - } - - return result.bundle() - .pipe(exorcist(path.join( DEST, dst + '.js.map'))) - .pipe(source(dst + '.js')) - .pipe(gulp.dest( DEST )); -}; - -var uglifyFile = function(file) { - return gulp.src( DEST + file + '.js') - .pipe(uglify()) - .pipe(rename(file + '.min.js')) - .pipe(gulp.dest( DEST )); +var src = 'index'; +var dst = 'ethereum'; + +var browserifyOptions = { + debug: true, + insert_global_vars: false, + detectGlobals: false, + bundleExternal: false }; gulp.task('bower', function(cb){ - bower.commands.install().on('end', function (installed){ - console.log(installed); - cb(); - }); + bower.commands.install().on('end', function (installed){ + console.log(installed); + cb(); + }); }); gulp.task('clean', ['lint'], function(cb) { - del([ DEST ], cb); + del([ DEST ], cb); }); gulp.task('lint', function(){ - return gulp.src(['./*.js', './lib/*.js']) - .pipe(jshint()) - .pipe(jshint.reporter('default')); + return gulp.src(['./*.js', './lib/*.js']) + .pipe(jshint()) + .pipe(jshint.reporter('default')); }); gulp.task('build', ['clean'], function () { - return build('index', 'ethereum', true); -}); - -gulp.task('buildDev', ['clean'], function () { - return build('index', 'ethereum', false); -}); - -gulp.task('uglify', ['build'], function(){ - return uglifyFile('ethereum'); -}); - -gulp.task('uglifyDev', ['buildDev'], function(){ - return uglifyFile('ethereum'); + return browserify(browserifyOptions) + .require('./' + src + '.js', {expose: 'web3'}) + .add('./' + src + '.js') + .transform('envify', { NODE_ENV: 'build' }) + .transform('unreachable-branch-transform') + .bundle() + .pipe(exorcist(path.join( DEST, dst + '.js.map'))) + .pipe(source(dst + '.js')) + .pipe(gulp.dest( DEST )) + .pipe(streamify(uglify())) + .pipe(rename(dst + '.min.js')) + .pipe(gulp.dest( DEST )); }); gulp.task('watch', function() { - gulp.watch(['./lib/*.js'], ['lint', 'prepare', 'build']); + gulp.watch(['./lib/*.js'], ['lint', 'build']); }); -gulp.task('release', ['bower', 'lint', 'build', 'uglify']); -gulp.task('dev', ['bower', 'lint', 'buildDev', 'uglifyDev']); +gulp.task('dev', ['bower', 'lint', 'build']); gulp.task('default', ['dev']); diff --git a/index.js b/index.js index 76c923722..67c500fb7 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,7 @@ var web3 = require('./lib/web3'); -var ProviderManager = require('./lib/providermanager'); -web3.provider = new ProviderManager(); -web3.filter = require('./lib/filter'); web3.providers.HttpSyncProvider = require('./lib/httpsync'); web3.providers.QtSyncProvider = require('./lib/qtsync'); web3.eth.contract = require('./lib/contract'); web3.abi = require('./lib/abi'); - module.exports = web3; diff --git a/lib/const.js b/lib/const.js index 8a17b794d..f7ccc9e28 100644 --- a/lib/const.js +++ b/lib/const.js @@ -51,6 +51,7 @@ module.exports = { ETH_PADDING: 32, ETH_SIGNATURE_LENGTH: 4, ETH_UNITS: ETH_UNITS, - ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, + ETH_POLLING_TIMEOUT: 1000 }; diff --git a/lib/contract.js b/lib/contract.js index a0525bd9d..4b2cd5f65 100644 --- a/lib/contract.js +++ b/lib/contract.js @@ -24,6 +24,7 @@ var web3 = require('./web3'); var abi = require('./abi'); var utils = require('./utils'); var eventImpl = require('./event'); +var filter = require('./filter'); var exportNatspecGlobals = function (vars) { // it's used byt natspec.js @@ -145,11 +146,11 @@ var addEventsToContract = function (contract, desc, address) { var signature = abi.eventSignatureFromAscii(e.name); var event = eventImpl.inputParser(address, signature, e); var o = event.apply(null, params); - o._onWatchEventResult = function (data) { + var outputFormatter = function (data) { var parser = eventImpl.outputParser(e); return parser(data); }; - return web3.eth.watch(o); + return web3.eth.watch(o, undefined, undefined, outputFormatter); }; // this property should be used by eth.filter to check if object is an event diff --git a/lib/db.js b/lib/db.js new file mode 100644 index 000000000..5f5ebc2b1 --- /dev/null +++ b/lib/db.js @@ -0,0 +1,35 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file db.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.db api methods +var methods = function () { + return [ + { name: 'put', call: 'db_put' }, + { name: 'get', call: 'db_get' }, + { name: 'putString', call: 'db_putString' }, + { name: 'getString', call: 'db_getString' } + ]; +}; + +module.exports = { + methods: methods +}; diff --git a/lib/eth.js b/lib/eth.js new file mode 100644 index 000000000..58ed5fa11 --- /dev/null +++ b/lib/eth.js @@ -0,0 +1,85 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file eth.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.eth api methods +var methods = function () { + var blockCall = function (args) { + return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; + }; + + var transactionCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; + }; + + var uncleCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; + }; + + var transactionCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber'; + }; + + var uncleCountCall = function (args) { + return typeof args[0] === "string" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber'; + }; + + return [ + { name: 'balanceAt', call: 'eth_balanceAt' }, + { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, + { name: 'countAt', call: 'eth_countAt'}, + { name: 'codeAt', call: 'eth_codeAt' }, + { name: 'transact', call: 'eth_transact' }, + { name: 'call', call: 'eth_call' }, + { name: 'block', call: blockCall }, + { name: 'transaction', call: transactionCall }, + { name: 'uncle', call: uncleCall }, + { name: 'compilers', call: 'eth_compilers' }, + { name: 'flush', call: 'eth_flush' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'serpent', call: 'eth_serpent' }, + { name: 'logs', call: 'eth_logs' }, + { name: 'transactionCount', call: transactionCountCall }, + { name: 'uncleCount', call: uncleCountCall } + ]; +}; + +/// @returns an array of objects describing web3.eth api properties +var properties = function () { + return [ + { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, + { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, + { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, + { name: 'gasPrice', getter: 'eth_gasPrice' }, + { name: 'accounts', getter: 'eth_accounts' }, + { name: 'peerCount', getter: 'eth_peerCount' }, + { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, + { name: 'number', getter: 'eth_number'} + ]; +}; + +module.exports = { + methods: methods, + properties: properties +}; + diff --git a/lib/filter.js b/lib/filter.js index 6ab2b7edc..e7aa1ef2e 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -23,79 +23,91 @@ * @date 2014 */ -var web3 = require('./web3'); // jshint ignore:line - -/// should be used when we want to watch something -/// it's using inner polling mechanism and is notified about changes -/// TODO: change 'options' name cause it may be not the best matching one, since we have events -var Filter = function(options, impl) { - - if (typeof options !== "string") { - - // topics property is deprecated, warn about it! - if (options.topics) { - console.warn('"topics" is deprecated, use "topic" instead'); - } - - this._onWatchResult = options._onWatchEventResult; - - // evaluate lazy properties - options = { - to: options.to, - topic: options.topic, - earliest: options.earliest, - latest: options.latest, - max: options.max, - skip: options.skip, - address: options.address - }; - - } - - this.impl = impl; - this.callbacks = []; - - this.id = impl.newFilter(options); - web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this)); +/// Should be called to check if filter implementation is valid +/// @returns true if it is, otherwise false +var implementationIsValid = function (i) { + return !!i && + typeof i.newFilter === 'function' && + typeof i.getMessages === 'function' && + typeof i.uninstallFilter === 'function' && + typeof i.startPolling === 'function' && + typeof i.stopPolling === 'function'; }; -/// alias for changed* -Filter.prototype.arrived = function(callback) { - this.changed(callback); -}; -Filter.prototype.happened = function(callback) { - this.changed(callback); -}; +/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones +/// @param should be string or object +/// @returns options string or object +var getOptions = function (options) { + if (typeof options === 'string') { + return options; + } -/// gets called when there is new eth/shh message -Filter.prototype.changed = function(callback) { - this.callbacks.push(callback); -}; + options = options || {}; -/// trigger calling new message from people -Filter.prototype.trigger = function(messages) { - for (var i = 0; i < this.callbacks.length; i++) { - for (var j = 0; j < messages.length; j++) { - var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j]; - this.callbacks[i].call(this, message); - } + if (options.topics) { + console.warn('"topics" is deprecated, is "topic" instead'); } -}; -/// should be called to uninstall current filter -Filter.prototype.uninstall = function() { - this.impl.uninstallFilter(this.id); - web3.provider.stopPolling(this.id); + // evaluate lazy properties + return { + to: options.to, + topic: options.topic, + earliest: options.earliest, + latest: options.latest, + max: options.max, + skip: options.skip, + address: options.address + }; }; -/// should be called to manually trigger getting latest messages from the client -Filter.prototype.messages = function() { - return this.impl.getMessages(this.id); -}; +/// Should be used when we want to watch something +/// it's using inner polling mechanism and is notified about changes +/// @param options are filter options +/// @param implementation, an abstract polling implementation +/// @param formatter (optional), callback function which formats output before 'real' callback +var filter = function(options, implementation, formatter) { + if (!implementationIsValid(implementation)) { + console.error('filter implemenation is invalid'); + return; + } -/// alias for messages -Filter.prototype.logs = function () { - return this.messages(); + options = getOptions(options); + var callbacks = []; + var filterId = implementation.newFilter(options); + var onMessages = function (messages) { + messages.forEach(function (message) { + messages = formatter ? formatter(message) : message; + callbacks.forEach(function (callback) { + callback(message); + }); + }); + }; + + implementation.startPolling(filterId, onMessages, implementation.uninstallFilter); + + var changed = function (callback) { + callbacks.push(callback); + }; + + var messages = function () { + return implementation.getMessages(filterId); + }; + + var uninstall = function (callback) { + implementation.stopPolling(filterId); + implementation.uninstallFilter(filterId); + callbacks = []; + }; + + return { + changed: changed, + arrived: changed, + happened: changed, + messages: messages, + logs: messages, + uninstall: uninstall + }; }; -module.exports = Filter; +module.exports = filter; + diff --git a/lib/httpsync.js b/lib/httpsync.js index 06e410ca8..90f3ee454 100644 --- a/lib/httpsync.js +++ b/lib/httpsync.js @@ -32,13 +32,15 @@ var HttpSyncProvider = function (host) { HttpSyncProvider.prototype.send = function (payload) { //var data = formatJsonRpcObject(payload); - + var request = new XMLHttpRequest(); request.open('POST', this.host, false); request.send(JSON.stringify(payload)); - - // check request.status + var result = request.responseText; + // check request.status + if(request.status !== 200) + return; return JSON.parse(result); }; diff --git a/lib/providermanager.js b/lib/providermanager.js deleted file mode 100644 index 55b072634..000000000 --- a/lib/providermanager.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - 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 - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file providermanager.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * Gav Wood - * @date 2014 - */ - -var web3 = require('./web3'); -var jsonrpc = require('./jsonrpc'); - - -/** - * Provider manager object prototype - * It's responsible for passing messages to providers - * If no provider is set it's responsible for queuing requests - * It's also responsible for polling the ethereum node for incoming messages - * Default poll timeout is 12 seconds - * If we are running ethereum.js inside ethereum browser, there are backend based tools responsible for polling, - * and provider manager polling mechanism is not used - */ -var ProviderManager = function() { - this.polls = []; - this.provider = undefined; - - var self = this; - var poll = function () { - self.polls.forEach(function (data) { - var result = self.send(data.data); - - if (!(result instanceof Array) || result.length === 0) { - return; - } - - data.callback(result); - }); - - setTimeout(poll, 1000); - }; - poll(); -}; - -/// sends outgoing requests -/// @params data - an object with at least 'method' property -ProviderManager.prototype.send = function(data) { - var payload = jsonrpc.toPayload(data.method, data.params); - - if (this.provider === undefined) { - console.error('provider is not set'); - return null; - } - - var result = this.provider.send(payload); - - if (!jsonrpc.isValidResponse(result)) { - console.log(result); - return null; - } - - return result.result; -}; - -/// setups provider, which will be used for sending messages -ProviderManager.prototype.set = function(provider) { - this.provider = provider; -}; - -/// this method is only used, when we do not have native qt bindings and have to do polling on our own -/// should be callled, on start watching for eth/shh changes -ProviderManager.prototype.startPolling = function (data, pollId, callback) { - this.polls.push({data: data, id: pollId, callback: callback}); -}; - -/// should be called to stop polling for certain watch changes -ProviderManager.prototype.stopPolling = function (pollId) { - for (var i = this.polls.length; i--;) { - var poll = this.polls[i]; - if (poll.id === pollId) { - this.polls.splice(i, 1); - } - } -}; - -module.exports = ProviderManager; - diff --git a/lib/requestmanager.js b/lib/requestmanager.js new file mode 100644 index 000000000..6162b5f38 --- /dev/null +++ b/lib/requestmanager.js @@ -0,0 +1,103 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file requestmanager.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Gav Wood + * @date 2014 + */ + +var jsonrpc = require('./jsonrpc'); +var c = require('./const'); + +/** + * It's responsible for passing messages to providers + * It's also responsible for polling the ethereum node for incoming messages + * Default poll timeout is 1 second + */ +var requestManager = function() { + var polls = []; + var provider; + + var send = function (data) { + var payload = jsonrpc.toPayload(data.method, data.params); + + if (!provider) { + console.error('provider is not set'); + return null; + } + + var result = provider.send(payload); + + if (!jsonrpc.isValidResponse(result)) { + console.log(result); + return null; + } + + return result.result; + }; + + var setProvider = function (p) { + provider = p; + }; + + var startPolling = function (data, pollId, callback, uninstall) { + polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); + }; + + var stopPolling = function (pollId) { + for (var i = polls.length; i--;) { + var poll = polls[i]; + if (poll.id === pollId) { + polls.splice(i, 1); + } + } + }; + + var reset = function () { + polls.forEach(function (poll) { + poll.uninstall(poll.id); + }); + polls = []; + }; + + var poll = function () { + polls.forEach(function (data) { + var result = send(data.data); + if (!(result instanceof Array) || result.length === 0) { + return; + } + data.callback(result); + }); + setTimeout(poll, c.ETH_POLLING_TIMEOUT); + }; + + poll(); + + return { + send: send, + setProvider: setProvider, + startPolling: startPolling, + stopPolling: stopPolling, + reset: reset + }; +}; + +module.exports = requestManager; + diff --git a/lib/shh.js b/lib/shh.js new file mode 100644 index 000000000..563e71d27 --- /dev/null +++ b/lib/shh.js @@ -0,0 +1,37 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file shh.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.shh api methods +var methods = function () { + return [ + { name: 'post', call: 'shh_post' }, + { name: 'newIdentity', call: 'shh_newIdentity' }, + { name: 'haveIdentity', call: 'shh_haveIdentity' }, + { name: 'newGroup', call: 'shh_newGroup' }, + { name: 'addToGroup', call: 'shh_addToGroup' } + ]; +}; + +module.exports = { + methods: methods +}; + diff --git a/lib/watches.js b/lib/watches.js new file mode 100644 index 000000000..84ff38922 --- /dev/null +++ b/lib/watches.js @@ -0,0 +1,49 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + 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 + (at your option) any later version. + + ethereum.js 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file watches.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// @returns an array of objects describing web3.eth.watch api methods +var eth = function () { + var newFilter = function (args) { + return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; + }; + + return [ + { name: 'newFilter', call: newFilter }, + { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, + { name: 'getMessages', call: 'eth_filterLogs' } + ]; +}; + +/// @returns an array of objects describing web3.shh.watch api methods +var shh = function () { + return [ + { name: 'newFilter', call: 'shh_newFilter' }, + { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, + { name: 'getMessages', call: 'shh_getMessages' } + ]; +}; + +module.exports = { + eth: eth, + shh: shh +}; + diff --git a/lib/web3.js b/lib/web3.js index 41df75051..1d8d0fba8 100644 --- a/lib/web3.js +++ b/lib/web3.js @@ -27,7 +27,13 @@ if (process.env.NODE_ENV !== 'build') { var BigNumber = require('bignumber.js'); } +var eth = require('./eth'); +var db = require('./db'); +var shh = require('./shh'); +var watches = require('./watches'); +var filter = require('./filter'); var utils = require('./utils'); +var requestManager = require('./requestmanager'); /// @returns an array of objects describing web3 api methods var web3Methods = function () { @@ -36,98 +42,6 @@ var web3Methods = function () { ]; }; -/// @returns an array of objects describing web3.eth api methods -var ethMethods = function () { - var blockCall = function (args) { - return typeof args[0] === "string" ? "eth_blockByHash" : "eth_blockByNumber"; - }; - - var transactionCall = function (args) { - return typeof args[0] === "string" ? 'eth_transactionByHash' : 'eth_transactionByNumber'; - }; - - var uncleCall = function (args) { - return typeof args[0] === "string" ? 'eth_uncleByHash' : 'eth_uncleByNumber'; - }; - - var methods = [ - { name: 'balanceAt', call: 'eth_balanceAt' }, - { name: 'stateAt', call: 'eth_stateAt' }, - { name: 'storageAt', call: 'eth_storageAt' }, - { name: 'countAt', call: 'eth_countAt'}, - { name: 'codeAt', call: 'eth_codeAt' }, - { name: 'transact', call: 'eth_transact' }, - { name: 'call', call: 'eth_call' }, - { name: 'block', call: blockCall }, - { name: 'transaction', call: transactionCall }, - { name: 'uncle', call: uncleCall }, - { name: 'compilers', call: 'eth_compilers' }, - { name: 'flush', call: 'eth_flush' }, - { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' }, - { name: 'serpent', call: 'eth_serpent' }, - { name: 'logs', call: 'eth_logs' } - ]; - return methods; -}; - -/// @returns an array of objects describing web3.eth api properties -var ethProperties = function () { - return [ - { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' }, - { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' }, - { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' }, - { name: 'gasPrice', getter: 'eth_gasPrice' }, - { name: 'accounts', getter: 'eth_accounts' }, - { name: 'peerCount', getter: 'eth_peerCount' }, - { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' }, - { name: 'number', getter: 'eth_number'} - ]; -}; - -/// @returns an array of objects describing web3.db api methods -var dbMethods = function () { - return [ - { name: 'put', call: 'db_put' }, - { name: 'get', call: 'db_get' }, - { name: 'putString', call: 'db_putString' }, - { name: 'getString', call: 'db_getString' } - ]; -}; - -/// @returns an array of objects describing web3.shh api methods -var shhMethods = function () { - return [ - { name: 'post', call: 'shh_post' }, - { name: 'newIdentity', call: 'shh_newIdentity' }, - { name: 'haveIdentity', call: 'shh_haveIdentity' }, - { name: 'newGroup', call: 'shh_newGroup' }, - { name: 'addToGroup', call: 'shh_addToGroup' } - ]; -}; - -/// @returns an array of objects describing web3.eth.watch api methods -var ethWatchMethods = function () { - var newFilter = function (args) { - return typeof args[0] === 'string' ? 'eth_newFilterString' : 'eth_newFilter'; - }; - - return [ - { name: 'newFilter', call: newFilter }, - { name: 'uninstallFilter', call: 'eth_uninstallFilter' }, - { name: 'getMessages', call: 'eth_filterLogs' } - ]; -}; - -/// @returns an array of objects describing web3.shh.watch api methods -var shhWatchMethods = function () { - return [ - { name: 'newFilter', call: 'shh_newFilter' }, - { name: 'uninstallFilter', call: 'shh_uninstallFilter' }, - { name: 'getMessages', call: 'shh_getMessages' } - ]; -}; - /// creates methods in a given object based on method description on input /// setups api calls for these methods var setupMethods = function (obj, methods) { @@ -135,7 +49,7 @@ var setupMethods = function (obj, methods) { obj[method.name] = function () { var args = Array.prototype.slice.call(arguments); var call = typeof method.call === 'function' ? method.call(args) : method.call; - return web3.provider.send({ + return web3.manager.send({ method: call, params: args }); @@ -149,14 +63,14 @@ var setupProperties = function (obj, properties) { properties.forEach(function (property) { var proto = {}; proto.get = function () { - return web3.provider.send({ + return web3.manager.send({ method: property.getter }); }; if (property.setter) { proto.set = function (val) { - return web3.provider.send({ + return web3.manager.send({ method: property.setter, params: [val] }); @@ -166,10 +80,30 @@ var setupProperties = function (obj, properties) { }); }; +var startPolling = function (method, id, callback, uninstall) { + web3.manager.startPolling({ + method: method, + params: [id] + }, id, callback, uninstall); +}; + +var stopPolling = function (id) { + web3.manager.stopPolling(id); +}; + +var ethWatch = { + startPolling: startPolling.bind(null, 'eth_changed'), + stopPolling: stopPolling +}; + +var shhWatch = { + startPolling: startPolling.bind(null, 'shh_changed'), + stopPolling: stopPolling +}; + /// setups web3 object, and it's in-browser executed methods var web3 = { - _callbacks: {}, - _events: {}, + manager: requestManager(), providers: {}, /// @returns ascii string representation of hex value prefixed with 0x @@ -208,11 +142,12 @@ var web3 = { /// @param filter may be a string, object or event /// @param indexed is optional, this is an object with optional event indexed params /// @param options is optional, this is an object with optional event options ('max'...) - watch: function (filter, indexed, options) { - if (filter._isEvent) { - return filter(indexed, options); + /// TODO: fix it, 4 params? no way + watch: function (fil, indexed, options, formatter) { + if (fil._isEvent) { + return fil(indexed, options); } - return new web3.filter(filter, ethWatch); + return filter(fil, ethWatch, formatter); } }, @@ -221,36 +156,30 @@ var web3 = { /// shh object prototype shh: { - /// @param filter may be a string, object or event - watch: function (filter, indexed) { - return new web3.filter(filter, shhWatch); + watch: function (fil) { + return filter(fil, shhWatch); } }, + setProvider: function (provider) { + web3.manager.setProvider(provider); + }, + + /// Should be called to reset state of web3 object + /// Resets everything except manager + reset: function () { + web3.manager.reset(); + } }; /// setups all api methods setupMethods(web3, web3Methods()); -setupMethods(web3.eth, ethMethods()); -setupProperties(web3.eth, ethProperties()); -setupMethods(web3.db, dbMethods()); -setupMethods(web3.shh, shhMethods()); - -var ethWatch = { - changed: 'eth_changed' -}; - -setupMethods(ethWatch, ethWatchMethods()); - -var shhWatch = { - changed: 'shh_changed' -}; - -setupMethods(shhWatch, shhWatchMethods()); - -web3.setProvider = function(provider) { - web3.provider.set(provider); -}; +setupMethods(web3.eth, eth.methods()); +setupProperties(web3.eth, eth.properties()); +setupMethods(web3.db, db.methods()); +setupMethods(web3.shh, shh.methods()); +setupMethods(ethWatch, watches.eth()); +setupMethods(shhWatch, watches.shh()); module.exports = web3; diff --git a/package.json b/package.json index 8102a2592..40b3349e5 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,42 @@ { "name": "ethereum.js", "namespace": "ethereum", - "version": "0.0.13", + "version": "0.0.15", "description": "Ethereum Compatible JavaScript API", "main": "./index.js", "directories": { "lib": "./lib" }, "dependencies": { + "bignumber.js": ">=2.0.0", "ws": "*", - "xmlhttprequest": "*", - "bignumber.js": ">=2.0.0" + "xmlhttprequest": "*" }, "devDependencies": { "bower": ">=1.3.0", "browserify": ">=6.0", + "coveralls": "^2.11.2", "del": ">=0.1.1", "envify": "^3.0.0", "exorcist": "^0.1.6", "gulp": ">=3.4.0", "gulp-jshint": ">=1.5.0", "gulp-rename": ">=1.2.0", + "gulp-streamify": "0.0.5", "gulp-uglify": ">=1.0.0", + "istanbul": "^0.3.5", "jshint": ">=2.5.0", - "uglifyify": "^2.6.0", + "mocha": ">=2.1.0", + "mocha-lcov-reporter": "0.0.1", "unreachable-branch-transform": "^0.1.0", - "vinyl-source-stream": "^1.0.0", - "mocha": ">=2.1.0" + "vinyl-source-stream": "^1.0.0" }, "scripts": { "build": "gulp", "watch": "gulp watch", "lint": "gulp lint", - "test": "mocha" + "test": "mocha", + "test-coveralls": "istanbul cover _mocha -- -R spec && cat coverage/lcov.info | coveralls --verbose" }, "repository": { "type": "git", diff --git a/test/eth.methods.js b/test/eth.methods.js index 8f10b441d..9ea0ad59a 100644 --- a/test/eth.methods.js +++ b/test/eth.methods.js @@ -19,6 +19,8 @@ describe('web3', function() { u.methodExists(web3.eth, 'solidity'); u.methodExists(web3.eth, 'serpent'); u.methodExists(web3.eth, 'logs'); + u.methodExists(web3.eth, 'transactionCount'); + u.methodExists(web3.eth, 'uncleCount'); u.propertyExists(web3.eth, 'coinbase'); u.propertyExists(web3.eth, 'listening'); diff --git a/test/filter.methods.js b/test/filter.methods.js new file mode 100644 index 000000000..9f81ec38f --- /dev/null +++ b/test/filter.methods.js @@ -0,0 +1,27 @@ +var assert = require('assert'); +var filter = require('../lib/filter'); +var u = require('./test.utils.js'); + +var empty = function () {}; +var implementation = { + newFilter: empty, + getMessages: empty, + uninstallFilter: empty, + startPolling: empty, + stopPolling: empty, +}; + +describe('web3', function () { + describe('eth', function () { + describe('filter', function () { + var f = filter({}, implementation); + + u.methodExists(f, 'arrived'); + u.methodExists(f, 'happened'); + u.methodExists(f, 'changed'); + u.methodExists(f, 'messages'); + u.methodExists(f, 'logs'); + u.methodExists(f, 'uninstall'); + }); + }); +}); diff --git a/test/web3.methods.js b/test/web3.methods.js index 06de41da4..8dcc61101 100644 --- a/test/web3.methods.js +++ b/test/web3.methods.js @@ -6,5 +6,16 @@ describe('web3', function() { u.methodExists(web3, 'sha3'); u.methodExists(web3, 'toAscii'); u.methodExists(web3, 'fromAscii'); + u.methodExists(web3, 'toDecimal'); + u.methodExists(web3, 'fromDecimal'); + u.methodExists(web3, 'toEth'); + u.methodExists(web3, 'setProvider'); + u.methodExists(web3, 'reset'); + + u.propertyExists(web3, 'manager'); + u.propertyExists(web3, 'providers'); + u.propertyExists(web3, 'eth'); + u.propertyExists(web3, 'db'); + u.propertyExists(web3, 'shh'); }); From 307e42a6c30148dde6d3be474b1960282f4e48b2 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 17 Feb 2015 16:19:11 +0100 Subject: [PATCH 12/59] getMemberTypes() respects source order --- libsolidity/Types.cpp | 32 ++++++++++++++++---------------- libsolidity/Types.h | 8 +++++--- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index d2f0e9bfd..a9c480176 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -573,19 +573,19 @@ MemberList const& ContractType::getMembers() const if (!m_members) { // All address members and all interface functions - map members(IntegerType::AddressMemberList.begin(), - IntegerType::AddressMemberList.end()); + vector> members(IntegerType::AddressMemberList.begin(), + IntegerType::AddressMemberList.end()); if (m_super) { for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts()) for (ASTPointer const& function: base->getDefinedFunctions()) - if (!function->isConstructor() && !function->getName().empty() && + if (!function->isConstructor() && !function->getName().empty()&& function->isVisibleInDerivedContracts()) - members.insert(make_pair(function->getName(), make_shared(*function, true))); + members.push_back(make_pair(function->getName(), make_shared(*function, true))); } else for (auto const& it: m_contract.getInterfaceFunctions()) - members[it.second->getDeclaration().getName()] = it.second; + members.push_back(make_pair(it.second->getDeclaration().getName(), it.second)); m_members.reset(new MemberList(members)); } return *m_members; @@ -653,9 +653,9 @@ MemberList const& StructType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - map members; + vector> members; for (ASTPointer const& variable: m_struct.getMembers()) - members[variable->getName()] = variable->getType(); + members.push_back(make_pair(variable->getName(), variable->getType())); m_members.reset(new MemberList(members)); } return *m_members; @@ -857,15 +857,15 @@ MemberList const& FunctionType::getMembers() const case Location::Bare: if (!m_members) { - map members{ - {"gas", make_shared(parseElementaryTypeVector({"uint"}), - TypePointers{copyAndSetGasOrValue(true, false)}, - Location::SetGas, false, m_gasSet, m_valueSet)}, + vector> members{ {"value", make_shared(parseElementaryTypeVector({"uint"}), TypePointers{copyAndSetGasOrValue(false, true)}, Location::SetValue, false, m_gasSet, m_valueSet)}}; - if (m_location == Location::Creation) - members.erase("gas"); + if (m_location != Location::Creation) + members.push_back(make_pair("gas", make_shared( + parseElementaryTypeVector({"uint"}), + TypePointers{copyAndSetGasOrValue(true, false)}, + Location::SetGas, false, m_gasSet, m_valueSet))); m_members.reset(new MemberList(members)); } return *m_members; @@ -959,7 +959,7 @@ MemberList const& TypeType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - map members; + vector> members; if (m_actualType->getCategory() == Category::Contract && m_currentContract != nullptr) { ContractDefinition const& contract = dynamic_cast(*m_actualType).getContractDefinition(); @@ -969,14 +969,14 @@ MemberList const& TypeType::getMembers() const // functions. Note that this does not add inherited functions on purpose. for (ASTPointer const& f: contract.getDefinedFunctions()) if (!f->isConstructor() && !f->getName().empty() && f->isVisibleInDerivedContracts()) - members[f->getName()] = make_shared(*f); + members.push_back(make_pair(f->getName(), make_shared(*f))); } else if (m_actualType->getCategory() == Category::Enum) { EnumDefinition const& enumDef = dynamic_cast(*m_actualType).getEnumDefinition(); auto enumType = make_shared(enumDef); for (ASTPointer const& enumValue: enumDef.getMembers()) - members.insert(make_pair(enumValue->getName(), enumType)); + members.push_back(make_pair(enumValue->getName(), enumType)); } m_members.reset(new MemberList(members)); } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index b66857f0c..d529d8d08 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -50,14 +50,16 @@ using TypePointers = std::vector; class MemberList { public: - using MemberMap = std::map; + using MemberMap = std::vector>; MemberList() {} explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {} TypePointer getMemberType(std::string const& _name) const { - auto it = m_memberTypes.find(_name); - return it != m_memberTypes.end() ? it->second : TypePointer(); + for (auto const& it: m_memberTypes) + if (it.first == _name) + return it.second; + return TypePointer(); } MemberMap::const_iterator begin() const { return m_memberTypes.begin(); } From 05938330e6b5295ae5fe11bc7fabac257a718da2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 17 Feb 2015 23:01:46 +0100 Subject: [PATCH 13/59] Style fix. --- alethzero/Transact.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index 3031232c2..bfeb41d9a 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -169,9 +169,7 @@ void Transact::rejigData() QString lll; QString solidity; if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0) - { m_data = fromHex(src); - } else if (sourceIsSolidity(src)) { dev::solidity::CompilerStack compiler; From c1572ea90bff2d03122af2753260d2ee30b4824f Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 18 Feb 2015 00:15:08 +0100 Subject: [PATCH 14/59] Fixes for assigning and deleting structs containing byte arrays. --- libsolidity/CompilerContext.h | 1 + libsolidity/ExpressionCompiler.cpp | 25 ++++++++++++++++++++- libsolidity/ExpressionCompiler.h | 2 +- test/SolidityEndToEndTest.cpp | 36 ++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 6d6a65b61..f202d7f4e 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -48,6 +48,7 @@ public: bytes const& getCompiledContract(ContractDefinition const& _contract) const; void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } + unsigned getStackHeight() { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; } bool isLocalVariable(Declaration const* _declaration) const; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 3bf1c8c93..a8bc53e0f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1119,9 +1119,13 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co { solAssert(_sourceType.getCategory() == m_dataType->getCategory(), ""); if (m_dataType->getCategory() == Type::Category::ByteArray) + { CompilerUtils(*m_context).copyByteArrayToStorage( dynamic_cast(*m_dataType), dynamic_cast(_sourceType)); + if (_move) + *m_context << eth::Instruction::POP; + } else if (m_dataType->getCategory() == Type::Category::Struct) { // stack layout: source_ref target_ref @@ -1136,12 +1140,14 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co *m_context << structType.getStorageOffsetOfMember(member.first) << eth::Instruction::DUP3 << eth::Instruction::DUP2 << eth::Instruction::ADD; + // stack: source_ref target_ref member_offset source_member_ref LValue rightHandSide(*m_context, LValueType::Storage, memberType); rightHandSide.retrieveValue(_location, true); - // stack: source_ref target_ref offset source_value... + // stack: source_ref target_ref member_offset source_value... *m_context << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD; + // stack: source_ref target_ref member_offset source_value... target_member_ref LValue memberLValue(*m_context, LValueType::Storage, memberType); memberLValue.storeValue(*memberType, _location, true); *m_context << eth::Instruction::POP; @@ -1189,6 +1195,23 @@ void ExpressionCompiler::LValue::setToZero(Location const& _location) const case LValueType::Storage: if (m_dataType->getCategory() == Type::Category::ByteArray) CompilerUtils(*m_context).clearByteArray(dynamic_cast(*m_dataType)); + else if (m_dataType->getCategory() == Type::Category::Struct) + { + // stack layout: ref + auto const& structType = dynamic_cast(*m_dataType); + for (auto const& member: structType.getMembers()) + { + // zero each member that is not a mapping + TypePointer const& memberType = member.second; + if (memberType->getCategory() == Type::Category::Mapping) + continue; + *m_context << structType.getStorageOffsetOfMember(member.first) + << eth::Instruction::DUP2 << eth::Instruction::ADD; + LValue memberValue(*m_context, LValueType::Storage, memberType); + memberValue.setToZero(); + } + *m_context << eth::Instruction::POP; + } else { if (m_size == 0) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 734da50de..471d81865 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -144,7 +144,7 @@ private: void retrieveValue(Location const& _location, bool _remove = false) const; /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true. /// @a _location is the source location of the expression that caused this operation. - /// Stack pre: [lvalue_ref] value + /// Stack pre: value [lvalue_ref] /// Stack post if !_move: value_of(lvalue_ref) void storeValue(Type const& _sourceType, Location const& _location = Location(), bool _move = false) const; /// Stores zero in the lvalue. diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 103b11269..8c87db2d8 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2479,6 +2479,42 @@ BOOST_AUTO_TEST_CASE(struct_copy) BOOST_CHECK(callContractFunction("retrieve(uint256)", 8) == encodeArgs(0, 0, 0, 0)); } +BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) +{ + char const* sourceCode = R"( + contract c { + struct Struct { uint a; bytes data; uint b; } + Struct data1; + Struct data2; + function set(uint _a, bytes _data, uint _b) external returns (bool) { + data1.a = _a; + data1.b = _b; + data1.data = _data; + return true; + } + function copy() returns (bool) { + data1 = data2; + return true; + } + function del() returns (bool) { + delete data1; + return true; + } + } + )"; + compileAndRun(sourceCode); + string data = "123456789012345678901234567890123"; + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true)); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true)); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true)); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("del()") == encodeArgs(true)); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + BOOST_AUTO_TEST_CASE(struct_copy_via_local) { char const* sourceCode = R"( From 27d436a04cd35a11de1345e4af045853d626b38b Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 18 Feb 2015 13:35:12 +0100 Subject: [PATCH 15/59] Rename "protected" to "inheritable". --- libsolidity/AST.h | 6 +++--- libsolidity/Parser.cpp | 4 ++-- libsolidity/Token.h | 4 ++-- libsolidity/grammar.txt | 4 ++-- test/SolidityNameAndTypeResolution.cpp | 12 ++++++------ test/SolidityParser.cpp | 6 +++--- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index af45934f7..62855bc7a 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -133,7 +133,7 @@ class Declaration: public ASTNode { public: /// Visibility ordered from restricted to unrestricted. - enum class Visibility { Default, Private, Protected, Public, External }; + enum class Visibility { Default, Private, Inheritable, Public, External }; Declaration(Location const& _location, ASTPointer const& _name, Visibility _visibility = Visibility::Default): @@ -144,7 +144,7 @@ public: Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } bool isPublic() const { return getVisibility() >= Visibility::Public; } bool isVisibleInContract() const { return getVisibility() != Visibility::External; } - bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Protected; } + bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Inheritable; } /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. @@ -453,7 +453,7 @@ public: bool isIndexed() const { return m_isIndexed; } protected: - Visibility getDefaultVisibility() const override { return Visibility::Protected; } + Visibility getDefaultVisibility() const override { return Visibility::Inheritable; } private: ASTPointer m_typeName; ///< can be empty ("var") diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index cf57ca50e..72334c6cc 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -186,8 +186,8 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) Declaration::Visibility visibility(Declaration::Visibility::Default); if (_token == Token::Public) visibility = Declaration::Visibility::Public; - else if (_token == Token::Protected) - visibility = Declaration::Visibility::Protected; + else if (_token == Token::Inheritable) + visibility = Declaration::Visibility::Inheritable; else if (_token == Token::Private) visibility = Declaration::Visibility::Private; else if (_token == Token::External) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 7bf8a7ef0..e9765e5eb 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -162,7 +162,7 @@ namespace solidity K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Protected, "protected", 0) \ + K(Inheritable, "inheritable", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ @@ -380,7 +380,7 @@ public: static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } - static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; } + static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Inheritable; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } // Returns a string corresponding to the JS token string diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 5e6e65f85..a3b246873 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -6,10 +6,10 @@ ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition InheritanceSpecifier = Identifier ( '(' Expression ( ',' Expression )* ')' )? StructDefinition = 'struct' Identifier '{' ( VariableDeclaration (';' VariableDeclaration)* )? '} -StateVariableDeclaration = TypeName ( 'public' | 'protected' | 'private' )? Identifier ';' +StateVariableDeclaration = TypeName ( 'public' | 'inheritable' | 'private' )? Identifier ';' ModifierDefinition = 'modifier' Identifier ParameterList? Block FunctionDefinition = 'function' Identifier ParameterList - ( Identifier | 'constant' | 'public' | 'protected' | 'private' )* + ( Identifier | 'constant' | 'external' | 'public' | 'inheritable' | 'private' )* ( 'returns' ParameterList )? Block EnumValue = Identifier diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 6b337ac74..bfef873c4 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -470,7 +470,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_indirect) BOOST_AUTO_TEST_CASE(illegal_override_visibility) { char const* text = R"( - contract B { function f() protected {} } + contract B { function f() inheritable {} } contract C is B { function f() public {} } )"; BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); @@ -706,7 +706,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) " uint64(2);\n" " }\n" "uint256 private foo;\n" - "uint256 protected bar;\n" + "uint256 inheritable bar;\n" "}\n"; ASTPointer source; @@ -717,7 +717,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) function = retrieveFunctionBySignature(contract, "foo()"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist"); function = retrieveFunctionBySignature(contract, "bar()"); - BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a protected variable should not exist"); + BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an inheritable variable should not exist"); } BOOST_AUTO_TEST_CASE(fallback_function) @@ -832,11 +832,11 @@ BOOST_AUTO_TEST_CASE(access_to_default_function_visibility) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } -BOOST_AUTO_TEST_CASE(access_to_protected_function) +BOOST_AUTO_TEST_CASE(access_to_inheritable_function) { char const* text = R"( contract c { - function f() protected {} + function f() inheritable {} } contract d { function g() { c(0).f(); } @@ -856,7 +856,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } -BOOST_AUTO_TEST_CASE(access_to_protected_state_variable) +BOOST_AUTO_TEST_CASE(access_to_inheritable_state_variable) { char const* text = R"( contract c { diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 5f9064e0c..ddb582447 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -651,13 +651,13 @@ BOOST_AUTO_TEST_CASE(visibility_specifiers) char const* text = R"( contract c { uint private a; - uint protected b; + uint inheritable b; uint public c; uint d; function f() {} function f_priv() private {} function f_public() public {} - function f_protected() protected {} + function f_inheritable() inheritable {} })"; BOOST_CHECK_NO_THROW(parseText(text)); } @@ -666,7 +666,7 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers) { char const* text = R"( contract c { - uint private protected a; + uint private inheritable a; })"; BOOST_CHECK_THROW(parseText(text), ParserError); } From 551d7588e1db010cd43497a4575c9a2a5ea37dc8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 18 Feb 2015 14:09:26 +0100 Subject: [PATCH 16/59] Disable SECP256k1 windows warnings. --- secp256k1/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secp256k1/CMakeLists.txt b/secp256k1/CMakeLists.txt index 8dbe175d5..deafa245a 100644 --- a/secp256k1/CMakeLists.txt +++ b/secp256k1/CMakeLists.txt @@ -31,7 +31,7 @@ else() add_library(${EXECUTABLE} SHARED ${EXECUTABLE}.c) endif() # /TP - compile project as cpp project - set_target_properties(${EXECUTABLE} PROPERTIES COMPILE_FLAGS "/TP") + set_target_properties(${EXECUTABLE} PROPERTIES COMPILE_FLAGS "/TP /wd4244") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_NUM_BOOST -DUSE_FIELD_10X26 -DUSE_FIELD_INV_BUILTIN") endif() From 9dffb5fe937f407776f7189e9907d045d8c85ae4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 18 Feb 2015 15:27:19 +0100 Subject: [PATCH 17/59] Fixes #1088. --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 7e15ada90..8e0b30366 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -542,7 +542,7 @@ std::string WebThreeStubServerBase::eth_solidity(std::string const& _code) int WebThreeStubServerBase::eth_number() { - return client()->number() + 1; + return client()->number(); } int WebThreeStubServerBase::eth_peerCount() From 88955a7049bc2179ef875856578831f3325614ee Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 19 Feb 2015 08:21:12 +0100 Subject: [PATCH 18/59] Squashed 'libjsqrc/ethereumjs/' changes from 9a85b09..c4c3b12 c4c3b12 fallback for go-ethereum && fixed parsing ethereum messages git-subtree-dir: libjsqrc/ethereumjs git-subtree-split: c4c3b126a3f385eeeca6027b1f544c6536f94b6b --- dist/ethereum.js | 3 ++- dist/ethereum.js.map | 6 +++--- dist/ethereum.min.js | 2 +- lib/event.js | 1 + lib/filter.js | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dist/ethereum.js b/dist/ethereum.js index 712e5d259..73b6e56ee 100644 --- a/dist/ethereum.js +++ b/dist/ethereum.js @@ -715,6 +715,7 @@ var outputParser = function (event) { args: {} }; + output.topics = output.topic; // fallback for go-ethereum if (!output.topic) { return result; } @@ -829,7 +830,7 @@ var filter = function(options, implementation, formatter) { var filterId = implementation.newFilter(options); var onMessages = function (messages) { messages.forEach(function (message) { - messages = formatter ? formatter(message) : message; + message = formatter ? formatter(message) : message; callbacks.forEach(function (callback) { callback(message); }); diff --git a/dist/ethereum.js.map b/dist/ethereum.js.map index 8c25b78c4..5bf0e8f1b 100644 --- a/dist/ethereum.js.map +++ b/dist/ethereum.js.map @@ -22,7 +22,7 @@ "index.js" ], "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", + "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "file": "generated.js", "sourceRoot": "", "sourcesContent": [ @@ -32,8 +32,8 @@ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file contract.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('./web3'); \nvar abi = require('./abi');\nvar utils = require('./utils');\nvar eventImpl = require('./event');\nvar filter = require('./filter');\n\nvar exportNatspecGlobals = function (vars) {\n // it's used byt natspec.js\n // TODO: figure out better way to solve this\n web3._currentContractAbi = vars.abi;\n web3._currentContractAddress = vars.address;\n web3._currentContractMethodName = vars.method;\n web3._currentContractMethodParams = vars.params;\n};\n\nvar addFunctionRelatedPropertiesToContract = function (contract) {\n \n contract.call = function (options) {\n contract._isTransact = false;\n contract._options = options;\n return contract;\n };\n\n contract.transact = function (options) {\n contract._isTransact = true;\n contract._options = options;\n return contract;\n };\n\n contract._options = {};\n ['gas', 'gasPrice', 'value', 'from'].forEach(function(p) {\n contract[p] = function (v) {\n contract._options[p] = v;\n return contract;\n };\n });\n\n};\n\nvar addFunctionsToContract = function (contract, desc, address) {\n var inputParser = abi.inputParser(desc);\n var outputParser = abi.outputParser(desc);\n\n // create contract functions\n utils.filterFunctions(desc).forEach(function (method) {\n\n var displayName = utils.extractDisplayName(method.name);\n var typeName = utils.extractTypeName(method.name);\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.signatureFromAscii(method.name);\n var parsed = inputParser[displayName][typeName].apply(null, params);\n\n var options = contract._options || {};\n options.to = address;\n options.data = signature + parsed;\n \n var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant);\n var collapse = options.collapse !== false;\n \n // reset\n contract._options = {};\n contract._isTransact = null;\n\n if (isTransact) {\n \n exportNatspecGlobals({\n abi: desc,\n address: address,\n method: method.name,\n params: params\n });\n\n // transactions do not have any output, cause we do not know, when they will be processed\n web3.eth.transact(options);\n return;\n }\n \n var output = web3.eth.call(options);\n var ret = outputParser[displayName][typeName](output);\n if (collapse)\n {\n if (ret.length === 1)\n ret = ret[0];\n else if (ret.length === 0)\n ret = null;\n }\n return ret;\n };\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n });\n};\n\nvar addEventRelatedPropertiesToContract = function (contract, desc, address) {\n contract.address = address;\n contract._onWatchEventResult = function (data) {\n var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));\n var parser = eventImpl.outputParser(matchingEvent);\n return parser(data);\n };\n \n Object.defineProperty(contract, 'topic', {\n get: function() {\n return utils.filterEvents(desc).map(function (e) {\n return abi.eventSignatureFromAscii(e.name);\n });\n }\n });\n\n};\n\nvar addEventsToContract = function (contract, desc, address) {\n // create contract events\n utils.filterEvents(desc).forEach(function (e) {\n\n var impl = function () {\n var params = Array.prototype.slice.call(arguments);\n var signature = abi.eventSignatureFromAscii(e.name);\n var event = eventImpl.inputParser(address, signature, e);\n var o = event.apply(null, params);\n var outputFormatter = function (data) {\n var parser = eventImpl.outputParser(e);\n return parser(data);\n };\n return web3.eth.watch(o, undefined, undefined, outputFormatter);\n };\n \n // this property should be used by eth.filter to check if object is an event\n impl._isEvent = true;\n\n var displayName = utils.extractDisplayName(e.name);\n var typeName = utils.extractTypeName(e.name);\n\n if (contract[displayName] === undefined) {\n contract[displayName] = impl;\n }\n\n contract[displayName][typeName] = impl;\n\n });\n};\n\n\n/**\n * This method should be called when we want to call / transact some solidity method from javascript\n * it returns an object which has same methods available as solidity contract description\n * usage example: \n *\n * var abi = [{\n * name: 'myMethod',\n * inputs: [{ name: 'a', type: 'string' }],\n * outputs: [{name: 'd', type: 'string' }]\n * }]; // contract abi\n *\n * var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object\n *\n * myContract.myMethod('this is test string param for call'); // myMethod call (implicit, default)\n * myContract.call().myMethod('this is test string param for call'); // myMethod call (explicit)\n * myContract.transact().myMethod('this is test string param for transact'); // myMethod transact\n *\n * @param address - address of the contract, which should be called\n * @param desc - abi json description of the contract, which is being created\n * @returns contract object\n */\n\nvar contract = function (address, desc) {\n\n // workaround for invalid assumption that method.name is the full anonymous prototype of the method.\n // it's not. it's just the name. the rest of the code assumes it's actually the anonymous\n // prototype, so we make it so as a workaround.\n // TODO: we may not want to modify input params, maybe use copy instead?\n desc.forEach(function (method) {\n if (method.name.indexOf('(') === -1) {\n var displayName = method.name;\n var typeName = method.inputs.map(function(i){return i.type; }).join();\n method.name = displayName + '(' + typeName + ')';\n }\n });\n\n var result = {};\n addFunctionRelatedPropertiesToContract(result);\n addFunctionsToContract(result, desc, address);\n addEventRelatedPropertiesToContract(result, desc, address);\n addEventsToContract(result, desc, address);\n\n return result;\n};\n\nmodule.exports = contract;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.db api methods\nvar methods = function () {\n return [\n { name: 'put', call: 'db_put' },\n { name: 'get', call: 'db_get' },\n { name: 'putString', call: 'db_putString' },\n { name: 'getString', call: 'db_getString' }\n ];\n};\n\nmodule.exports = {\n methods: methods\n};\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file eth.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/// @returns an array of objects describing web3.eth api methods\nvar methods = function () {\n var blockCall = function (args) {\n return typeof args[0] === \"string\" ? \"eth_blockByHash\" : \"eth_blockByNumber\";\n };\n\n var transactionCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionByHash' : 'eth_transactionByNumber';\n };\n\n var uncleCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleByHash' : 'eth_uncleByNumber';\n };\n\n var transactionCountCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_transactionCountByHash' : 'eth_transactionCountByNumber';\n };\n\n var uncleCountCall = function (args) {\n return typeof args[0] === \"string\" ? 'eth_uncleCountByHash' : 'eth_uncleCountByNumber';\n };\n\n return [\n { name: 'balanceAt', call: 'eth_balanceAt' },\n { name: 'stateAt', call: 'eth_stateAt' },\n { name: 'storageAt', call: 'eth_storageAt' },\n { name: 'countAt', call: 'eth_countAt'},\n { name: 'codeAt', call: 'eth_codeAt' },\n { name: 'transact', call: 'eth_transact' },\n { name: 'call', call: 'eth_call' },\n { name: 'block', call: blockCall },\n { name: 'transaction', call: transactionCall },\n { name: 'uncle', call: uncleCall },\n { name: 'compilers', call: 'eth_compilers' },\n { name: 'flush', call: 'eth_flush' },\n { name: 'lll', call: 'eth_lll' },\n { name: 'solidity', call: 'eth_solidity' },\n { name: 'serpent', call: 'eth_serpent' },\n { name: 'logs', call: 'eth_logs' },\n { name: 'transactionCount', call: transactionCountCall },\n { name: 'uncleCount', call: uncleCountCall }\n ];\n};\n\n/// @returns an array of objects describing web3.eth api properties\nvar properties = function () {\n return [\n { name: 'coinbase', getter: 'eth_coinbase', setter: 'eth_setCoinbase' },\n { name: 'listening', getter: 'eth_listening', setter: 'eth_setListening' },\n { name: 'mining', getter: 'eth_mining', setter: 'eth_setMining' },\n { name: 'gasPrice', getter: 'eth_gasPrice' },\n { name: 'accounts', getter: 'eth_accounts' },\n { name: 'peerCount', getter: 'eth_peerCount' },\n { name: 'defaultBlock', getter: 'eth_defaultBlock', setter: 'eth_setDefaultBlock' },\n { name: 'number', getter: 'eth_number'}\n ];\n};\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('./abi');\nvar utils = require('./utils');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, signature, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topic = [];\n o.topic.push(signature);\n if (indexed) {\n o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexed.splice(0, 1)[0];\n else\n value = notIndexed.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n args: {}\n };\n\n if (!output.topic) {\n return result;\n }\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var signature = abi.eventSignatureFromAscii(events[i].name); \n if (signature === payload.topic[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\n/// Should be called to check if filter implementation is valid\n/// @returns true if it is, otherwise false\nvar implementationIsValid = function (i) {\n return !!i && \n typeof i.newFilter === 'function' && \n typeof i.getMessages === 'function' && \n typeof i.uninstallFilter === 'function' &&\n typeof i.startPolling === 'function' &&\n typeof i.stopPolling === 'function';\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n if (typeof options === 'string') {\n return options;\n } \n\n options = options || {};\n\n if (options.topics) {\n console.warn('\"topics\" is deprecated, is \"topic\" instead');\n }\n\n // evaluate lazy properties\n return {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n};\n\n/// Should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// @param options are filter options\n/// @param implementation, an abstract polling implementation\n/// @param formatter (optional), callback function which formats output before 'real' callback \nvar filter = function(options, implementation, formatter) {\n if (!implementationIsValid(implementation)) {\n console.error('filter implemenation is invalid');\n return;\n }\n\n options = getOptions(options);\n var callbacks = [];\n var filterId = implementation.newFilter(options);\n var onMessages = function (messages) {\n messages.forEach(function (message) {\n messages = formatter ? formatter(message) : message;\n callbacks.forEach(function (callback) {\n callback(message);\n });\n });\n };\n\n implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);\n\n var changed = function (callback) {\n callbacks.push(callback);\n };\n\n var messages = function () {\n return implementation.getMessages(filterId);\n };\n \n var uninstall = function (callback) {\n implementation.stopPolling(filterId);\n implementation.uninstallFilter(filterId);\n callbacks = [];\n };\n\n return {\n changed: changed,\n arrived: changed,\n happened: changed,\n messages: messages,\n logs: messages,\n uninstall: uninstall\n };\n};\n\nmodule.exports = filter;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('./abi');\nvar utils = require('./utils');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, signature, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topic = [];\n o.topic.push(signature);\n if (indexed) {\n o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexed.splice(0, 1)[0];\n else\n value = notIndexed.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n args: {}\n };\n\n output.topics = output.topic; // fallback for go-ethereum\n if (!output.topic) {\n return result;\n }\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var signature = abi.eventSignatureFromAscii(events[i].name); \n if (signature === payload.topic[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\n};\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\n/// Should be called to check if filter implementation is valid\n/// @returns true if it is, otherwise false\nvar implementationIsValid = function (i) {\n return !!i && \n typeof i.newFilter === 'function' && \n typeof i.getMessages === 'function' && \n typeof i.uninstallFilter === 'function' &&\n typeof i.startPolling === 'function' &&\n typeof i.stopPolling === 'function';\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n if (typeof options === 'string') {\n return options;\n } \n\n options = options || {};\n\n if (options.topics) {\n console.warn('\"topics\" is deprecated, is \"topic\" instead');\n }\n\n // evaluate lazy properties\n return {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n};\n\n/// Should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// @param options are filter options\n/// @param implementation, an abstract polling implementation\n/// @param formatter (optional), callback function which formats output before 'real' callback \nvar filter = function(options, implementation, formatter) {\n if (!implementationIsValid(implementation)) {\n console.error('filter implemenation is invalid');\n return;\n }\n\n options = getOptions(options);\n var callbacks = [];\n var filterId = implementation.newFilter(options);\n var onMessages = function (messages) {\n messages.forEach(function (message) {\n message = formatter ? formatter(message) : message;\n callbacks.forEach(function (callback) {\n callback(message);\n });\n });\n };\n\n implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);\n\n var changed = function (callback) {\n callbacks.push(callback);\n };\n\n var messages = function () {\n return implementation.getMessages(filterId);\n };\n \n var uninstall = function (callback) {\n implementation.stopPolling(filterId);\n implementation.uninstallFilter(filterId);\n callbacks = [];\n };\n\n return {\n changed: changed,\n arrived: changed,\n happened: changed,\n messages: messages,\n logs: messages,\n uninstall: uninstall\n };\n};\n\nmodule.exports = filter;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file formatters.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar utils = require('./utils');\nvar c = require('./const');\n\n/// @param string string to be padded\n/// @param number of characters that result string should have\n/// @param sign, by default 0\n/// @returns right aligned string\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/// Formats input value to byte representation of int\n/// If value is negative, return it's two's complement\n/// If the value is floating point, round it down\n/// @returns right-aligned byte representation of int\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n if (value instanceof BigNumber || typeof value === 'number') {\n if (typeof value === 'number')\n value = new BigNumber(value);\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n value = value.round();\n\n if (value.lessThan(0)) \n value = new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(value).plus(1);\n value = value.toString(16);\n }\n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else if (typeof value === 'string')\n value = formatInputInt(new BigNumber(value));\n else\n value = (+value).toString(16);\n return padLeft(value, padding);\n};\n\n/// Formats input value to byte representation of string\n/// @returns left-algined byte representation of string\nvar formatInputString = function (value) {\n return utils.fromAscii(value, c.ETH_PADDING).substr(2);\n};\n\n/// Formats input value to byte representation of bool\n/// @returns right-aligned byte representation bool\nvar formatInputBool = function (value) {\n return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n};\n\n/// Formats input value to byte representation of real\n/// Values are multiplied by 2^m and encoded as integers\n/// @returns byte representation of real\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); \n};\n\n\n/// Check if input value is negative\n/// @param value is hex format\n/// @returns true if it is negative, otherwise false\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/// Formats input right-aligned input bytes to int\n/// @returns right-aligned input bytes formatted to int\nvar formatOutputInt = function (value) {\n value = value || \"0\";\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/// Formats big right-aligned input bytes to uint\n/// @returns right-aligned input bytes formatted to uint\nvar formatOutputUInt = function (value) {\n value = value || \"0\";\n return new BigNumber(value, 16);\n};\n\n/// @returns input bytes formatted to real\nvar formatOutputReal = function (value) {\n return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns input bytes formatted to ureal\nvar formatOutputUReal = function (value) {\n return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns right-aligned input bytes formatted to hex\nvar formatOutputHash = function (value) {\n return \"0x\" + value;\n};\n\n/// @returns right-aligned input bytes formatted to bool\nvar formatOutputBool = function (value) {\n return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/// @returns left-aligned input bytes formatted to ascii string\nvar formatOutputString = function (value) {\n return utils.toAscii(value);\n};\n\n/// @returns right-aligned input bytes formatted to address\nvar formatOutputAddress = function (value) {\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputString: formatInputString,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputHash: formatOutputHash,\n formatOutputBool: formatOutputBool,\n formatOutputString: formatOutputString,\n formatOutputAddress: formatOutputAddress\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://localhost:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n\n var result = request.responseText;\n // check request.status\n if(request.status !== 200)\n return;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar messageId = 1;\n\n/// Should be called to valid json create payload object\n/// @param method of jsonrpc call, required\n/// @param params, an array of method params, optional\n/// @returns valid jsonrpc payload object\nvar toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: messageId++\n }; \n};\n\n/// Should be called to check if jsonrpc response is valid\n/// @returns true if response is valid, otherwise false \nvar isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/// Should be called to create batch payload object\n/// @param messages, an array of objects with method (required) and params (optional) fields\nvar toBatchPayload = function (messages) {\n return messages.map(function (message) {\n return toPayload(message.method, message.params);\n }); \n};\n\nmodule.exports = {\n toPayload: toPayload,\n isValidResponse: isValidResponse,\n toBatchPayload: toBatchPayload\n};\n\n\n", diff --git a/dist/ethereum.min.js b/dist/ethereum.min.js index bb8a10c35..cbf98f363 100644 --- a/dist/ethereum.min.js +++ b/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file +require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(n.topics=n.topic,!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file diff --git a/lib/event.js b/lib/event.js index 0c41e0a39..f8b61f3f9 100644 --- a/lib/event.js +++ b/lib/event.js @@ -99,6 +99,7 @@ var outputParser = function (event) { args: {} }; + output.topics = output.topic; // fallback for go-ethereum if (!output.topic) { return result; } diff --git a/lib/filter.js b/lib/filter.js index e7aa1ef2e..cf04b44f1 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -76,7 +76,7 @@ var filter = function(options, implementation, formatter) { var filterId = implementation.newFilter(options); var onMessages = function (messages) { messages.forEach(function (message) { - messages = formatter ? formatter(message) : message; + message = formatter ? formatter(message) : message; callbacks.forEach(function (callback) { callback(message); }); From 7ead7052a31b4a7e698e86acea61e59b67ef1b37 Mon Sep 17 00:00:00 2001 From: Alexandre Van de Sande Date: Thu, 19 Feb 2015 12:01:11 +0100 Subject: [PATCH 19/59] Started Branch UI --- mix/qml/Debugger.qml | 14 +++++++------- mix/qml/ProjectList.qml | 10 +++++++--- mix/qml/StepActionImage.qml | 19 +++++++++++++------ mix/qml/img/dappProjectIcon.png | Bin 0 -> 2144 bytes mix/qml/img/jumpintoback.png | Bin 762 -> 953 bytes mix/qml/img/jumpintobackdisabled.png | Bin 678 -> 865 bytes mix/qml/img/jumpintoforward.png | Bin 785 -> 981 bytes mix/qml/img/jumpintoforwarddisabled.png | Bin 695 -> 915 bytes mix/qml/img/jumpoutback.png | Bin 700 -> 860 bytes mix/qml/img/jumpoutbackdisabled.png | Bin 634 -> 806 bytes mix/qml/img/jumpoutforward.png | Bin 674 -> 866 bytes mix/qml/img/jumpoutforwarddisabled.png | Bin 580 -> 773 bytes mix/qml/img/jumpoverback.png | Bin 692 -> 1051 bytes mix/qml/img/jumpoverbackdisabled.png | Bin 532 -> 930 bytes mix/qml/img/jumpoverforward.png | Bin 717 -> 1017 bytes mix/qml/img/jumpoverforwarddisabled.png | Bin 0 -> 893 bytes mix/qml/img/opentriangleindicator@2x.png | Bin 0 -> 836 bytes mix/res.qrc | 2 ++ 18 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 mix/qml/img/dappProjectIcon.png create mode 100644 mix/qml/img/jumpoverforwarddisabled.png create mode 100644 mix/qml/img/opentriangleindicator@2x.png diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 316ec86c7..52587dd4e 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -164,7 +164,7 @@ Rectangle { Rectangle { // step button + slider id: buttonRow - height: 27 + height: 30 Layout.fillWidth: true color: "transparent" @@ -184,7 +184,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoutback.png" disableStateImg: "qrc:/qml/img/jumpoutbackdisabled.png" onClicked: Debugger.stepOutBack() - width: 28 + width: 30 height: 30 buttonShortcut: "Ctrl+Shift+F11" buttonTooltip: qsTr("Step Out Back") @@ -196,7 +196,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpintoback.png" disableStateImg: "qrc:/qml/img/jumpintobackdisabled.png" onClicked: Debugger.stepIntoBack() - width: 28 + width: 30 height: 30 buttonShortcut: "Ctrl+F11" buttonTooltip: qsTr("Step Into Back") @@ -208,7 +208,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoverback.png" disableStateImg: "qrc:/qml/img/jumpoverbackdisabled.png" onClicked: Debugger.stepOverBack() - width: 28 + width: 30 height: 30 buttonShortcut: "Ctrl+F10" buttonTooltip: qsTr("Step Over Back") @@ -220,7 +220,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoverforward.png" disableStateImg: "qrc:/qml/img/jumpoverforwarddisabled.png" onClicked: Debugger.stepOverForward() - width: 28 + width: 30 height: 30 buttonShortcut: "F10" buttonTooltip: qsTr("Step Over Forward") @@ -232,7 +232,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpintoforward.png" disableStateImg: "qrc:/qml/img/jumpintoforwarddisabled.png" onClicked: Debugger.stepIntoForward() - width: 28 + width: 30 height: 30 buttonShortcut: "F11" buttonTooltip: qsTr("Step Into Forward") @@ -244,7 +244,7 @@ Rectangle { enabledStateImg: "qrc:/qml/img/jumpoutforward.png" disableStateImg: "qrc:/qml/img/jumpoutforwarddisabled.png" onClicked: Debugger.stepOutForward() - width: 28 + width: 30 height: 30 buttonShortcut: "Shift+F11" buttonTooltip: qsTr("Step Out Forward") diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index d4875220a..ba162793b 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -25,11 +25,15 @@ Item { Layout.fillWidth: true Image { id: projectIcon - source: "qrc:/qml/img/projecticon.png" - sourceSize.height: 30 + source: "qrc:/qml/img/dappProjectIcon.png" + //sourceSize.height: 32 anchors.right: projectTitle.left anchors.verticalCenter: parent.verticalCenter anchors.rightMargin: 6 + //anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 32 + height: 32 } Text @@ -115,7 +119,7 @@ Item { ci++; } } - } + } } } diff --git a/mix/qml/StepActionImage.qml b/mix/qml/StepActionImage.qml index a4ff23e54..e5129e379 100644 --- a/mix/qml/StepActionImage.qml +++ b/mix/qml/StepActionImage.qml @@ -16,19 +16,26 @@ Rectangle { { buttonAction.enabled = state; if (state) - debugImg.iconSource = enabledStateImg; + debugImage.source = enabledStateImg; else - debugImg.iconSource = disableStateImg; + debugImage.source = disableStateImg; } Button { anchors.fill: parent id: debugImg - iconSource: enabledStateImg - action: buttonAction - width: buttonActionContainer.width - 3 - height: buttonActionContainer.height +/* iconSource: enabledStateImg +*/ action: buttonAction + } + + Image { + id: debugImage + source: enabledStateImg + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + width: 15 + height: 15 } Action { diff --git a/mix/qml/img/dappProjectIcon.png b/mix/qml/img/dappProjectIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..eea9025d03cae05e0300837e2e57e04639da7c1c GIT binary patch literal 2144 zcmV-m2%qPx-8c9S!RCodHT3bw1M;IPpK@bE1(Rv2~wO&x72^TLE2oL&NN$gwIS_4>3?1O!1 zQetdF+SF7Oo7SX#vC)UtXsRYA4fTRoyg&g_yd)wjRzVFcx8>6Bo9;9V=NxwTEW0-G zOoC_k%0!$R9Dwrj^5m$fsPBV=gR^JNniZLlkT7`l z>eb$%p`qU#4#%fOMMZxPlhDs!0tNsSkB*3l*bRL?TDELiXj)pDt*)+4EL^xyKzUJJ zUESN**w{ZfIJoQS)2H9TJo@~syPV$d02CG$hUDkxZ^n*)osyDb%goFK4iR$knwlC3 zKxk;F{Qm0ID{=n(`Oat0o^`-1w!kcY_csWB1z`XF{rTbH;Rj=5V-s?6a-!nn=p z5&+ft=+Pr__Uu`EZ*T8kJv}{}w{G3qp!&x8=@$U@?%kV8JGa?vnX6WD~rJ{e+hXuE?>Spbn)WFwvdnz zL-9rfK>Y}c3pmN1J9qBTKYZTW+FAks(69P^eU1qLPCMTMWy@&i85tS>+4*P!dIEs@ z{mYjxX%?MrZEfv{79S&8oK}6lJbeZLc3wa`kBf_oU%h&@#?D6*&Km&KJP#i}l>PxA zRD&H`U=~fP&&<;_00#~nNQ3wO8OhAMP&^_rG12Sw%>ckf1_lNMLg>J?Yu6Yme}c38 z!mNJ?_F8J^51@P{1W8}9VudN?jn?h%?iROi-xj32QKMg3x^!vCx^?R!A|oS&s}Y4X%S6LO#<1Wc=F_l{EXez{0=#S zxP1AtIC}J`0P})i4)16NdHBLK0GK~`%9JSr4p7XUJ6D`IaYCFqb4G9n-L=lnPI2qj zEy2X+@#Dub(`SB0*tV` zThplDX4K*CJ%kBHd=~tpu<-tZY&de{h!hH`E(Oy}Q(Idr6~;M0{)TivckY}VM+Nyk zIXPJ%8x-yB?PBK4nZj({RZ(r5{e zT9Z$j4qD&=z@m}?T-~)%u{CSfNPE6;;R3z2Sh;eg+;y7Bk|j&HW1_ykUMfk&X3w52 zcbxN3asIJUIV3=0`t<2?PCZ63V?=ZCA2ZD~1F#s_ZyZHu%$Onl1DSCA_;IN;eZ{zO z;{@qXM~9?FOq(`MG&eU(rVz0C^XE$+KxarZz(GokA3xquHv&M1Y&gJ8hc5u=GQf2` z?)0KXi$rQ_sTbvoV8P7??`0LlrD zl!}gQBr~|{REWys+%LMix}>k5*QZlsT1Sg9f zr1r>0A3z^LM@Z$7N()sa89CP7cQOF71Rekgrpo{dJbChD`A0`aKqgI^q|t+vXRhFD zb231iE_yhzX%jGFfa|*S`p=&~mm$#g{aAkXl>w#!fD#%8@Tf`;?%L?knEdE9j(2)- zy>5@*y)gzrIt>6!Xp&I=VklFmIYs~;Ui2ErIK8-Dw@2@s40t0ZpaFmqlk(~5=`!Rg zHu$>Bqaoo0uxGR}qxG4N0+x1fsX?>Bv3F_`t=*Kf)M3;}Rba+uIO&(jz9qdCnhuna(K=RseWJMv^ zjSi40ufH18Xs~O8+4)WR04V1`HdlM{Xv3kFQLEnCWr%aTln%$LvW^ zagAn2>CBFjSgzTLwIv%5X2Q9C2nCRXIMO;$qRNIagD8*Lc(7rk%`^LBSmfcxD9yzs zhs+qgagOvQs0KT5=IBK&;Tx33-`}=vTdN0R>kctK(CZG@zTC5CPaJA@yV3I@!e1x~ z9w_v9Ml5g3;yh$w*Sp|n{=kW{1d6w4CGzf#&j6_9ocI3a`2HSC<){JZ<_T&%pPmB1 z!U=DMkT|u%q&DEzxXN`NUp|i+07?kl6lI}K|04<=iMSYzqCYTd?f~GuATCFH?%uuY zz^?B^-S7v5U|9n*n$z3&V-A2405?a4@Dt^T3Q?#DMyWcV>gUr40ESZdmcdJxF7<*& zhY(4278e&A-;}sc>g8v@0YEvhTVYeDPW=Q*l)@x$H{ues z-b~Md*q$c(88BhR}tZZ0000004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0009- zNkl*s>C} z$y&5XqD>!SLE;n<5fwzWX;;`ZQ}nT@pv>muz5DLzK1)#N4bIGqAn3vH-aGf4|8LHH z=iGY%{`D)=IWjBQc~8qVkDMK+3pVz>D>p5x5g2blrq`2WYbI6iP=2qb`+B|S4Gx7z zOmK|d;K+78FlQ+tg0xZ~5kCN#UJOrLUf@vpV+ATlJzc1s#q538!WXs6~=u^>0i%W8V(i{x0p`fH7# z;A(;BWlU>B#?=~y5f$USZs*bnN7~KI6LLlMr_5@a^{6vwom% zY(~Ztf=#`#1`YKA#6BS9OnscI`yJPGfHlAJy0h_$}KEF%>Z@ENU8$c8EIQ|bFxSw&z@7w zS>OOS0(Fk{1Kf%xk|6DrI^}4^>cG)4c}Xn<>c)72k;4X+U52J3EY*OxQlMF$F_@>p z6Rf`J_+~I&3&-1@gd7#BvHe}1U<4XMo_Q)_YL`+6oriPlYCikJW|?X$<(zlYi96g3 z0MktMGt}M?0LMlE;v$ZESJH^<325buunt=3}rQ!6@(drSu+5V6J bt26KucHlDr^nf!y00000NkvXXu0mjfpyjsg literal 762 zcmVPx%v`IukR5%f(R9#3@VHkej?`%^}*pLbmN=q9F)m4K1frC)DmE=tpRuElBsFhI= zSi~fmTi|WobP=H_(!nZRh)XKkXd99k!MA-n`HI^E}^s zzMq5ekLK@5mU@<8Mf$s#!o_GbMUu6e#ttLG9ssPBT$789uD=o48Gg0QQ>ynO!z0wM zNsa(9OA}17EJ|P8nxn=B4dDhLRueHp-B&orYl+8C9>GwXDcMCQY3!TyX$&6F=;gHZ zIAriZyt{JJxokm^?H6B{x!kUs^8#X2yif0o5BPpM1&U7Mb?e=LupWeX_IYNy{pmnm zUI8hRcTa-hw<}ODNl{%ldA2^$RXsttps~Ca-P1~Woi_5;p9Ca-PQ>4rT$v*#phd>W z`LLC5j-@Ir?DQ-Yo!q3mwHJYy5w?nm^A`yOe<*XoSn8|>__8TtY_@t-&jhj>fx^oW zPluvL-&|3^DgluF@on~FFlwAbWasIglrhGAD%rww8yk!zTLIZ10=fZsjJ~o{HVEKh z1a^j?$+>xOtZVIci>P}0bZEsEdK1I6qDO5I0BAiVl;;Ojopi9{s$xHbNoH` zT)MaB812O_dJyF(U_zwR7viUUABwH9AhLH*3vSzTmrkfbCD6vs(D61Tj#ocd^D4IA zPH1cWQKx`xq}%IdOuMX-oY)oth5={Mib<%>A9=Ifik;pTp|QQrq8huj(xqywVq1ig z<7z?0^p2+QbXFzRoQiD`Gn?t9EBaL}E?{wjFlpsCTjci1bzeAUcTnqn>i$g-pSURw s#XG95=BF3Q%Aa&o|GU*iT5?Li0Dk-3nMEad`2YX_07*qoM6N<$f*-?bL;wH) diff --git a/mix/qml/img/jumpintobackdisabled.png b/mix/qml/img/jumpintobackdisabled.png index a66b5ba418c85e97eded471ab75ea478b7ac50c4..d4d33a3a972e9839d9537b9bd43368db0f5c2504 100644 GIT binary patch literal 865 zcmV-n1D^beP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0008) zNklBbG|QjGI$fZ|@Sw|9AY`5ig!3x~s> zHaash)&=(a{UMjj6(Y1>2x;HIz(7k-*`Rf^U8Yj0?aaAB9yLNe-VUfP@XE@{QHrT2 zpU=MsJiXaQ^*(PI`*%^r1NpnCvy4h2u^_TqzcdUx8hvxFXmN$~?1B zSy$Jq)9Lh&U@-U=`&p{^Bvrh39pK>=DgwR5SR(>s!^6Y(S^-;Bizg>1PXK;I1UlE- zp$1r^vP&ozXk4|#ADioc_E(o?r5jaHyV}wKWYjVLn8dZ&FaFIGyDB10Rap z6F4-E~?);ckBuM9Ox!vd9#B^51T*#LGo zg*IO8YG#1dHA*lKkE5Px%U`a$lR5%f(ls#xuQ5460FNu-DQzQyjoRnfgT~u(ii?~>ojwqWL}pv9*0wc`Mxjuc4+H{tEX%qMZ(g{)UhiyhFCxWaF#`Ds*t_h2%h?$W z2HX99e`lfy0%vU7egp9&y94n#=Zkv1zEQ1Kdm=biB$vz0A@g;{ce(g2oFU{rP48ZP>X9Uip^DCD_=I7omIB?v>Bjtbl_{b zTwYT_M23UJ415q@rBZnq4u?0vTu>PEv`PIGjzbXd19~b!GC0BR;`@&85w6GB4tq}G z-Zd;Nz$E~$2!_~Mc1nNJ%wDMNKT8jZdbzjx{GP?trnB{kS@f+QoJS7NbP)%2UT z?oK=&U*}`G0m&RF8S~|F0wSg}QOXqYDt3))SWM~7L?TgBv8hfzx+{oXn~LwUGZtqup+=rc$Y`aWB#$uD}<-M@#}@Kd8-l#{aKhfWqnSxEbsc5D@h} z$jA6h5&TXqLU6$k;QB6e>a4vuE#lU|8y`Lsv-!JE76IMxRlv!WHW2BLit9|I3sOWc z5Z`ZpO!vHg^I3~X8>I^b-?D!~{>Awo-$gpJX_EG2le*MEzhDyS4_`d$7UT71Gynhq M07*qoM6N<$g6N7c(*OVf diff --git a/mix/qml/img/jumpintoforward.png b/mix/qml/img/jumpintoforward.png index b47f741ebeac7bff3878cdb1cfd45d7a35f088ae..eeedeada99e1d0a09680b616c1ef94140b8a07bd 100644 GIT binary patch literal 981 zcmV;`11kK9P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw000AE zNklUa)k(s{%jhE*d;P3C`>5U-6-i$LglIGPz07DfdnlC z6_Kq{hw#v~$PQv;vSQjF>|mWDq%wESBD65n*8MYYW||TA(DQBUzOCrc4<7U8H#6VQ zd%yRa-x~n_RjUm2VSnIV{_lQ1m`TugDZC!J&^?F<5S$Ki&L2=D`g%_nk7ru@tMNsG zwZ}-)*CFBnP_Ce{nGw!JYkY>c^#_XLzXGHiL+J)m{&*tt5g53FCTBMpvoj}XY`O;` zT&yq2Z*}HtcdA>)3sZBmX*0g@0x=<=KlouUMCc01bC)J(zYP+=_H||%`s~5;PvUL< zv=$R_n>h2gC!>=cu_Nk8wt8jri2CgztB`wZrM=TKR2*m00(g zq6nk3iE}Cd;Abm?;Q}j&l`ki-68!RJvV$e#1K6>�j+uD~OfPHh9;?q2*E#zHHk< zW!s4`0f2FD3bHZqTHk&7y*t%6x3<9E*5PvJQuh;oFkGhu1v3VW_;(;PeWU8DYUe3f z7StUiwCC!GNBPW#&5p(N5!Xu~hNTEQuI&j%sKH4m;@ptMrBFhhE_d-2>{xP=(fBk6 zVvW=sHS6ZEogznx?zk!IsK%Lb6+(DQX4n+uybHUQ9b+`{HEG0;^wbxJ%uv<04OWZ& z&7;Q=!8ag8I%ml_IgL1h+-6@GH4b$*czV@5E6WM21bxk;wHm=~^42B4G2oni=7QC9 z*Lj{<0aL!5!Ahv=TI4XscXShYE2 zwGvckFHK{0QfQ})fP6#PV^DlO)VOlO3i#jm*CX%)86QIBEoYEp00000NkvXXu0mjf D-CV)# literal 785 zcmV+s1Md8ZP)Px%%Sl8*R5%fxlwU{`K^({DH?t?*g;>->LZz2ULPQUOW(8eT-g#7pq(sq6&pqg+ z21Xz~7}>cO^%evX6=6LjQmgi2K~X&gSsCS>>q~zO#Hgdw+x_*MJ=gAPSI>S6`mKIupwZmP7H(Py968>Ho$4!yu^Yn+1oFOfHThvOdEwuMf5QNAu-zo(B3l zCXgX{r~rV|iXukpRQ>9nu6L{Q0l~beu~!6Zwrv-H#}L>FVBlehaRb@G!AQxQd7VS! z4`c1)QG3~kEJ;q2=k(?}TKoDjjHhgwW_AJN9hpy=F-mN)0BAO8E<i5Sb9Vq&EV> zZ2*=#W5gNy#|~?el76XM5MqI1;|)}cJJxSN0h&Py4Qv=VRVsJPvPB_M6;vnc1!uj~ zM3Wiy1I_+HD|@N0aF4z}9M$(NH7{@dqRXl6`M6Huo-=ekR8c{us5TFh(_@#1J9nq; zuPg`&_Qbc+Hb17q7TF2X)6NWQ&z|pPcbg2^cRaCjK$;NZ+TQ>fr!5bJYpPGmwlr5r zAo_ka$tyE5hc}0i9d(6xO>fQ;>;&5*;{3QPgl@MuGWO5iVMEBvJH|3s2#pd0TjzAS z4%s&&J$v2`E(Bp(bIA?Uz~cn_EE6P^o+l=xcMi2}{Axq;_VT>AUDm$=DK6`W{LdiG P00000NkvXXu0mjfrG{*3 diff --git a/mix/qml/img/jumpintoforwarddisabled.png b/mix/qml/img/jumpintoforwarddisabled.png index 07364cdde3580db0278b6e609329f8f5ff9bc616..933fcf333b9b532d7788babc4494af1b0e487d88 100644 GIT binary patch literal 915 zcmV;E18n?>P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0009X zNkl*?>?Wsm_d)nQ*F1~Zx0R*YN=FeCY?^-O(v6%y1KeP75lc(x~0&f ztVJS`UFGHFPs+;5cJQohUtC;#$02$vDk_FrT3QmtY~)+F=2PbC=I7^Uxn%>OeThUO z7>~y%Z8qC(puNbqhKGl}x%-XIi{4l@l*wc)(P;Dpx9@Sg-L)KKn)%5CYis)mxS8jz%jG)l^?IAKYewFt z!D76-yZb${zs!@t1D8m|DkD(YQxaGVkZ5<7mzSrUPG=3--yk|8!!$S+i){s9X>D!Q ziTfC}F1*Gpl$blHeNR?a-=@F=0|WIAhvO;l3t|vAPf=PL2iPkzP&+Y?puf)ncZyCO zMLU=Jfyk6p4Uk%Hc^$ZpJVu<8=)5B%BTf>o2e*d^!FNJY%_kpJJ2q8eM4p(Kc;oZ= zW-)pU*l})_v|6q8d~2b!_7Ly$wAHUmOG{_l+uI-Kv$^R8l53>Dzdu0ph@o?E zOosuEli5|kq=9J6HR^W`*$4dfMsVZ4Q7nv(j@sl0Ay7clR3xJ{YFFUf@WMsqlXaqL z@WR4^n;Y&Yi`N+xVYQ|YN$dP&aaCa&OmEI$L*K|S9?SRyeVHz9?h2j{0C^1!s z{Ha*G=lA=6wlj4DvS~1G#&+f^F`eOupb1PKnWLK~?$`40)>I{BwOFBFZ>N6c_jrWE pq)4zy-qBz%_<4=;fATjy@B>UFQn7_5OH2R&002ovPDHLkV1lJmsLucZ literal 695 zcmV;o0!aOdP)Px%aY;l$R5%fxl}%_9Q4q)7j}Q?eNIY2Sp-{wvcu}$7#pckPwF*W>Z{G544ptC^ z;GvLuNXaL7>OnoI2TMf|k3~UGinSEPkDCMuf}(caeE6H1C)=>QO?>cn=FR-)|7PCo z+tqTp-1cxdJk)43KBKR1`;VcO%jE-xVXSmx*E*ffVyo3!NTpJ1{qpJUc6*(`j|4~- zW16O2HBED+R;%4&gK$4YngT_mQ6mzG9E0Q{woA+aO zWbz84{h?53rZ-rvUCU8Uk(73nOkSY=q^uFhzc~G(duF151ieIm%-q4Na7x*o(vzf6 zC=4keB|Q+GvZjDlut+y<05-|wCbP+USdiG}z+6GKDRI>EV9DYa>=;Gdg`hX%-;{VJkw`2F&h<>hA%k7+v)egTd&9tkwZ#QJtq8>Kn~4hKB2IG+ z?m^JOHXVz_o+#fyk~2C1+2lY$gMhazhxcGFrOZJ(K{W<)*|MyeY&QEzZRAVRC3p>Z zw+avm**9+aA-V0c_U%qLgG~eyM9X(_Dd$C(;Y)&lLO>ovzBe0{_>y$bz?B1^&fj5c z5~7z~86*Wwdk#rk{Jxn;7vvCoiLm|R19e&1eMzK^(gnbenBNKhfqaVX2%T9~Bz;R# dmosqP^baBP`E5I{;XD8U002ovPDHLkV1oT|MsWZD diff --git a/mix/qml/img/jumpoutback.png b/mix/qml/img/jumpoutback.png index d619ff082e726a12928f902b30da09c4fe3b3f82..a1c4c0a40c30558613a67b2e4d87eefe83f14832 100644 GIT binary patch literal 860 zcmV-i1Ec(jP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0008# zNklTvSGVfH5 zJq&v-*6d1+sFMJpiFBf7aGZ)%e(zhhWD&YWtHYxOmp|)aTJ`c~!DOl)vshANcgGh8 zU{V*BZB>!b>Q6vft$qLaSF^(DcrX#+{QY@*L|X5`lI;T1Q~-3H-(Y}0X90pfjnQEi zrb9!w3a1nGo2ez-x3jl&5zL?93HK$8bEaUF>nWodNzFad#v79aG z802j8dnZ$zk44#bj)c~~1H!KA5?w$#E(Q>KIQ^oiI4}vVyrE359cXa*VkA<&CN(y? zjIR-p;|Vu#li@m#sa^Al|Ps&k&w_L+OkiO(CRd$_{=~_YP)Px%c1c7*R5%fplS^n*Q4oe_PHxgBwmz^{tB?euXjK$ni`p)tZJHEOS1tv0CAf;M z_*iA5SWTLRx=;{xA?^epq_OrTN`*cIkx*OOBzED-Xj9YPG>?0nquda0ZwQ&qJv0Bz zcjlbA2SCS;_DpT*2*%IpNM%Dzo8b<|8>*Rk2$4N>2fv-x>gD|ZfX-X7O$Nk4D%!?5 z|FoEf*X00Oy#Q>#JyUNsu>kFI&GuX88!U5v5%Y8LN%q=I*bxqM)zSKC(3byNT{IL}#kw%=pR~jIGte zgkR`T729skT8&i_b&7U{!`ZOc`dHNt_{J^uYc{+mZ9g4V;kH`TiXL`N%r@Fx6co3SEcH7 z9Sd?U?N}kG33^{-=+T3TTm)QgHkeu}0@8%n>20LOko1ax9AQ)~*8ApxjaCHgO+I=~ z)BUIiqxh3I7j2P>fZ+2f8F}eA9sL1KIqEP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00089 zNkl&&PK^UlgxOoCetL-Nt@ZY$-wa5+~2wP-22`z%=DQu zFlAuMfJO$`aenc5{HWP%KEw0;^Jp|Gj*8jYKoOlB<>i_Hw!Y1+!bZnwKusZ>@l zOiw{IgDQDccn#|uXkV_?YLAf^T5r39B+AKTa$XZ+&q=1bA0&}T95xsX4*_r$fS)11 zh~fH5`dltIk7Vvyt=4lGx*ynI2m}J}`o5E_3Se?ZzmFj3BLG|i_!qFS7!HR&kdBTT zSa^We+=gxo^RSFo{6um*>|S zkxHdb4%({i4QdLKd%a#B%aais7Bg@cNjcGizbXtJLwm@MVO@oAX~akIsamnZvM0dL z!h*_9;c`)!^kfUL;S|ad!NkBWmrF#20>DQ?F+@9EJOUK^{>df=_INyWqiuk01u)3~ z{0bHS>w&^zS1>U!ToGGZ!_d8_i-y4Hr9H{e=li?i)ptt1)NO|}IL|Yf<_MBF+f$S= k?Ma-5ogu^N$Ny&F4`i|uDVR$^%K!iX07*qoM6N<$g6n8wH2?qr literal 634 zcmV-=0)_pFP)Px%G)Y83R5%fxl*wz;Q4q)T`(-1xhDwUjDk8Wd>Ou720#>ki(w=(spvSBx2g%J` zV?ts!f`@|tf(s%@)lw*eC=^klhf+Lva>3Y;glvAMwdwOU(!_zuo9}n#ec!x!Ni3Eg zmQJVlluD(WJyKgzre2ZBWOln;u9xuBh+fz8TVb18P%IXAnWp&y?hyX2)9E}>^Zmr# z4(VnmVl!+yiZ4{F)d`=^_oE*XwPsZ?l}e4$jffq?-&ZP?%h71`yIR<9Y!nIwk6hC* zjFajn4p@Zy1ox=bYCQ}D0^ij9zhbl5Y|0$%dI4gG;U@8E4qRp=caq8EkY1-_LkM{c z1YY4s=vr-M)d?gY{fI9^dBmdS8Q2;42)m!a7&4*KbE6k!4~_ zw?hG9;c)nKtyYsx1FD$hJRZ*o{9cK%VQwO`pK>~#3%OkGfRKOvQiKrub6Rl?ZG75n zw!5Gm8_ZgSsM~J0-veFU)S+Ii;c*SC@FKt%NRaDVRRuLBXENi#1QD21MbwyU&m-6# zs6%;8Iw`9{62ny+jm9mB2NIOW;=6i^ee$>V3!w_@bGXx?Q0OD^{~OnnnQdz5H}@0N UE7yHWtN;K207*qoM6N<$g1NyjCIA2c diff --git a/mix/qml/img/jumpoutforward.png b/mix/qml/img/jumpoutforward.png index 29745f75619eeedc0b94a1a490af53e115235843..10c58c53a9af65ba85acd101b2722cb8db923993 100644 GIT binary patch literal 866 zcmV-o1D*VdP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0008* zNklF|7{K43nb}!)+%++Yz+D##B!k2V3@<|d%P8_-MVCMlya=h8c?hgi zP`OzN5gob()}f5jRSBV#4jsC9h!R&M`a_hq>+Cr5=Dpq|WA3i|kAyD!V0iPs?|a|x z`@Z+)8vt@6SAkpwauxXB6{sIv*xwik9n3Tin5khZyZYN9KQ_?}L;@m)-aOu2I+M!Y z(xG$)ndoIz`_3~M7bLk@6of~$H$GIQ+qWg)k>0YfYbo5OYvBi2a_*F*yy3>1a|cqv zw*+hhsKe+b+R9Um9VHk#9ybI+m9{Q^{--mpy*lSb4qPiBdX7mS(mzD zV4)nN{4q(+zXTZDW<eZ z`fDHeVvL@PPPf-sS)SIZd496n|Hd|I3M||eWY-B|tbS%@^yFywu63PlW6v3%@zLw= ziwJfG#XNVVuKpU1XsrEppYNyTsHT5bak`ZO(V5?78roMvNK3HG`^tuFHfNM^)6o15 zLx(*QhZ^eg%dj3jJKa|nwjH`WN-=}*IMJg&sIH$1_V`mmt$isot_#dp2moJ!5L5$* z3L!-Nrs^G|U8Q$ys68LPHDAS6fjrjZpR#4C=A_`d!NuJofD?i!`*`{IWuZJwWJS6} zsM!+i^i8I6oKBbYRtuDNU`h57U0s7(o;VzdQUR~P#hQMW(J>_pASsw{sAk0aG-C%f zbe=WbSKtXLv6}2w$-xk)fTxx))?^xWD`tW&3qevarR)j(({y6tSd@9`+2lxTQ6vja zf@xB4#Bkjsn);0YZTPu501_O)>PWmx@xDth^J@HUjR|hk3u4oWv#%NYrZ{x<41(wg szgZFka7xq7`%@SEU*b%2%d{2v4c5v8XM%*=*8l(j07*qoM6N<$g5OPt%>V!Z literal 674 zcmV;T0$u%yP)Px%TuDShR5%fxlS^n5K^Vusnca=M+D9Zs6rruvMnyce1z%uNYg-HIK|F~U4=Sh! z+u-Atlc;UolSdIx9t1%xeORqMR0}?-R5Z}o1d56Z8k%m*YsPQVZdo>)#W;tZng4&j z-#or=0sf;M&|@cBZ$#ERg;FQcP3zF(#|fdgRH{Ae&|~ZDYs&^M{DA?^`C9}vN`#CB zuFtNuLdynDT(0}Ycyd2*m;xYMG!K2+-aE6#gc5U5ZXf82)M%16MhI-j*l8n|3XX?1 z|NLj*zAGPn9!)z;fE?mLwj#)HJp>1MpD`9%Wvl2kZttC1MP+Y@5E8=OE5sV7QxMJ- z;45S&Z<*Vs#~T!YhX~syM9yJ^b9N6Xo5&=yNwq?KfcPd%QY4jSf$<9)zLf-a^+)|c zmFIYz8e~o9^6b>(p86L8+;%lut*FW<2DjiQGr0`x9lcolMR<-`4(PL9PL)Rj#(@tS zzvp+Fu-(@_RU&Ly!0^bQA(IZ8FacbC!_K~F3zg(^__*SFRru(eM7@1a{5bk1+-!)& zqE&iU9zoa+^kUg`F8Jh9WjC>S8E33{sHgs2kyk>Xn&jEz2onJWD50dYM69Ds35V5=&XS04 z>UHz&9?b)NX%}ttSGKw9l#X=QeZY)~gcLQ@Cx;TZ?-v;^LZJ>*33eK<){ixpURs;S zgxt-fjDrvkGne=xt57zk+H~@@;`949&eN~)$?jb#Q!l6g3v3(A&!)GqNdN!<07*qo IM6N<$g72j_X#fBK diff --git a/mix/qml/img/jumpoutforwarddisabled.png b/mix/qml/img/jumpoutforwarddisabled.png index c7243c859d0eba1ccc50a1b9c2f6c3a57c3458a5..f1104b4a8cb1901a4342d1ffb7f46abc3b01f330 100644 GIT binary patch literal 773 zcmV+g1N!`lP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0007z zNkl2Io1oyM8xaF86gSm^3qg=P35XzF7~KQ} zH+hn{=-Mb+L{l&n#DWTL{SOQU@qtR-Prs4e+U8!pNwaX13x}CGGxPiAoH=(SY4S}n zFv-9q1OF=nsZ?qnJ25I>9(BX^^#J!942EYWlW8>`k1uSW)9a4~u2!qx0KBwVEYnu2 z^&#++dO&5~sC0JI7K_D}$Kxpgbz=)ef7a{uzAY3AANBOcinuQ>6Zvwp*?dIGXRv%S znLMfoHs~$TnolGW`(#-@jh*TBdWVSg0P95dT!5u+x4YSHx6k|i{`Xq@h0pZ22`zs% zn{@#SGk4u)v(3<#YPDJ$a2Z&SRuVq?X251G4aGNfs)=$A!8L$)*z5-QnDj2;n>QMb za{ymZWCHxD)oNV~hr@3ah*mpP!~$wIo1fe5_F3-p9pX2AKHr8Sm`3rre zi=j|xYff1+*y@5~vDh9WTIoZdB7Q9p2z(Vnq~5{!9#B6~e!(sUgTYsW5Uue)!8{Od z?k(hSIF3~+m5oNDaWxW&d{>0(_4-~iae@2%0rWBlT36=uTFt7?WHN`@co#c`O%t(% z@C~Z;{-9tkm-CR`sZpRpLj~qO4-!R@LYW07DpV5H%J-B0B6qtc2IGFJswO(0fRfhV zPyrCX2#1-Xdn=#MTgHWo{VFh!;}ncaTSQOfN6O{0OEtL*hYHMVRPCpBhg{!RC*A5( z?N~Y7Km|s4RX_&eq*|nWy;Le~RrPQP?NutU)9GB{exC@CF!A<^7YW}7z_+8(XjfZm zG_R_v#dh&9@QYjld=8i$*K7XO2Rsg&qsdQJ|H;5FU7j0Z%Qm;000000NkvXXu0mjf DS4LLM literal 580 zcmV-K0=xZ*P)P000;W1^@s654Bdt00001b5ch_0Itp) z=>Px${z*hZR7ef&lS?Z^VHn5F8I!3wBA2496tR$nFQBa57B0zBX|6@sh)6c3OwD!S z0}v%5HQCIDvQgqAC}v}2fw}p;Iw$AMInEiErMI5*yzg`Q|KI0%-cwcezmyKdVzHiN zGC5+^5Qml1&X-6eS|mxjC9bYiDvkSmz9X|7$;?=(&F}X=0=`4M%i(bBLpo@d`>RS+ zK-#qh$s*^sLZL7k2n5blpU{6oB7jn<)HZ64%3dKH_IkZ(VHfL1B=LB>(dl#!lRpG# zH=vy#XrG@KDjK4qb789fwA=5(;jl-R)zZ9>ifnSkI~B#XtsS5T`+0hz*gh}JFJcDdc|4P~&`*=%-9OTYzM zA)NlUr*;}RXrU{B}J91J81 z!3{ADnmDn2%H?vsp-||)%x-%$v`eX=oIn6IC_Y=z@&E$~0sZAcnzNNp6Q004R>004l5008;`004mK004C`008P>0026e000+ooVrmw000A~ zNkl>hv0_>hs5Na6d})0y3KcBKgw}!} z4p^n3>ZbTq1d9*)(7cFENt;A5DyXzRNC_&XO|tkPMoqKX-I<-abFb%4*s!KagEk7@!-4p_lU4|YUw|J$;tj`g7&<1qdlFnk5YhRBGtB8D+SVD)<{?Ztuc<; zBAEfDBt(Hfr?kqo3j2f6mo^m}ks2KH0w@YSJdu7v6P7XWPYvJf$)uB$cB<_StY~9c zE{sWU`IwU7;|#(s8Sw{YRC!XCZ#ydRrU>Y)m1sR%3jNCi!?(Ijjz$(&d@z^)5{dUn zS>7RK)GoMvfs4e(z$;8L(65g<*>CD5a$P!b-;sU_^pr?scFRgJue{*7@sr!Wts8?t zTrq$K6-m&6+RX_&Pnkf{<&oc(7M{H;smbiR>hjB5KZ~NmVBi-%Vs@&NB>0E>PT%Zo zOiau`;g7;;ChSh>m);+DI)}b@d&+kUuEnklb^qyQ4k_?lXF zM;Lg|Tye6OOx#*qnd*`JSJX=NDj9%Q;UX6QD-IPyXM;;lWWNju0gJr?g!bYJTMyrb zfjl#DB0IY_>A~FG5VO*+$)NP+xRZT*EpFbqxoNGJR1__0B~foefshWIbwp4pttx@0 z+o{dYGAp%9N1+J-Dy+vel>7JP<_D*ot+z~`s!5qR7r^2tQ%fJuRrl6DV`5*^qs%L& zIEYxzxZiQH8Y(oB3C0|5C3ne6X*FKq0dSBW7Jlg@ZoY^Y9(u(lPCQ^7|8|%vR(-}& zS6}Kq4~*o0U`*^VWVJ>pH?5gXE80Cew8g8%8m;S2T{X~kwb9%3`yWhWnb`6FVCx{p zY1Z&L<<=eP8MjTpr$?O*{|>OhMnhr~9~E^@R?0u)qym0i;tK~2Wa!U_fgZ-9SNq$5 zZxvp*O#9EwZR3`B6~D{9X7o|wYf)G{HF3P_r`2rta?$6`v>b46#D6CDlIQ=I`!56S VZq_VXR0RM4002ovPDHLkV1j$k?JocT literal 692 zcmV;l0!#ggP)Px%Zb?KzR5%fhQ%z_SQ4pTl-NYn{ib&ClCLxGc(1Qo7o`RO7Er@s#L~`&TC|A;QP>^hdV)fwPK?N@&q%A3}E%g#Tn3yJSoL9{@rn^ZVVK?vl z=KH?4v$F_ou5e;X17Bdf7u1afZT{O^<9M+hDK;zWyPH3N3Z4UmQ-pAci>-PhS_H%_ zRYf{`HDIz2*?D1qD!<6O9ly%eoiDEkmt;}oUT(Lhxb851o-GxL5kZBo-#MYkVVwx* zk+@tO_7O-JrV)Jg7g@Wmir2OPy`!^XRds*j)5QpBg-F~NRq9#(vg|W;e`iMbhs*)L zPe5fqJKtdK93mbDMV;zP2=np zByY7y1sszkKlURgf?Q-HJ-bMfvni;6#cT>J~08z#%fameE z8Q(ka#7n$o0Dlu{o|wn$Oo$4C#D#Tu1JLp%*XpCA`Iv%uhUdHk2|kpdH2lKYw@~Aq a?tcIkT004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0009m zNkl|`VE3kqJ+O*JWla01W3@dEjuRdq!4tLaPriGiB3zz#l=XcKep6~aZ zQAH^|B?U?floTi_P^1F7BI7b)Ua!{_3*XzwRq$HC`g}l%BhH2s! z`M(N*%Dw(iP_x-=-Ve|Qu{|D7b6Hv0BywKDtO|uf4|pBXXmlSS4S?(f@BmDm_?{56 zohIBg^LT7*tU+oNdQ`^G0X`Uy#~bOoh5~-GwKqZk#wBqx@Tv*;%SXemmH&7`6aEh3xGrEAnM@mDe$#HZcaoH|X!(k$exJ{0p@F+Lo9)>0^76gK#l@4- zn0l}MW`SWTTdM#%O#?@0S{Xy(c+2Az} z8L8Ls=eS_?4w)NKCC3kY8O{Lf&# zGFM^73Og|6bUGueE(Fj(9;AO9imWjXLJ79et zkT$XuDKuK)l5 literal 532 zcmV+v0_**WP)Px$&PhZ;R5%f(lf6rVQ543#hLlS~5JaSnjnNhqAv8s8HI!R5gdZ3!1}!<%kU@p$ z>lDH-&U2o7y|1wJXrWMOU>GZx z%c4*yypor@jfzeU(P(tuYPBxYvm}IYn0j@?Fdo5fz^*(V&x5I^LJ^P04VlrP7HOI` z4Rp-#tm?E_zKP!<1s0>keWuzq_^#LMeKKJdt2vQzEEd~l_*N1#Aj$SCmC6*$?f5tZ z&U8B64>m*X4F6z~;^%k~ccU`JZ_kG6Jr*1?P}FsO&hPi%DRQ=cQM7a1b<|$;%xY@n3USG6ZoDwTqPK;WfuhU-}X zOCeP2N)Cww;w%G04McfrldTpYW)S>Cz3qlUm2!^>k~Ia?2T4xmu7_%wy7L;;6uFv^ z8qlfM{1MgW{vY+CJkw!Kr&@RA@>M{dZ?QoBp|aN2x+<5iLB0wYlK5NIlkHxLdD9P} Wy3&HYaT^%`0000004R>004l5008;`004mK004C`008P>0026e000+ooVrmw000Ao zNklSk13urN*Du2Cf zp`ROLR`c}jhkW2?9y|Q=pwrYqvefH(2ncLTGFoQ5t8is2hovcy#GeRy`nk!>gLb}92_}TOtX~#ii~PU0BvDS#B9hARv3vPiI7xVz%ctU5+Y;Wfbn9+Qq~ zN{&zGH_kQg6X4NzXV<4p>VVB+hx3gdE1ff8?WpEaMUk$r&;##AR5KKavbZ~qQs8a^ zNZVeCrwM#Izwx-u`U_vz{z$~t&C$Z#1_XZ6c4@zDocbJLsjU+6VQScmw(IUdz%11J z&vI=08!i9T%GMfTF{#%CwwahIfS-~Px%heTnKKwELP+-iDY7*uzJydnLL=hV%m_jK-^-(`4rmwgXA=l;&` z{LcBl@9aZZ-NKgZU#qdou_l|({u++dXI7U6fOf>t&G9W%;W{ai)Ims12v}iqiKf|q zO+e44(sP4Jr7>^DRydXdA!XbHUik`_zECVmL@6fEa{eYjTq|@Kp9G+5@gCnpfwjie zI}&0SkapH7K-~uVCj2P7p0n#G&H|#xON5Vp&!parDZAzc_i*pTR;TP}M@c$|h&%Wo z9<;^O;Cx!^eyh~w1W&i-4g#@nO)iv%7+TL=eFTlV;un3NipdsVQKVK+=V=Myma!{> zcWOElsPVdQiyasRT5f#aC|6dEayLFAc$!M5P8D}-5ncfVqiQ1y#u1^0o4e1u|04=W zI+w)<3gR>}mCl^_A8|eZRk$`ui;L|nJj*&~Sk$NE`jUdN$(_8t4(@zzfpW*}CSrf| zedVF(m(7JV>+j3U+Y)?fm-Gk$?iLIuS8G6^6j#4D6yE+r1ccSc6=ivVlY)E%&bEH_ zCm+LAo|?Pnv004R>004l5008;`004mK004C`008P>0026e000+ooVrmw0009B zNkl55Rrn-`{g(44Y^I)#6>rf11EFNoSFG&{+T3- z(p*gjnhZ1j)=l&p*$wVe5CSn4De;2-wipAoZ*X#9&PL|=1sQnoZ zhmRHtg=Yi~W6_n(W>>bhwypy@1W-4@y7T#bKY)Icd5ldv)Zez*Y%fEh(11k6wzZ|D zeh0{{cs%|B+KQUybAh&OQu$@7T_^F6 z+*f@*-xMNcywTS;*v>$460lbQS?FttHpy4#0K=(3xtQwMtpaA`?^E>?Xs)6c z{Sgv-O8r`nZXMPCGIKPLs<4D~zRV(N|#9}d5y~)=cb-ZiJ zT5@A!Lz3Lh-sp5XjkSDh>2?dGv!{|Qij}{EqI(k^RImKYpGCvKf<%vJncQ`HDns>q z%UN_x_N*?OI+uofti|E$bPTYY459X0{FY(6J3c=CNwe8g$sb6o>^%kfuY&&qfSy!{ TTZ72K00000NkvXXu0mjfdt{S! literal 0 HcmV?d00001 diff --git a/mix/qml/img/opentriangleindicator@2x.png b/mix/qml/img/opentriangleindicator@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fd948d73b76a58fa6c48af563742943064805193 GIT binary patch literal 836 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw1|+Ti+$;i8jKx9jP7LeL$-HD>VEX6j;uw;_ z`ZnCQLpV_2o~>eT*6TkaNtwyXg-SE#T$`sT7kL=)w7e&2g@rpEaG?3>%OC2VFerZq?= zuwkbf|93M6o8Bqf`G?Kyd&pap*ZbFA&8ki`*mg+cq}An@U+k_;)A@b8_;kN!h{P$* z?YG~aOxk#(^?RfS%U&aWmJt zB7X04zF$7OuPIlFoON0G%iCOrDy;>lRCO)CU$Fk2P^oe0Gc#@7 zpM^JGtFZsLQOQ|llEJC$J`SxN=ak)ray<5F+l6iTCe`aAq;|g|dETS44Q%S19~=7x zPlvyen|4w6^sg`t5k03e*J?Y~c>M8)Vw}$1(DREK7n&Sdu4 zDv{fzW>G?F26N8G7udzSU7CKaF@MtHDfb^+|NN*nSL3{pex@bIoSE$rmv2Xx&iS=% zRaxV&DB)u>EA8f=*S?`^wcMHalB)D3-qZyvmaJXkD)ZvGyu~Upjkm9z#0u)0_SK3n z5dK*>=f1P(g|$H|zi@iy=Nlb*S9h%Z6YqLp>9lqTkFw?4dabGM6n$;CM-k9NMR zer4^$$;;Lp|KrP_&X)eDwbwSjQ@Lqxe1OM*`3wUJqml/StateDialog.qml qml/StateList.qml qml/StateListModel.qml + qml/img/dappProjectIcon.png qml/img/jumpintoback.png qml/img/jumpintoforward.png qml/img/jumpoutback.png qml/img/jumpoutforward.png qml/img/jumpoverback.png qml/img/jumpoverforward.png + qml/img/jumpoverforwarddisabled.png qml/StepActionImage.qml qml/img/jumpintobackdisabled.png qml/img/jumpintoforwarddisabled.png From 09d1fad5dcc9bee7b4347a49ca980b1634d98e12 Mon Sep 17 00:00:00 2001 From: Alexandre Van de Sande Date: Thu, 19 Feb 2015 12:18:38 +0100 Subject: [PATCH 20/59] Smaller font on the editor --- mix/qml/html/cm/codemirror.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/html/cm/codemirror.css b/mix/qml/html/cm/codemirror.css index b5f69e6aa..f08bacc89 100644 --- a/mix/qml/html/cm/codemirror.css +++ b/mix/qml/html/cm/codemirror.css @@ -5,7 +5,7 @@ font-family: monospace; border: 1px solid black; height: 100%; - font-size:16px + font-size:12px } /* PADDING */ From 952350bec1207050e1d9477ebae8c7bbd519cebe Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 19 Feb 2015 17:43:53 +0100 Subject: [PATCH 21/59] Bugfix for functions override - Functions with byte array type parameters can now be safely overriden. Parameter location is now set at the right place. - Also made a test for the fix --- libsolidity/AST.cpp | 19 ++++--------------- libsolidity/AST.h | 2 +- libsolidity/NameAndTypeResolver.cpp | 8 +++++++- test/SolidityNameAndTypeResolution.cpp | 13 +++++++++++++ 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index c6d8f5c58..761427db4 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -274,15 +274,6 @@ TypePointer FunctionDefinition::getType(ContractDefinition const*) const void FunctionDefinition::checkTypeRequirements() { - // change all byte arrays parameters to point to calldata - if (getVisibility() == Visibility::External) - for (ASTPointer const& var: getParameters()) - { - auto const& type = var->getType(); - solAssert(!!type, ""); - if (auto const* byteArrayType = dynamic_cast(type.get())) - var->setType(byteArrayType->copyForLocation(ByteArrayType::Location::CallData)); - } for (ASTPointer const& var: getParameters() + getReturnParameters()) if (!var->getType()->canLiveOutsideStorage()) BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); @@ -299,16 +290,14 @@ string FunctionDefinition::getCanonicalSignature() const bool VariableDeclaration::isLValue() const { - if (auto const* function = dynamic_cast(getScope())) - if (function->getVisibility() == Declaration::Visibility::External && isFunctionParameter()) - return false; - return true; + // External function parameters are Read-Only + return !isExternalFunctionParameter(); } -bool VariableDeclaration::isFunctionParameter() const +bool VariableDeclaration::isExternalFunctionParameter() const { auto const* function = dynamic_cast(getScope()); - if (!function) + if (!function || function->getVisibility() != Declaration::Visibility::External) return false; for (auto const& variable: function->getParameters()) if (variable.get() == this) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 62855bc7a..64dac594d 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -448,7 +448,7 @@ public: virtual bool isLValue() const override; bool isLocalVariable() const { return !!dynamic_cast(getScope()); } - bool isFunctionParameter() const; + bool isExternalFunctionParameter() const; bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index ea70b65b4..e19b0bf9e 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -333,7 +333,13 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) // or mapping if (_variable.getTypeName()) { - _variable.setType(_variable.getTypeName()->toType()); + TypePointer type = _variable.getTypeName()->toType(); + // All byte array parameter types should point to call data + if (_variable.isExternalFunctionParameter()) + if (auto const* byteArrayType = dynamic_cast(type.get())) + type = byteArrayType->copyForLocation(ByteArrayType::Location::CallData); + _variable.setType(type); + if (!_variable.getType()) BOOST_THROW_EXCEPTION(_variable.getTypeName()->createTypeError("Invalid type name")); } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index bfef873c4..da6c2a88a 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1163,6 +1163,19 @@ BOOST_AUTO_TEST_CASE(external_argument_delete) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type) +{ + char const* sourceCode = R"( + contract Vehicle { + function f(bytes _a) external returns (uint256 r) {r = 1;} + } + contract Bike is Vehicle { + function f(bytes _a) external returns (uint256 r) {r = 42;} + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(sourceCode)); +} + BOOST_AUTO_TEST_SUITE_END() } From 275bdcb74b890c2b2ed8d32229627db06877bdca Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 19 Feb 2015 17:56:42 +0100 Subject: [PATCH 22/59] Fix gas limit. Disable whisper test until alex fixes networking. --- libevm/VM.cpp | 2 +- test/whisperTopic.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 9274628fb..d60f585a5 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -529,7 +529,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) m_stack.push_back(_ext.currentBlock.difficulty); break; case Instruction::GASLIMIT: - m_stack.push_back(1000000); + m_stack.push_back(_ext.currentBlock.gasLimit); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/test/whisperTopic.cpp b/test/whisperTopic.cpp index be93174ec..4609c957d 100644 --- a/test/whisperTopic.cpp +++ b/test/whisperTopic.cpp @@ -30,6 +30,7 @@ using namespace dev::shh; BOOST_AUTO_TEST_SUITE(whisper) +#if ALEX_HASH_FIXED_NETWORKING BOOST_AUTO_TEST_CASE(topic) { cnote << "Testing Whisper..."; @@ -293,5 +294,6 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) BOOST_REQUIRE_EQUAL(result, 1); } +#endif BOOST_AUTO_TEST_SUITE_END() From 2657276cc898409f11336f2a270aee5d9426bbbb Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 20 Feb 2015 12:37:58 +0100 Subject: [PATCH 23/59] fixed web preview --- mix/qml/html/WebContainer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/qml/html/WebContainer.html b/mix/qml/html/WebContainer.html index 26cac5103..e2f97fd86 100644 --- a/mix/qml/html/WebContainer.html +++ b/mix/qml/html/WebContainer.html @@ -17,7 +17,7 @@ reloadPage = function() { updateContracts = function(contracts) { if (window.web3) { - window.web3.provider.polls = []; + window.web3.reset(); window.contracts = {}; for (var c in contracts) { var contract = window.web3.eth.contract(contracts[c].address, contracts[c].interface); From bcb888985343e0a90a1038cbb65ddb1c0951ed64 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 13:04:39 +0100 Subject: [PATCH 24/59] Protocol bump. --- libethcore/CommonEth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index e07eb04ba..2264e6ec9 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -32,7 +32,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 53; +const unsigned c_protocolVersion = 54; const unsigned c_databaseVersion = 5; vector> const& units() From 4ffa45b83fcd116f5feca4945124a1038ad8ff05 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 20 Jan 2015 11:56:06 -0800 Subject: [PATCH 25/59] Genesis info. --- libethereum/BlockChain.cpp | 3 +++ libethereum/CanonBlockChain.cpp | 25 +++++++++++----------- libethereum/GenesisInfo.cpp | 37 +++++++++++++++++++++++++++++++++ libethereum/GenesisInfo.h | 32 ++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 libethereum/GenesisInfo.cpp create mode 100644 libethereum/GenesisInfo.h diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 11ab08ce6..29095076f 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -22,6 +22,7 @@ #include "BlockChain.h" #include +#include #include #include #include @@ -29,11 +30,13 @@ #include #include #include +#include "GenesisInfo.h" #include "State.h" #include "Defaults.h" using namespace std; using namespace dev; using namespace dev::eth; +namespace js = json_spirit; #define ETH_CATCH 1 diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index fc7107154..0e468970c 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -21,6 +21,7 @@ #include "CanonBlockChain.h" +#include #include #include #include @@ -29,11 +30,13 @@ #include #include #include +#include "GenesisInfo.h" #include "State.h" #include "Defaults.h" using namespace std; using namespace dev; using namespace dev::eth; +namespace js = json_spirit; #define ETH_CATCH 1 @@ -42,18 +45,16 @@ std::map const& dev::eth::genesisState() static std::map s_ret; if (s_ret.empty()) { - // Initialise. - for (auto i: vector({ - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "e4157b34ea9615cfbde6b4fda419828124b70c78" - })) - s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation); + js::mValue val; + json_spirit::read_string(c_genesisInfo, val); + for (auto account: val.get_obj()) + if (account.second.get_obj()["code"].get_str().size()) + { + s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::ContractConception); + s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str())); + } + else + s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::NormalCreation); } return s_ret; } diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp new file mode 100644 index 000000000..5b5a4ba5d --- /dev/null +++ b/libethereum/GenesisInfo.cpp @@ -0,0 +1,37 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file GenesisInfo.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "GenesisInfo.h" + +std::string const dev::eth::c_genesisInfo = +R"ETHEREUM( +{ + "51ba59315b3a95761d0863b05ccc7a7f54703d99": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", code: "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" } +} +)ETHEREUM"; diff --git a/libethereum/GenesisInfo.h b/libethereum/GenesisInfo.h new file mode 100644 index 000000000..7775da9e8 --- /dev/null +++ b/libethereum/GenesisInfo.h @@ -0,0 +1,32 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file GenesisInfo.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include + +namespace dev { +namespace eth { + +extern std::string const c_genesisInfo; + +} +} From 5da18796730f3c08e246d4bd61b658fd17d4e553 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 21 Jan 2015 11:30:16 -0800 Subject: [PATCH 26/59] Better, modular Genesis info. --- libethereum/CanonBlockChain.cpp | 13 ++++++++++--- libethereum/GenesisInfo.cpp | 6 +++++- libevm/VM.cpp | 5 +++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 0e468970c..50184161e 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -48,13 +48,20 @@ std::map const& dev::eth::genesisState() js::mValue val; json_spirit::read_string(c_genesisInfo, val); for (auto account: val.get_obj()) - if (account.second.get_obj()["code"].get_str().size()) + { + u256 balance; + if (account.second.get_obj().count("balance")) + balance = fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())); + else + balance = u256(account.second.get_obj()["finney"].get_str()) * finney; + if (account.second.get_obj().count("code")) { - s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::ContractConception); + s_ret[Address(fromHex(account.first))] = Account(balance, Account::ContractConception); s_ret[Address(fromHex(account.first))].setCode(fromHex(account.second.get_obj()["code"].get_str())); } else - s_ret[Address(fromHex(account.first))] = Account(fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())), Account::NormalCreation); + s_ret[Address(fromHex(account.first))] = Account(balance, Account::NormalCreation); + } } return s_ret; } diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp index 5b5a4ba5d..b417837a7 100644 --- a/libethereum/GenesisInfo.cpp +++ b/libethereum/GenesisInfo.cpp @@ -32,6 +32,10 @@ R"ETHEREUM( "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", code: "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" } + "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", "code": "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" }, + "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" }, + "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" }, + "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" }, + "b7576e9d314df41ec5506494293afb1bd5d3f65d": { "finney": "69423399" }, } )ETHEREUM"; diff --git a/libevm/VM.cpp b/libevm/VM.cpp index d60f585a5..a922cbf14 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -34,7 +34,8 @@ void VM::reset(u256 _gas) noexcept bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { - auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + auto gasForMem = [](bigint _size) -> bigint { bigint s = _size / 32; return (bigint)c_memoryGas * (s + s * s / 1024); }; if (m_jumpDests.empty()) for (unsigned i = 0; i < _ext.code.size(); ++i) @@ -297,7 +298,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size()) - runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += gasForMem(newTempSize) - gasForMem(m_temp.size()); runGas += c_copyGas * (copySize + 31) / 32; onOperation(); From 13ee1d0f511e94e2181842fb2c725eba4d55e836 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 20 Feb 2015 14:05:44 +0100 Subject: [PATCH 27/59] use windeployqt for deployment on windows --- cmake/EthDependencies.cmake | 5 ++++ cmake/EthExecutableHelper.cmake | 46 +++++---------------------------- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index fb6b09bb8..3f6cbcd77 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -128,6 +128,11 @@ if (NOT HEADLESS) set (MACDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/macdeployqt) message(" - macdeployqt path: ${MACDEPLOYQT_APP}") endif() + # we need to find path to windeployqt on windows + if (WIN32) + set (WINDEPLOYQT_APP ${Qt5Core_DIR}/../../../bin/windeployqt) + message(" - windeployqt path: ${WINDEPLOYQT_APP}") + endif() # TODO check node && npm version find_program(ETH_NODE node) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 427e0a9c4..7d6edef34 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -63,7 +63,7 @@ macro(eth_install_executable EXECUTABLE) if (APPLE) set(eth_qml_dir "-qmldir=${ETH_INSTALL_EXECUTABLE_QMLDIR}") elseif (WIN32) - set(eth_qml_dir --qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}) + set(eth_qml_dir "--qmldir ${ETH_INSTALL_EXECUTABLE_QMLDIR}") endif() message(STATUS "${EXECUTABLE} qmldir: ${eth_qml_dir}") endif() @@ -88,49 +88,17 @@ macro(eth_install_executable EXECUTABLE) set(BU_CHMOD_BUNDLE_ITEMS 1) verify_app(\"${APP_BUNDLE_PATH}\") " COMPONENT RUNTIME ) - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - - # copy all dlls to executable directory - # TODO improve that by copying only required dlls - file (GLOB DLLS ${ETH_DEPENDENCY_INSTALL_DIR}/bin/*.dll) - - foreach(DLL ${DLLS}) - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy "${DLL}" "$" - ) - endforeach() + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy_directory - "${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms" - $/platforms + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir} --verbose 100" + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) - - # ugly way, improve that + #workaround for https://bugreports.qt.io/browse/QTBUG-42083 add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmake -E copy_directory - "${ETH_DEPENDENCY_INSTALL_DIR}/qml" - $ - ) - - install( FILES ${DLLS} - DESTINATION bin - COMPONENT ${EXECUTABLE} - ) - - install( DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/plugins/platforms - DESTINATION bin - COMPONENT ${EXECUTABLE} + COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM ) - - file (GLOB QMLS ${ETH_DEPENDENCY_INSTALL_DIR}/qml/*) - foreach(QML ${QMLS}) - install( DIRECTORY ${QML} - DESTINATION bin - COMPONENT ${EXECUTABLE} - ) - endforeach() - install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin COMPONENT ${EXECUTABLE} From 6fbee922e054eadbcd5bfb91619981faadd2a748 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 14:10:03 +0100 Subject: [PATCH 28/59] Remove genesis contract. --- libethereum/GenesisInfo.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp index b417837a7..0a7572dd6 100644 --- a/libethereum/GenesisInfo.cpp +++ b/libethereum/GenesisInfo.cpp @@ -24,7 +24,7 @@ std::string const dev::eth::c_genesisInfo = R"ETHEREUM( { - "51ba59315b3a95761d0863b05ccc7a7f54703d99": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, @@ -32,7 +32,6 @@ R"ETHEREUM( "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "000000000000000000000000000000000000002a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000", "code": "60035415601c576000600060006000609660020a3360155a03f150005b610100331015602757005b60003560805260805160a060020a02330160a0523460a051540160a051553460805154016080515560006000546003600154041015607557506a027b46536c66c8e300000060005460015401115b608157600060025560a5565b600254608f574260025560a4565b62093a806002544203111560a35760016003555b5b5b" }, "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" }, "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" }, "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" }, From bf16bc119b3906a0196ddfc28c759a6709d54d70 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 20 Feb 2015 17:07:51 +0300 Subject: [PATCH 29/59] New Solidity Tests --- test/stInitCodeTestFiller.json | 80 +++++++++- test/stSolidityTestFiller.json | 279 ++++++++++++++++++++++++++++++++- 2 files changed, 355 insertions(+), 4 deletions(-) diff --git a/test/stInitCodeTestFiller.json b/test/stInitCodeTestFiller.json index 134d75198..ea5467df8 100644 --- a/test/stInitCodeTestFiller.json +++ b/test/stInitCodeTestFiller.json @@ -267,7 +267,7 @@ { "095e7baea6a6c7c4c2dfeb977efac326af552d87": { "balance": "0", - "nonce": "0", + "nonce": "40", "code": "{[[ 2 ]](ADDRESS)(CODECOPY 0 0 32)(CREATE 0 0 32)}", "storage": {} }, @@ -489,5 +489,83 @@ "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "0" } + }, + + "ReturnTest" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(CALL 2000 0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b 0 30 1 31 1) (RETURN 30 2)}", + "nonce" : "0", + "storage" : { + } + }, + + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(MSTORE 0 0x15) (RETURN 31 1)}", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "ReturnTest2" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(MSTORE 0 0x15)(CALL 7000 0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b 0 0 32 32 32) (RETURN 0 64)}", + "nonce" : "0", + "storage" : { + } + }, + + "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "{(MSTORE 0 (MUL 3 (CALLDATALOAD 0)))(RETURN 0 32)}", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "data" : "", + "gasLimit" : "15000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } } } diff --git a/test/stSolidityTestFiller.json b/test/stSolidityTestFiller.json index fc0770c5e..973c52a8d 100644 --- a/test/stSolidityTestFiller.json +++ b/test/stSolidityTestFiller.json @@ -73,6 +73,9 @@ "//" : " if (!testStructuresAndVariabless()) ", "//" : " res = hash(int(res) + int(0x0000f00000000000000000000000000000000000000000000000000000000000)); ", "//" : " ", + "//" : " if (!testCryptographicFunctions()) ", + "//" : " res = hash(int(res) + int(0x00000f0000000000000000000000000000000000000000000000000000000000)); ", + "//" : " ", "//" : " //Tested 27.01.2015 ", "//" : " //should run out of gas ", "//" : " //if (!testInfiniteLoop()) ", @@ -83,6 +86,21 @@ "//" : " // res = hash(int(res) + int(0x0000000000000000000000000000000000000000000000000000000000000000)); ", "//" : " } ", "//" : " ", + "//" : " function testCryptographicFunctions() returns (bool res) ", + "//" : " { ", + "//" : " res = true; ", + "//" : " if (sha3('teststring') != 0x43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d) ", + "//" : " return false; ", + "//" : " ", + "//" : " if (sha256('teststring') != 0x3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d111) ", + "//" : " return false; ", + "//" : " ", + "//" : " if (ripemd160('teststring') != 0xcd566972b5e50104011a92b59fa8e0b1234851ae) ", + "//" : " return false; ", + "//" : " ", + "//" : " //ecrecover ", + "//" : " } ", + "//" : " ", "//" : " function testStructuresAndVariabless() returns (bool res) ", "//" : " { ", "//" : " res = true; ", @@ -112,8 +130,8 @@ "//" : " return false; ", "//" : " ", "//" : " //for some reason does not work 27.01.2015 ", - "//" : " //if (block.gaslimit != 1000000000000000000000) ", - "//" : " // return false; ", + "//" : " if (block.gaslimit != 1000000000000000000000) ", + "//" : " return false; ", "//" : " ", "//" : " if (block.number != 120) ", "//" : " return false; ", @@ -213,7 +231,7 @@ "//" : " a = new TestContract(); ", "//" : " } ", "//" : "} ", - "code" : "0x60e060020a6000350480630c4c9a8014610078578063296df0df1461008a5780632a9afb831461009c578063380e4396146100ae5780634893d88a146100c05780637ee17e12146100ce578063981a3165146100dc578063a60eedda146100ee578063e97384dc14610100578063ed973fe91461011257005b610080610431565b8060005260206000f35b6100926103f7565b8060005260206000f35b6100a46105d1565b8060005260206000f35b6100b6610220565b8060005260206000f35b6100c8610426565b60006000f35b6100d66102df565b60006000f35b6100e4610411565b8060005260206000f35b6100f6610124565b8060005260206000f35b6101086102f5565b8060005260206000f35b61011a6101be565b8060005260206000f35b60006000605f6106be600039605f60006000f0905080600160a060020a031662f55d9d8060e060020a0260005241600160a060020a0316600452600060006024600060008660155a03f150505080600160a060020a031663b9c3d0a58060e060020a02600052602060006004600060008660155a03f150505060005160e1146101ac576101b5565b600191506101ba565b600091505b5090565b60006000605f6106be600039605f60006000f0905080600160a060020a031663b9c3d0a58060e060020a02600052602060006004600060008660155a03f150505060005160e11461020e57610217565b6001915061021c565b600091505b5090565b60006000600060009150600092508160001461023b576102bf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe78213156102b5575b600a82121561027a578180600101925050610264565b81600a14610287576102b0565b600a90505b60008160ff1611156102af5781806001900392505080806001900391505061028c565b5b6102be565b600092506102da565b5b816000146102cc576102d5565b600192506102da565b600092505b505090565b6000605f6106be600039605f60006000f0905090565b60006001905041600160a060020a0316732adc25665018aa1fe0e6bc666dac8fc2697ff9ba14156103255761032e565b600090506103f4565b446302b8feb0141561033f57610348565b600090506103f4565b43607814156103565761035f565b600090506103f4565b33600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561038957610392565b600090506103f4565b34606414156103a0576103a9565b600090506103f4565b3a600114156103b7576103c0565b600090506103f4565b32600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156103ea576103f3565b600090506103f4565b5b90565b6000600090505b60011561040a576103fe565b6001905090565b60006000905061041f610426565b6001905090565b61042e610411565b50565b60006000905061043f6102df565b50610448610220565b1561045257610478565b7ff000000000000000000000000000000000000000000000000000000000000000810190505b6104806101be565b1561048a576104b0565b7f0f00000000000000000000000000000000000000000000000000000000000000810190505b6104b8610124565b156104c2576104e7565b7ef0000000000000000000000000000000000000000000000000000000000000810190505b6104ef6102f5565b156104f95761051e565b7e0f000000000000000000000000000000000000000000000000000000000000810190505b60ff60008190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b60018190555060ff6002819055507f676c6f62616c2064617461203332206c656e67746820737472696e670000000060038190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b600460006000526020526040600020819055506105a06105d1565b156105aa576105ce565b7df00000000000000000000000000000000000000000000000000000000000810190505b90565b60006001905060005460ff14156105e7576105f0565b600090506106ba565b60025460005414156106015761060a565b600090506106ba565b600154600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156106365761063f565b600090506106ba565b6003547f676c6f62616c2064617461203332206c656e67746820737472696e6700000000141561066e57610677565b600090506106ba565b60046000600052602052604060002054600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b14156106b0576106b9565b600090506106ba565b5b905600605380600c6000396000f30060e060020a600035048062f55d9d14601d578063b9c3d0a514602c57005b60266004356045565b60006000f35b6032603c565b8060005260206000f35b600060e1905090565b80600160a060020a0316ff5056", + "code" : "0x60003560e060020a900480630c4c9a8014610084578063296df0df146100965780632a9afb83146100a8578063380e4396146100ba5780634893d88a146100cc5780637ee17e12146100da578063981a3165146100e8578063a60eedda146100fa578063e0a9fd281461010c578063e97384dc1461011e578063ed973fe91461013057005b61008c6102c0565b8060005260206000f35b61009e61067b565b8060005260206000f35b6100b06101ba565b8060005260206000f35b6100c261049b565b8060005260206000f35b6100d461087d565b60006000f35b6100e26101a4565b60006000f35b6100f06102ab565b8060005260206000f35b610102610695565b8060005260206000f35b610114610732565b8060005260206000f35b61012661055a565b8060005260206000f35b610138610142565b8060005260206000f35b600060006060610889600039606060006000f0905080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660155a03f150505060005160e1146101925761019b565b600191506101a0565b600091505b5090565b60006060610889600039606060006000f0905090565b60006001905060005460ff14156101d0576101d9565b600090506102a8565b60025460005414156101ea576101f3565b600090506102a8565b600154600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561021f57610228565b600090506102a8565b6003547f676c6f62616c2064617461203332206c656e67746820737472696e6700000000141561025757610260565b600090506102a8565b600460006000815260200190815260200160002054600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561029e576102a7565b600090506102a8565b5b90565b6000600090506102b961087d565b6001905090565b6000600090506102ce6101a4565b506102d761049b565b156102e157610307565b7ff000000000000000000000000000000000000000000000000000000000000000810190505b61030f610142565b156103195761033f565b7f0f00000000000000000000000000000000000000000000000000000000000000810190505b610347610695565b1561035157610376565b7ef0000000000000000000000000000000000000000000000000000000000000810190505b61037e61055a565b15610388576103ad565b7e0f000000000000000000000000000000000000000000000000000000000000810190505b60ff60008190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b60018190555060ff6002819055507f676c6f62616c2064617461203332206c656e67746820737472696e670000000060038190555073a94f5374fce5edbc8e2a8697c15331677e6ebf0b6004600060008152602001908152602001600020819055506104346101ba565b1561043e57610462565b7df00000000000000000000000000000000000000000000000000000000000810190505b61046a610732565b1561047457610498565b7d0f0000000000000000000000000000000000000000000000000000000000810190505b90565b6000600060006000915060009250816000146104b65761053a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7821315610530575b600a8212156104f55781806001019250506104df565b81600a146105025761052b565b600a90505b60008160ff16111561052a57818060019003925050808060019003915050610507565b5b610539565b60009250610555565b5b8160001461054757610550565b60019250610555565b600092505b505090565b60006001905041600160a060020a0316732adc25665018aa1fe0e6bc666dac8fc2697ff9ba141561058a57610593565b60009050610678565b446302b8feb014156105a4576105ad565b60009050610678565b45683635c9adc5dea0000014156105c3576105cc565b60009050610678565b43607814156105da576105e3565b60009050610678565b33600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561060d57610616565b60009050610678565b34606414156106245761062d565b60009050610678565b3a6001141561063b57610644565b60009050610678565b32600160a060020a031673a94f5374fce5edbc8e2a8697c15331677e6ebf0b141561066e57610677565b60009050610678565b5b90565b6000600090505b60011561068e57610682565b6001905090565b60006000600191506060610889600039606060006000f0905080600160a060020a031662f55d9d600060008260e060020a02600052600441600160a060020a03168152602001600060008660155a03f150505080600160a060020a031663b9c3d0a5602060008260e060020a026000526004600060008660155a03f150505060005160e114156107245761072d565b6000915061072e565b5b5090565b60006001905060007f74657374737472696e67000000000000000000000000000000000000000000008152600a016000207f43c4b4524adb81e4e9a5c4648a98e9d320e3908ac5b6c889144b642cd08ae16d141561078f57610798565b6000905061087a565b60026020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560155a03f150506000517f3c8727e019a42b444667a587b6001251becadabbb36bfed8087a92c18882d11114156108015761080a565b6000905061087a565b60036020600060007f74657374737472696e67000000000000000000000000000000000000000000008152600a01600060008560155a03f15050600051600160a060020a031673cd566972b5e50104011a92b59fa8e0b1234851ae141561087057610879565b6000905061087a565b5b90565b6108856102ab565b505600605480600c6000396000f30060003560e060020a90048062f55d9d14601e578063b9c3d0a514602d57005b60276004356046565b60006000f35b6033603d565b8060005260206000f35b600060e1905090565b80600160a060020a0316ff5056", "nonce" : "0", "storage" : { } @@ -233,5 +251,260 @@ "to" : "d94f5374fce5edbc8e2a8697c15331677e6ebf0b", "value" : "100" } + }, + + "CallLowLevelCreatesSolidity" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "//": "contract subcaller ", + "//": "{ ", + "//": " function init(address a) ", + "//": " { ", + "//": " main(a).setdata(225); ", + "//": " } ", + "//": "} ", + "//": " ", + "//": "contract main ", + "//": "{ ", + "//": " uint data; ", + "//": " function run() returns (uint) ", + "//": " { ", + "//": " data = 1; ", + "//": " subcaller a = new subcaller(); ", + "//": " a.init(msg.sender); ", + "//": " return data; ", + "//": " } ", + "//": " ", + "//": " function setdata(uint _data) ", + "//": " { ", + "//": " data = _data; ", + "//": " } ", + "//": "}", + "code" : "0x60e060020a60003504806330debb4214610020578063c04062261461003157005b61002b6004356100a4565b60006000f35b610039610043565b8060005260206000f35b60006000600160008190555060656100af600039606560006000f0905080600160a060020a03166319ab453c600060008260e060020a02600052600433600160a060020a03168152602001600060008660155a03f150505060005491505090565b80600081905550505600605980600c6000396000f30060e060020a60003504806319ab453c14601457005b601d6004356023565b60006000f35b80600160a060020a03166330debb42600060008260e060020a02600052600460e18152602001600060008660155a03f15050505056", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "run()", + "data" : "0xc0406226", + "gasLimit" : "15000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "CallRecursiveMethods" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "//" : "contract recursiveMethods ", + "//" : "{ ", + "//" : " function testInfiniteLoop() ", + "//" : " { ", + "//" : " while(true){} ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods() ", + "//" : " { ", + "//" : " testRecursiveMethods2(); ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods2() ", + "//" : " { ", + "//" : " testRecursiveMethods(); ", + "//" : " } ", + "//" : "}", + "code" : "0x60e060020a600035048063296df0df1460285780634893d88a146034578063981a316514604057005b602e604c565b60006000f35b603a6061565b60006000f35b60466059565b60006000f35b5b600115605757604d565b565b605f6061565b565b60676059565b56", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "testRecursiveMethods()", + "data" : "0x981a3165", + "gasLimit" : "7000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "CallInfiniteLoop" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "//" : "contract recursiveMethods ", + "//" : "{ ", + "//" : " function testInfiniteLoop() ", + "//" : " { ", + "//" : " while(true){} ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods() ", + "//" : " { ", + "//" : " testRecursiveMethods2(); ", + "//" : " } ", + "//" : " ", + "//" : " function testRecursiveMethods2() ", + "//" : " { ", + "//" : " testRecursiveMethods(); ", + "//" : " } ", + "//" : "}", + "code" : "0x60e060020a600035048063296df0df1460285780634893d88a146034578063981a316514604057005b602e604c565b60006000f35b603a6061565b60006000f35b60466059565b60006000f35b5b600115605757604d565b565b605f6061565b565b60676059565b56", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "testInfiniteLoop()", + "data" : "0x296df0df", + "gasLimit" : "10000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "RecursiveCreateContracts" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000", + "//" : "contract recursiveCreate1 ", + "//" : "{ ", + "//" : " function recursiveCreate1(address a, uint depth) ", + "//" : " { ", + "//" : " depth = depth - 1; ", + "//" : " if(depth > 0) ", + "//" : " main(a).create2(depth); ", + "//" : " } ", + "//" : "} ", + "//" : " ", + "//" : "contract recursiveCreate2 ", + "//" : "{ ", + "//" : " function recursiveCreate2(address a, uint depth) ", + "//" : " { ", + "//" : " depth = depth - 1; ", + "//" : " if(depth > 0) ", + "//" : " recursiveCreate1 rec1 = new recursiveCreate1(a, depth); ", + "//" : " } ", + "//" : "} ", + "//" : " ", + "//" : "contract main ", + "//" : "{ ", + "//" : " address maincontract; ", + "//" : " uint depp; ", + "//" : " function run(uint depth) ", + "//" : " { ", + "//" : " maincontract = msg.sender; ", + "//" : " depp = depth; ", + "//" : " recursiveCreate1 rec1 = new recursiveCreate1(maincontract, depth); ", + "//" : " } ", + "//" : " ", + "//" : " function create2(uint depth) ", + "//" : " { ", + "//" : " recursiveCreate2 rec2 = new recursiveCreate2(maincontract, depth); ", + "//" : " address(rec2).send(2); ", + "//" : " } ", + "//" : "}", + "code" : "0x60003560e060020a90048063820b13f614610021578063a444f5e91461003257005b61002c600435610043565b60006000f35b61003d60043561008f565b60006000f35b600060c66100cc60003960c6600054600160a060020a0316815260200182815260200160006000f0905080600160a060020a0316600060026000600060006000848787f1505050505050565b6000336000819055508160018190555060686101926000396068600054600160a060020a0316815260200182815260200160006000f09050505056006012604060c6600439600451602451601e565b60018060c56000396000f35b6000600182039150600082116031576057565b6068605d600039606883600160a060020a0316815260200182815260200160006000f090505b5050505600601260406068600439600451602451601e565b60018060676000396000f35b60018103905060008111602f576062565b81600160a060020a031663820b13f6600060008260e060020a026000526004858152602001600060008660155a03f15050505b505056000000601260406068600439600451602451601e565b60018060676000396000f35b60018103905060008111602f576062565b81600160a060020a031663820b13f6600060008260e060020a026000526004858152602001600060008660155a03f15050505b5050560000", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "run(uint256)", + "data" : "0xa444f5e900000000000000000000000000000000000000000000000000000000000204", + "gasLimit" : "10000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } + }, + + "AmbigiousMethod" : { + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "45678256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : 1, + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : + { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "code" : "0x60003560e060020a90048063c040622614601557005b601b6021565b60006000f35b61014f60008190555056", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : + { + "//" : "run()", + "data" : "0xc0406226", + "gasLimit" : "10000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "1" + } } } From 4e6f4013a50121a877151d0381a761267eba549f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 15:30:40 +0100 Subject: [PATCH 30/59] Decimal wei rather than hex balance. Memory back to linear cost. --- libethereum/CanonBlockChain.cpp | 4 ++-- libethereum/GenesisInfo.cpp | 16 ++++++++-------- libevm/VM.cpp | 7 ++++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 50184161e..b0fe90a78 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -50,8 +50,8 @@ std::map const& dev::eth::genesisState() for (auto account: val.get_obj()) { u256 balance; - if (account.second.get_obj().count("balance")) - balance = fromBigEndian(fromHex(account.second.get_obj()["balance"].get_str())); + if (account.second.get_obj().count("wei")) + balance = u256(account.second.get_obj()["wei"].get_str()); else balance = u256(account.second.get_obj()["finney"].get_str()) * finney; if (account.second.get_obj().count("code")) diff --git a/libethereum/GenesisInfo.cpp b/libethereum/GenesisInfo.cpp index 0a7572dd6..b9b45d4b4 100644 --- a/libethereum/GenesisInfo.cpp +++ b/libethereum/GenesisInfo.cpp @@ -24,14 +24,14 @@ std::string const dev::eth::c_genesisInfo = R"ETHEREUM( { - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "e6716f9544a56c530d868e4bfbacb172315bdead": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "6c386a4b26f73c802f34673f7248bb118f97424a": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, - "e4157b34ea9615cfbde6b4fda419828124b70c78": { "balance": "0000000000000100000000000000000000000000000000000000000000000000" }, + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "e6716f9544a56c530d868e4bfbacb172315bdead": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "6c386a4b26f73c802f34673f7248bb118f97424a": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, + "e4157b34ea9615cfbde6b4fda419828124b70c78": { "wei": "1606938044258990275541962092341162602522202993782792835301376" }, "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": { "finney": "154162184" }, "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": { "finney": "102774789" }, "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": { "finney": "51387394" }, diff --git a/libevm/VM.cpp b/libevm/VM.cpp index a922cbf14..a7ca91533 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -35,7 +35,12 @@ void VM::reset(u256 _gas) noexcept bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; - auto gasForMem = [](bigint _size) -> bigint { bigint s = _size / 32; return (bigint)c_memoryGas * (s + s * s / 1024); }; + auto gasForMem = [](bigint _size) -> bigint + { + bigint s = _size / 32; +// return (bigint)c_memoryGas * (s + s * s / 1024); + return (bigint)c_memoryGas * s; + }; if (m_jumpDests.empty()) for (unsigned i = 0; i < _ext.code.size(); ++i) From f71337400b88716a3daa27a2aefe7edcc42d6652 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 20 Feb 2015 15:47:07 +0100 Subject: [PATCH 31/59] removed verbosity flag --- cmake/EthExecutableHelper.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 7d6edef34..c6e0210de 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -91,7 +91,7 @@ macro(eth_install_executable EXECUTABLE) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir} --verbose 100" + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ) #workaround for https://bugreports.qt.io/browse/QTBUG-42083 From 73d5ff677e8c768c282e87ffc57a60420388d7f5 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 10:51:22 +0100 Subject: [PATCH 32/59] Refactored account management out of WebThreeStubServerBase. --- libdevcrypto/Common.cpp | 2 + libdevcrypto/Common.h | 3 ++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 66 ++++++++++++----------- libweb3jsonrpc/WebThreeStubServerBase.h | 33 ++++++++++-- 4 files changed, 68 insertions(+), 36 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 0a94662c8..048134de8 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -44,6 +44,8 @@ bool dev::SignatureStruct::isValid() const return true; } +Address dev::ZeroAddress = Address(); + Public dev::toPublic(Secret const& _secret) { Public p; diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index e91df2526..ccbd0953b 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -62,6 +62,9 @@ struct SignatureStruct /// @NOTE This is not endian-specific; it's just a bunch of bytes. using Address = h160; +/// The zero address. +extern Address ZeroAddress; + /// A vector of Ethereum addresses. using Addresses = h160s; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 8e0b30366..185d3f6e0 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -211,22 +211,33 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message return res; } -WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): - AbstractWebThreeStubServer(_conn) -{ - setAccounts(_accounts); -} - -void WebThreeStubServerBase::setAccounts(std::vector const& _accounts) +void AccountHolder::setAccounts(std::vector const& _accounts) { m_accounts.clear(); - for (auto const& i: _accounts) + for (auto const& keyPair: _accounts) { - m_accounts.push_back(i.address()); - m_accountsLookup[i.address()] = i; + m_accounts.push_back(keyPair.address()); + m_keyPairs[keyPair.address()] = keyPair; } } +Address const& AccountHolder::getDefaultCallAccount() const +{ + if (m_accounts.empty()) + return ZeroAddress; + Address const* bestMatch = &m_accounts.front(); + for (auto const& account: m_accounts) + if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) + bestMatch = &account; + return *bestMatch; +} + +WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): + AbstractWebThreeStubServer(_conn), m_accounts(std::bind(&WebThreeStubServerBase::client, this)) +{ + m_accounts.setAccounts(_accounts); +} + void WebThreeStubServerBase::setIdentities(std::vector const& _ids) { m_ids.clear(); @@ -242,7 +253,7 @@ std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) Json::Value WebThreeStubServerBase::eth_accounts() { Json::Value ret(Json::arrayValue); - for (auto const& i: m_accounts) + for (auto const& i: m_accounts.getAllAccounts()) ret.append(toJS(i)); return ret; } @@ -326,21 +337,15 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) - { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) + if (!t.from) + t.from = m_accounts.getDefaultCallAccount(); + if (!m_accounts.isRealAccount(t.from)) return ret; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - ret = toJS(client()->call(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->call(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); return ret; } @@ -684,16 +689,14 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); - if (!t.from && m_accounts.size()) + if (!t.from) + t.from = m_accounts.getDefaultCallAccount(); + if (!m_accounts.isRealAccount(t.from)) { - auto b = m_accounts.front(); - for (auto const& a: m_accounts) - if (client()->balanceAt(a) > client()->balanceAt(b)) - b = a; - t.from = b; - } - if (!m_accountsLookup.count(t.from)) +// if (m_accounts.isProxyAccount(t.from)) +// m_accounts.storeTransaction(t); return ret; + } if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) @@ -702,9 +705,9 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { if (t.to) // TODO: from qethereum, insert validification hook here. - client()->transact(m_accountsLookup[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); + client()->transact(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); else - ret = toJS(client()->transact(m_accountsLookup[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->transact(m_accounts.secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); } return ret; @@ -741,4 +744,3 @@ bool WebThreeStubServerBase::eth_uninstallFilter(int _id) client()->uninstallWatch(_id); return true; } - diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ec83c9797..988f13b8f 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include #include #pragma GCC diagnostic push @@ -53,6 +54,32 @@ public: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; }; + +/** + * Manages real accounts (where we know the secret key) and proxy accounts (where transactions + * to be sent from these accounts are forwarded to a proxy on the other side). + */ +class AccountHolder +{ +public: + explicit AccountHolder(std::function const& _client): m_client(_client) {} + + /// Sets or resets the list of real accounts. + void setAccounts(std::vector const& _accounts); + std::vector const& getRealAccounts() const { return m_accounts; } + bool isRealAccount(dev::Address const& _account) const { return m_keyPairs.count(_account) > 0; } + Secret const& secretKey(dev::Address const& _account) const { return m_keyPairs.at(_account).secret(); } + std::vector const& getAllAccounts() const { return m_accounts; /*todo */} + dev::Address const& getDefaultCallAccount() const; + +private: + std::map m_keyPairs; + std::vector m_accounts; + std::function m_client; + +}; + + /** * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int @@ -125,7 +152,7 @@ public: virtual bool shh_post(Json::Value const& _json); virtual bool shh_uninstallFilter(int _id); - void setAccounts(std::vector const& _accounts); + void setAccounts(std::vector const& _accounts) { m_accounts.setAccounts(_accounts); } void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } @@ -138,11 +165,9 @@ protected: virtual dev::WebThreeNetworkFace* network() = 0; virtual dev::WebThreeStubDatabaseFace* db() = 0; - std::map m_accountsLookup; - std::vector m_accounts; - std::map m_ids; std::map m_shhWatches; + AccountHolder m_accounts; }; } //namespace dev From 0b014457d4b631924a0811f3104572aad3f0fc3e Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 15:13:03 +0100 Subject: [PATCH 33/59] Implemented account proxy queues. --- libweb3jsonrpc/AccountHolder.cpp | 102 ++++++++++++++++++++ libweb3jsonrpc/AccountHolder.h | 74 ++++++++++++++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 91 ++++++++++------- libweb3jsonrpc/WebThreeStubServerBase.h | 37 ++----- libweb3jsonrpc/abstractwebthreestubserver.h | 18 ++++ libweb3jsonrpc/spec.json | 4 + test/AccountHolder.cpp | 74 ++++++++++++++ test/webthreestubclient.h | 30 ++++++ 8 files changed, 365 insertions(+), 65 deletions(-) create mode 100644 libweb3jsonrpc/AccountHolder.cpp create mode 100644 libweb3jsonrpc/AccountHolder.h create mode 100644 test/AccountHolder.cpp diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp new file mode 100644 index 000000000..e12380110 --- /dev/null +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -0,0 +1,102 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file AccountHolder.cpp + * @authors: + * Christian R + * Lefteris Karapetsas + * @date 2015 + */ + +#include "AccountHolder.h" +#include + + +using namespace std; +using namespace dev; +using namespace dev::eth; + +vector emptyQueue; + +void AccountHolder::setAccounts(vector const& _accounts) +{ + m_accounts.clear(); + for (auto const& keyPair: _accounts) + { + m_accounts.push_back(keyPair.address()); + m_keyPairs[keyPair.address()] = keyPair; + } +} + +vector
AccountHolder::getAllAccounts() const +{ + vector
accounts = m_accounts; + for (auto const& pair: m_proxyAccounts) + if (!isRealAccount(pair.first)) + accounts.push_back(pair.first); + return accounts; +} + +Address const& AccountHolder::getDefaultCallAccount() const +{ + if (m_accounts.empty()) + return ZeroAddress; + Address const* bestMatch = &m_accounts.front(); + for (auto const& account: m_accounts) + if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) + bestMatch = &account; + return *bestMatch; +} + +int AccountHolder::addProxyAccount(const Address& _account) +{ + int const c_id = m_transactionQueues.empty() ? 1 : m_transactionQueues.rbegin()->first + 1; + if (isProxyAccount(_account)) + return 0; + m_proxyAccounts.insert(make_pair(_account, c_id)); + m_transactionQueues[c_id].first = _account; + return c_id; +} + +bool AccountHolder::removeProxyAccount(unsigned _id) +{ + if (!m_transactionQueues.count(_id)) + return false; + m_proxyAccounts.erase(m_transactionQueues[_id].first); + m_transactionQueues.erase(_id); + return true; +} + +void AccountHolder::queueTransaction(TransactionSkeleton const& _transaction) +{ + if (!m_proxyAccounts.count(_transaction.from)) + return; + int id = m_proxyAccounts[_transaction.from]; + m_transactionQueues[id].second.push_back(_transaction); +} + +vector const& AccountHolder::getQueuedTransactions(int _id) const +{ + if (!m_transactionQueues.count(_id)) + return emptyQueue; + return m_transactionQueues.at(_id).second; +} + +void AccountHolder::clearQueue(int _id) +{ + if (m_transactionQueues.count(_id)) + m_transactionQueues.at(_id).second.clear(); +} diff --git a/libweb3jsonrpc/AccountHolder.h b/libweb3jsonrpc/AccountHolder.h new file mode 100644 index 000000000..939947ea2 --- /dev/null +++ b/libweb3jsonrpc/AccountHolder.h @@ -0,0 +1,74 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file AccountHolder.h + * @authors: + * Christian R + * Lefteris Karapetsas + * @date 2015 + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace dev +{ +namespace eth +{ +class Interface; +} + +/** + * Manages real accounts (where we know the secret key) and proxy accounts (where transactions + * to be sent from these accounts are forwarded to a proxy on the other side). + */ +class AccountHolder +{ +public: + explicit AccountHolder(std::function const& _client): m_client(_client) {} + + /// Sets or resets the list of real accounts. + void setAccounts(std::vector const& _accounts); + std::vector
const& getRealAccounts() const { return m_accounts; } + bool isRealAccount(Address const& _account) const { return m_keyPairs.count(_account) > 0; } + bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; } + Secret const& secretKey(Address const& _account) const { return m_keyPairs.at(_account).secret(); } + std::vector
getAllAccounts() const; + Address const& getDefaultCallAccount() const; + + int addProxyAccount(Address const& _account); + bool removeProxyAccount(unsigned _id); + void queueTransaction(eth::TransactionSkeleton const& _transaction); + + std::vector const& getQueuedTransactions(int _id) const; + void clearQueue(int _id); + +private: + using TransactionQueue = std::vector; + + std::map m_keyPairs; + std::vector
m_accounts; + std::map m_proxyAccounts; + std::map> m_transactionQueues; + std::function m_client; +}; + +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 185d3f6e0..b5cc6e078 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -35,6 +35,7 @@ #include #endif #include "WebThreeStubServerBase.h" +#include "AccountHolder.h" using namespace std; using namespace dev; @@ -72,6 +73,18 @@ static Json::Value toJson(dev::eth::Transaction const& _t) return res; } +static Json::Value toJson(dev::eth::TransactionSkeleton const& _t) +{ + Json::Value res; + res["to"] = toJS(_t.to); + res["from"] = toJS(_t.from); + res["gas"] = (int)_t.gas; + res["gasPrice"] = toJS(_t.gasPrice); + res["value"] = toJS(_t.value); + res["data"] = jsFromBinary(_t.data); + return res; +} + static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; @@ -211,31 +224,10 @@ static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message return res; } -void AccountHolder::setAccounts(std::vector const& _accounts) -{ - m_accounts.clear(); - for (auto const& keyPair: _accounts) - { - m_accounts.push_back(keyPair.address()); - m_keyPairs[keyPair.address()] = keyPair; - } -} - -Address const& AccountHolder::getDefaultCallAccount() const -{ - if (m_accounts.empty()) - return ZeroAddress; - Address const* bestMatch = &m_accounts.front(); - for (auto const& account: m_accounts) - if (m_client()->balanceAt(account) > m_client()->balanceAt(*bestMatch)) - bestMatch = &account; - return *bestMatch; -} - WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector const& _accounts): - AbstractWebThreeStubServer(_conn), m_accounts(std::bind(&WebThreeStubServerBase::client, this)) + AbstractWebThreeStubServer(_conn), m_accounts(make_shared(std::bind(&WebThreeStubServerBase::client, this))) { - m_accounts.setAccounts(_accounts); + m_accounts->setAccounts(_accounts); } void WebThreeStubServerBase::setIdentities(std::vector const& _ids) @@ -253,7 +245,7 @@ std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) Json::Value WebThreeStubServerBase::eth_accounts() { Json::Value ret(Json::arrayValue); - for (auto const& i: m_accounts.getAllAccounts()) + for (auto const& i: m_accounts->getAllAccounts()) ret.append(toJS(i)); return ret; } @@ -338,14 +330,14 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts.getDefaultCallAccount(); - if (!m_accounts.isRealAccount(t.from)) + t.from = m_accounts->getDefaultCallAccount(); + if (!m_accounts->isRealAccount(t.from)) return ret; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - ret = toJS(client()->call(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->call(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice)); return ret; } @@ -469,6 +461,25 @@ bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce) return client()->submitNonce(jsToFixed<32>(_nonce)); } +int WebThreeStubServerBase::eth_register(std::string const& _address) +{ + return m_accounts->addProxyAccount(jsToAddress(_address)); +} + +bool WebThreeStubServerBase::eth_unregister(int _id) +{ + return m_accounts->removeProxyAccount(_id); +} + +Json::Value WebThreeStubServerBase::eth_queuedTransactions(int _id) +{ + Json::Value ret(Json::arrayValue); + for (TransactionSkeleton const& t: m_accounts->getQueuedTransactions(_id)) + ret.append(toJson(t)); + m_accounts->clearQueue(_id); + return ret; +} + std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who) { (void)_id; @@ -690,24 +701,27 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts.getDefaultCallAccount(); - if (!m_accounts.isRealAccount(t.from)) - { -// if (m_accounts.isProxyAccount(t.from)) -// m_accounts.storeTransaction(t); - return ret; - } + t.from = m_accounts->getDefaultCallAccount(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); + if (!m_accounts->isRealAccount(t.from)) + { + if (m_accounts->isProxyAccount(t.from)) + { + // todo "authenticate for proxy" + m_accounts->queueTransaction(t); + } + return ret; + } if (authenticate(t)) { if (t.to) // TODO: from qethereum, insert validification hook here. - client()->transact(m_accounts.secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); + client()->transact(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); else - ret = toJS(client()->transact(m_accounts.secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); + ret = toJS(client()->transact(m_accounts->secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); client()->flushTransactions(); } return ret; @@ -744,3 +758,8 @@ bool WebThreeStubServerBase::eth_uninstallFilter(int _id) client()->uninstallWatch(_id); return true; } + +void WebThreeStubServerBase::setAccounts(const std::vector& _accounts) +{ + m_accounts->setAccounts(_accounts); +} diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 988f13b8f..62260d11d 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -23,8 +23,8 @@ #pragma once +#include #include -#include #include #include #pragma GCC diagnostic push @@ -36,6 +36,7 @@ namespace dev { class WebThreeNetworkFace; +class AccountHolder; class KeyPair; namespace eth { @@ -54,32 +55,6 @@ public: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; }; - -/** - * Manages real accounts (where we know the secret key) and proxy accounts (where transactions - * to be sent from these accounts are forwarded to a proxy on the other side). - */ -class AccountHolder -{ -public: - explicit AccountHolder(std::function const& _client): m_client(_client) {} - - /// Sets or resets the list of real accounts. - void setAccounts(std::vector const& _accounts); - std::vector const& getRealAccounts() const { return m_accounts; } - bool isRealAccount(dev::Address const& _account) const { return m_keyPairs.count(_account) > 0; } - Secret const& secretKey(dev::Address const& _account) const { return m_keyPairs.at(_account).secret(); } - std::vector const& getAllAccounts() const { return m_accounts; /*todo */} - dev::Address const& getDefaultCallAccount() const; - -private: - std::map m_keyPairs; - std::vector m_accounts; - std::function m_client; - -}; - - /** * @brief JSON-RPC api implementation * @todo filters should work on unsigned instead of int @@ -137,6 +112,10 @@ public: virtual Json::Value eth_getWork(); virtual bool eth_submitWork(std::string const& _nonce); + virtual int eth_register(std::string const& _address); + virtual bool eth_unregister(int _id); + virtual Json::Value eth_queuedTransactions(int _id); + virtual std::string db_get(std::string const& _name, std::string const& _key); virtual std::string db_getString(std::string const& _name, std::string const& _key); virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); @@ -152,7 +131,7 @@ public: virtual bool shh_post(Json::Value const& _json); virtual bool shh_uninstallFilter(int _id); - void setAccounts(std::vector const& _accounts) { m_accounts.setAccounts(_accounts); } + void setAccounts(std::vector const& _accounts); void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_ids; } @@ -167,7 +146,7 @@ protected: std::map m_ids; std::map m_shhWatches; - AccountHolder m_accounts; + std::shared_ptr m_accounts; }; } //namespace dev diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 53d7f856d..e40c68acd 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -55,6 +55,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_unregister", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_unregisterI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_queuedTransactions", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_queuedTransactionsI); this->bindAndAddMethod(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(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(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); @@ -253,6 +256,18 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_submitWork(request[0u].asString()); } + inline virtual void eth_registerI(const Json::Value &request, Json::Value &response) + { + response = this->eth_register(request[0u].asString()); + } + inline virtual void eth_unregisterI(const Json::Value &request, Json::Value &response) + { + response = this->eth_unregister(request[0u].asInt()); + } + inline virtual void eth_queuedTransactionsI(const Json::Value &request, Json::Value &response) + { + response = this->eth_queuedTransactions(request[0u].asInt()); + } inline virtual void db_putI(const Json::Value &request, Json::Value &response) { response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString()); @@ -349,6 +364,9 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer. + */ +/** + * @author Christian R + * @date 2015 + * Unit tests for the account holder used by the WebThreeStubServer. + */ + +#include +#include + +namespace dev +{ +namespace test +{ + +BOOST_AUTO_TEST_SUITE(AccountHolderTest) + +BOOST_AUTO_TEST_CASE(ProxyAccountUseCase) +{ + AccountHolder h = AccountHolder(std::function()); + BOOST_CHECK(h.getAllAccounts().empty()); + BOOST_CHECK(h.getRealAccounts().empty()); + Address addr("abababababababababababababababababababab"); + Address addr2("abababababababababababababababababababab"); + int id = h.addProxyAccount(addr); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + // register it again + int secondID = h.addProxyAccount(addr); + BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); + + eth::TransactionSkeleton t1; + eth::TransactionSkeleton t2; + t1.from = addr; + t1.data = fromHex("12345678"); + t2.from = addr; + t2.data = fromHex("abcdef"); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + h.queueTransaction(t1); + BOOST_CHECK_EQUAL(1, h.getQueuedTransactions(id).size()); + h.queueTransaction(t2); + BOOST_REQUIRE_EQUAL(2, h.getQueuedTransactions(id).size()); + + // second proxy should not see transactions + BOOST_CHECK(h.getQueuedTransactions(secondID).empty()); + + BOOST_CHECK(h.getQueuedTransactions(id)[0].data == t1.data); + BOOST_CHECK(h.getQueuedTransactions(id)[1].data == t2.data); + + h.clearQueue(id); + BOOST_CHECK(h.getQueuedTransactions(id).empty()); + // removing fails because it never existed + BOOST_CHECK(!h.removeProxyAccount(secondID)); + BOOST_CHECK(h.removeProxyAccount(id)); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} diff --git a/test/webthreestubclient.h b/test/webthreestubclient.h index ee175b058..70aa9db99 100644 --- a/test/webthreestubclient.h +++ b/test/webthreestubclient.h @@ -447,6 +447,36 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + int eth_register(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_register",p); + if (result.isInt()) + return result.asInt(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool eth_unregister(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_unregister",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value eth_queuedTransactions(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_queuedTransactions",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; From 78d9e1be94aa49c667ef4dc47a9e379dec9c91b0 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 15:15:30 +0100 Subject: [PATCH 34/59] Renamed method. --- libweb3jsonrpc/AccountHolder.cpp | 2 +- libweb3jsonrpc/AccountHolder.h | 2 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index e12380110..a7bdc7a68 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -50,7 +50,7 @@ vector
AccountHolder::getAllAccounts() const return accounts; } -Address const& AccountHolder::getDefaultCallAccount() const +Address const& AccountHolder::getDefaultTransactAccount() const { if (m_accounts.empty()) return ZeroAddress; diff --git a/libweb3jsonrpc/AccountHolder.h b/libweb3jsonrpc/AccountHolder.h index 939947ea2..52005b51f 100644 --- a/libweb3jsonrpc/AccountHolder.h +++ b/libweb3jsonrpc/AccountHolder.h @@ -52,7 +52,7 @@ public: bool isProxyAccount(Address const& _account) const { return m_proxyAccounts.count(_account) > 0; } Secret const& secretKey(Address const& _account) const { return m_keyPairs.at(_account).secret(); } std::vector
getAllAccounts() const; - Address const& getDefaultCallAccount() const; + Address const& getDefaultTransactAccount() const; int addProxyAccount(Address const& _account); bool removeProxyAccount(unsigned _id); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index b5cc6e078..d5da8a044 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -330,7 +330,7 @@ std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts->getDefaultCallAccount(); + t.from = m_accounts->getDefaultTransactAccount(); if (!m_accounts->isRealAccount(t.from)) return ret; if (!t.gasPrice) @@ -701,7 +701,7 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) std::string ret; TransactionSkeleton t = toTransaction(_json); if (!t.from) - t.from = m_accounts->getDefaultCallAccount(); + t.from = m_accounts->getDefaultTransactAccount(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) From 954d818f30c8be9e111e248f77c042778ee07939 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 18:08:18 +0100 Subject: [PATCH 35/59] Session id as random number and authentication popup for proxies. --- alethzero/OurWebThreeStubServer.cpp | 25 +++++++++++++---------- alethzero/OurWebThreeStubServer.h | 8 ++++---- libweb3jsonrpc/AccountHolder.cpp | 18 ++++++++-------- libweb3jsonrpc/WebThreeStubServerBase.cpp | 13 ++++++------ libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 2d1dd0481..5b5ce420a 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -51,22 +51,24 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string return button == QMessageBox::Ok; } -bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) const { - return showAuthenticationPopup("Contract Creation Transaction", "ÐApp is attemping to create a contract; to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) const { - return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + +", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) const +bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) const { return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", "ÐApp is attempting to call into an unknown contract at address " + - m_main->pretty(_t.to).toStdString() + - ".\n\nCall involves sending " + + m_main->pretty(_t.to).toStdString() + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + + "Call involves sending " + formatBalance(_t.value) + " to the recipient, with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + "However, this also does other stuff which we don't understand, and does so in your name.\n\n" + @@ -76,25 +78,25 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t) "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); } -bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t) +bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) { if (_t.creation) { // recipient has no code - nothing special about this transaction, show basic value transfer info - return showCreationNotice(_t); + return showCreationNotice(_t, _toProxy); } h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); if (contractCodeHash == EmptySHA3) { // recipient has no code - nothing special about this transaction, show basic value transfer info - return showSendNotice(_t); + return showSendNotice(_t, _toProxy); } string userNotice = m_main->natSpec()->getUserNotice(contractCodeHash, _t.data); if (userNotice.empty()) - return showUnknownCallNotice(_t); + return showUnknownCallNotice(_t, _toProxy); NatspecExpressionEvaluator evaluator; userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString(); @@ -104,6 +106,7 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t) "ÐApp attempting to conduct contract interaction with " + m_main->pretty(_t.to).toStdString() + ": " + userNotice + ".\n\n" + + (_toProxy ? "This transaction is not executed directly, but forwarded to another ÐApp.\n\n" : "") + (_t.value > 0 ? "In addition, ÐApp is attempting to send " + formatBalance(_t.value) + " to said recipient, with additional network fees of up to " + diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index fbdae7d03..1ab5f813c 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -35,16 +35,16 @@ public: std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); + virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); signals: void onNewId(QString _s); private: bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; - bool showCreationNotice(dev::eth::TransactionSkeleton const& _t) const; - bool showSendNotice(dev::eth::TransactionSkeleton const& _t) const; - bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t) const; + bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; + bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; + bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; dev::WebThreeDirect* m_web3; Main* m_main; diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index a7bdc7a68..6db41cbbf 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -22,14 +22,15 @@ */ #include "AccountHolder.h" +#include +#include #include - using namespace std; using namespace dev; using namespace dev::eth; -vector emptyQueue; +vector g_emptyQueue; void AccountHolder::setAccounts(vector const& _accounts) { @@ -63,12 +64,13 @@ Address const& AccountHolder::getDefaultTransactAccount() const int AccountHolder::addProxyAccount(const Address& _account) { - int const c_id = m_transactionQueues.empty() ? 1 : m_transactionQueues.rbegin()->first + 1; - if (isProxyAccount(_account)) + static std::mt19937 s_randomNumberGenerator(time(0)); + int id = std::uniform_int_distribution(1)(s_randomNumberGenerator); + if (isProxyAccount(_account) || id == 0 || m_transactionQueues.count(id)) return 0; - m_proxyAccounts.insert(make_pair(_account, c_id)); - m_transactionQueues[c_id].first = _account; - return c_id; + m_proxyAccounts.insert(make_pair(_account, id)); + m_transactionQueues[id].first = _account; + return id; } bool AccountHolder::removeProxyAccount(unsigned _id) @@ -91,7 +93,7 @@ void AccountHolder::queueTransaction(TransactionSkeleton const& _transaction) vector const& AccountHolder::getQueuedTransactions(int _id) const { if (!m_transactionQueues.count(_id)) - return emptyQueue; + return g_emptyQueue; return m_transactionQueues.at(_id).second; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index d5da8a044..3fa22a928 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -41,6 +41,7 @@ using namespace std; using namespace dev; using namespace dev::eth; + static Json::Value toJson(dev::eth::BlockInfo const& _bi) { Json::Value res; @@ -78,7 +79,7 @@ static Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value res; res["to"] = toJS(_t.to); res["from"] = toJS(_t.from); - res["gas"] = (int)_t.gas; + res["gas"] = toJS(_t.gas); res["gasPrice"] = toJS(_t.gasPrice); res["value"] = toJS(_t.value); res["data"] = jsFromBinary(_t.data); @@ -709,13 +710,11 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) if (!m_accounts->isRealAccount(t.from)) { if (m_accounts->isProxyAccount(t.from)) - { - // todo "authenticate for proxy" - m_accounts->queueTransaction(t); - } + if (authenticate(t, true)) + m_accounts->queueTransaction(t); return ret; } - if (authenticate(t)) + if (authenticate(t, false)) { if (t.to) // TODO: from qethereum, insert validification hook here. @@ -727,7 +726,7 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) return ret; } -bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t) +bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool) { cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; return true; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 62260d11d..ed2f09d99 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -136,7 +136,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t); + virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); protected: virtual dev::eth::Interface* client() = 0; From 1c1072dff210378d97fb79bacacc338fcba505a1 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 20 Feb 2015 16:25:51 +0100 Subject: [PATCH 36/59] Thread-safe and less predictable random numbers. --- libweb3jsonrpc/AccountHolder.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libweb3jsonrpc/AccountHolder.cpp b/libweb3jsonrpc/AccountHolder.cpp index 6db41cbbf..b88397953 100644 --- a/libweb3jsonrpc/AccountHolder.cpp +++ b/libweb3jsonrpc/AccountHolder.cpp @@ -24,6 +24,7 @@ #include "AccountHolder.h" #include #include +#include #include using namespace std; @@ -31,6 +32,8 @@ using namespace dev; using namespace dev::eth; vector g_emptyQueue; +static std::mt19937 g_randomNumberGenerator(time(0)); +static Mutex x_rngMutex; void AccountHolder::setAccounts(vector const& _accounts) { @@ -64,8 +67,9 @@ Address const& AccountHolder::getDefaultTransactAccount() const int AccountHolder::addProxyAccount(const Address& _account) { - static std::mt19937 s_randomNumberGenerator(time(0)); - int id = std::uniform_int_distribution(1)(s_randomNumberGenerator); + Guard g(x_rngMutex); + int id = std::uniform_int_distribution(1)(g_randomNumberGenerator); + id = int(u256(FixedHash<32>(sha3(bytesConstRef((byte*)(&id), sizeof(int) / sizeof(byte)))))); if (isProxyAccount(_account) || id == 0 || m_transactionQueues.count(id)) return 0; m_proxyAccounts.insert(make_pair(_account, id)); From 40effa64466c1a1c96aeec01af1a49eceac5cfa4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 19:47:30 +0100 Subject: [PATCH 37/59] Trie fixes (long time coming). --- exp/main.cpp | 6 ++++-- libdevcrypto/TrieDB.h | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/exp/main.cpp b/exp/main.cpp index 80f4fa37d..23c907ed1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -33,11 +34,13 @@ #include #include #include +#include using namespace std; using namespace dev; using namespace dev::eth; using namespace dev::p2p; using namespace dev::shh; +namespace js = json_spirit; #if 0 int main() @@ -98,8 +101,7 @@ int main() #else int main() { - cnote << KeyPair(Secret("0000000000000000000000000000000000000000000000000000000000000000")).address(); - cnote << KeyPair(Secret("1111111111111111111111111111111111111111111111111111111111111111")).address(); + return 0; } #endif diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 3da63edf4..f5b7ff9c9 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -161,7 +161,7 @@ public: std::string at(bytesConstRef _key) const; void insert(bytesConstRef _key, bytesConstRef _value); void remove(bytesConstRef _key); - void contains(bytesConstRef _key) { return !at(_key).empty(); } + bool contains(bytesConstRef _key) { return !at(_key).empty(); } class iterator { @@ -809,7 +809,10 @@ template bytes GenericTrieDB::deleteAt(RLP const& _orig, NibbleSl // exactly our node - return null. if (k == _k && isLeaf(_orig)) + { + killNode(_orig); return RLPNull; + } // partial key is our key - move down. if (_k.contains(k)) @@ -917,7 +920,6 @@ template bytes GenericTrieDB::place(RLP const& _orig, NibbleSlice tdebug << "place " << _orig << _k; #endif - killNode(_orig); if (_orig.isEmpty()) return (RLPStream(2) << hexPrefixEncode(_k, true) << _s).out(); From 4323c987b77af21a5099ca9e2df1710c024d033f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:00:13 +0100 Subject: [PATCH 38/59] cppcheck fixes. --- alethzero/GraphParameters.h | 7 +++++-- alethzero/Grapher.h | 16 ++++++++-------- alethzero/MiningView.cpp | 5 ++--- alethzero/NatspecHandler.cpp | 1 - alethzero/NatspecHandler.h | 2 +- alethzero/Transact.cpp | 2 +- eth/main.cpp | 2 +- evmjit/libevmjit-cpp/Env.cpp | 2 +- libdevcore/Common.cpp | 2 +- libdevcore/Worker.h | 2 +- libdevcore/vector_ref.h | 7 ++++--- libethereum/BlockQueue.cpp | 3 +-- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 ++-- libevm/VMFace.h | 2 +- libevm/VMFactory.cpp | 2 +- libevmcore/Assembly.cpp | 6 +++--- libevmcore/Assembly.h | 2 ++ libp2p/UDP.cpp | 6 +++--- libsolidity/Token.h | 2 +- libsolidity/Types.h | 23 ++++++++++++++++------- 21 files changed, 56 insertions(+), 44 deletions(-) diff --git a/alethzero/GraphParameters.h b/alethzero/GraphParameters.h index e73061335..e1669bd21 100644 --- a/alethzero/GraphParameters.h +++ b/alethzero/GraphParameters.h @@ -37,8 +37,11 @@ static T graphParameters(T _min, T _max, unsigned _divisions, T* o_from = 0, T* T uMax = _max / _divisor; if (uMax == uMin || !_divisions) { - *o_from = 0; - *o_delta = 1; + if (o_delta && o_from) + { + *o_from = 0; + *o_delta = 1; + } return 1; } long double l10 = std::log10((uMax - uMin) / T(_divisions) * 5.5f); diff --git a/alethzero/Grapher.h b/alethzero/Grapher.h index 0f7ccd642..564fe6654 100644 --- a/alethzero/Grapher.h +++ b/alethzero/Grapher.h @@ -76,24 +76,24 @@ public: void labelYOrderedPoints(std::map const& _translatedData, int _maxCount = 20, float _minFactor = .01f) const; protected: - QPainter* p; + QPainter* p = nullptr; QRect active; std::pair xRange; std::pair yRange; - float xM; - float xC; - float yM; - float yC; + float xM = 0; + float xC = 0; + float yM = 0; + float yC = 0; - float dx; - float dy; + float dx = 0; + float dy = 0; std::function xLabel; std::function yLabel; std::function pLabel; - float fontPixelSize; + float fontPixelSize = 0; // Translate from raw indexed data into x/y graph units. Only relevant for indexed data. float xT(float _dataIndex) const { return _dataIndex * xM + xC; } diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index fa6da737b..63d1fcf99 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -48,7 +48,6 @@ string sL(float _x, float _y) { return toString(round(_x * 1000)) + "s (" + toSt MiningView::MiningView(QWidget* _p): QWidget(_p) { - } void MiningView::appendStats(list const& _i, MineProgress const& _p) @@ -86,10 +85,10 @@ void MiningView::appendStats(list const& _i, MineProgress const& _p) for (auto& i: m_resets) i -= o; - remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}); + m_resets.erase(remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}), m_resets.end()); for (auto& i: m_completes) i -= o; - remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}); + m_completes.erase(remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}), m_completes.end()); m_progress = _p; update(); diff --git a/alethzero/NatspecHandler.cpp b/alethzero/NatspecHandler.cpp index bfdbaa178..27cf00341 100644 --- a/alethzero/NatspecHandler.cpp +++ b/alethzero/NatspecHandler.cpp @@ -66,7 +66,6 @@ string NatspecHandler::getUserNotice(string const& json, dev::bytes const& _tran { Json::Value natspec; Json::Value userNotice; - string retStr; m_reader.parse(json, natspec); FixedHash<4> transactionFunctionHash((bytesConstRef(&_transactionData).cropped(0, 4).toBytes())); diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 15ceb7b0b..7aeafec41 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -54,6 +54,6 @@ class NatspecHandler: public NatSpecFace private: ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; - ldb::DB* m_db; + ldb::DB* m_db = nullptr; Json::Reader m_reader; }; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index bfeb41d9a..1b9a62a2d 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -202,7 +202,7 @@ void Transact::rejigData() for (auto& i: errors) i = "(LLL " + i + ")"; } - catch (string err) + catch (string const& err) { errors.push_back("Serpent " + err); } diff --git a/eth/main.cpp b/eth/main.cpp index f17817fbf..fbf47a69c 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -749,7 +749,7 @@ int main(int argc, char** argv) else if (format == "standard+") oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { - dev::eth::VM* vm = (VM*)vvm; + dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) for (auto const& i: ext->state().storage(ext->myAddress)) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index f89897792..228f637e8 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -70,7 +70,7 @@ extern "C" _env->subBalance(value); auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; - auto outRef = bytesConstRef{_outBeg, _outSize}; + auto outRef = bytesRef{_outBeg, _outSize}; OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); auto gas = llvm2eth(*io_gas); diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 365f65202..431a95580 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.8.1"; +char const* Version = "0.8.2"; } diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index f73a0f4aa..40bc118aa 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -64,7 +64,7 @@ protected: private: std::string m_name; - unsigned m_idleWaitMs; + unsigned m_idleWaitMs = 0; mutable Mutex x_work; ///< Lock for the network existance. std::unique_ptr m_work; ///< The network thread. diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 9039c3149..42633f6f1 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -19,7 +19,7 @@ public: vector_ref(): m_data(nullptr), m_count(0) {} vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {} - vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data((_T*)_data->data()), m_count(_data->size() / sizeof(_T)) {} + vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {} vector_ref(typename std::conditional::value, std::vector::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {} #ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ @@ -29,9 +29,10 @@ public: bool contentsEqual(std::vector const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); } std::vector toVector() const { return std::vector(m_data, m_data + m_count); } - std::vector toBytes() const { return std::vector((unsigned char const*)m_data, (unsigned char const*)m_data + m_count * sizeof(_T)); } + std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(_T)); } std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); } - template operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>((_T2*)m_data, m_count * sizeof(_T) / sizeof(_T2)); } + template explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); } + operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); } _T* data() const { return m_data; } size_t count() const { return m_count; } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index bb5055104..01c8c796c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -59,7 +59,6 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) catch (Exception const& _e) { cwarn << "Ignoring malformed block: " << diagnostic_information(_e); - return false; return ImportResult::Malformed; } #endif @@ -128,7 +127,7 @@ void BlockQueue::drain(std::vector& o_out) void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) { list goodQueue(1, _good); - while (goodQueue.size()) + while (!goodQueue.empty()) { auto r = m_unknown.equal_range(goodQueue.front()); goodQueue.pop_front(); diff --git a/libethereum/Client.h b/libethereum/Client.h index f4ab5ce76..7cd520ab6 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -127,7 +127,7 @@ template struct ABIDeserialiser {}; template struct ABIDeserialiser> { static FixedHash deserialise(bytesConstRef& io_t) { static_assert(N <= 32, "Parameter sizes must be at most 32 bytes."); FixedHash ret; io_t.cropped(32 - N, N).populate(ret.ref()); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u256 deserialise(bytesConstRef& io_t) { u256 ret = fromBigEndian(io_t.cropped(0, 32)); io_t = io_t.cropped(32); return ret; } }; template <> struct ABIDeserialiser { static u160 deserialise(bytesConstRef& io_t) { u160 ret = fromBigEndian(io_t.cropped(12, 20)); io_t = io_t.cropped(32); return ret; } }; -template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(vector_ref(ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; +template <> struct ABIDeserialiser { static string32 deserialise(bytesConstRef& io_t) { string32 ret; io_t.cropped(0, 32).populate(bytesRef((byte*)ret.data(), 32)); io_t = io_t.cropped(32); return ret; } }; template T abiOut(bytes const& _data) { diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 5b9da0cdd..21fa62676 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1199,11 +1199,11 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) else if (j.second) cached.insert(j.first); } - if (delta.size()) + if (!delta.empty()) lead = (lead == " . ") ? "*.* " : "*** "; contout << " @:"; - if (delta.size()) + if (!delta.empty()) contout << "???"; else contout << r[2].toHash(); diff --git a/libevm/VMFace.h b/libevm/VMFace.h index 44ae03868..f8c20feb1 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -40,7 +40,7 @@ public: explicit VMFace(u256 _gas): m_gas(_gas) {} virtual ~VMFace() = default; VMFace(VMFace const&) = delete; - void operator=(VMFace const&) = delete; + VMFace& operator=(VMFace const&) = delete; virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } u256 gas() const noexcept { return m_gas; } diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index b6549ba04..40f8a3500 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -39,7 +39,7 @@ void VMFactory::setKind(VMKind _kind) std::unique_ptr VMFactory::create(u256 _gas) { #if ETH_EVMJIT - return std::unique_ptr(g_kind == VMKind::JIT ? (VMFace*)new JitVM(_gas) : new VM(_gas)); + return std::unique_ptr(g_kind == VMKind::JIT ? static_cast(new JitVM(_gas)) : static_cast(new VM(_gas))); #else asserts(g_kind == VMKind::Interpreter && "JIT disabled in build configuration"); return std::unique_ptr(new VM(_gas)); diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index 889865d9f..b3cb191b7 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -214,7 +214,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix) const BOOST_THROW_EXCEPTION(InvalidOpcode()); } - if (m_data.size() || m_subs.size()) + if (!m_data.empty() || !m_subs.empty()) { _out << _prefix << ".data:" << endl; for (auto const& i: m_data) @@ -441,7 +441,7 @@ Assembly& Assembly::optimise(bool _enable) if (i.type() == PushTag) tags.erase(i.data()); - if (tags.size()) + if (tags.empty()) { auto t = *tags.begin(); unsigned i = t.second; @@ -567,7 +567,7 @@ bytes Assembly::assemble() const toBigEndian(tagPos[i.second], r); } - if (m_data.size()) + if (!m_data.empty()) { ret.push_back(0); for (auto const& i: m_data) diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 9d9e4093c..ffe13b34d 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -72,6 +72,8 @@ inline std::ostream& operator<<(std::ostream& _out, AssemblyItems const& _i) { r class Assembly { public: + Assembly() {} + AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index e27b6e57a..5d9cdab79 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -38,9 +38,9 @@ h256 RLPXDatagramFace::sign(Secret const& _k) Signature sig = dev::sign(_k, sighash); // S(H(type||data)) data.resize(h256::size + Signature::size + rlpx.size()); - bytesConstRef rlpxHash(&data[0], h256::size); - bytesConstRef rlpxSig(&data[h256::size], Signature::size); - bytesConstRef rlpxPayload(&data[h256::size + Signature::size], rlpx.size()); + bytesRef rlpxHash(&data[0], h256::size); + bytesRef rlpxSig(&data[h256::size], Signature::size); + bytesRef rlpxPayload(&data[h256::size + Signature::size], rlpx.size()); sig.ref().copyTo(rlpxSig); rlpx.copyTo(rlpxPayload); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index e9765e5eb..4aa000475 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -372,7 +372,7 @@ public: static Value AssignmentToBinaryOp(Value op) { solAssert(isAssignmentOp(op) && op != Assign, ""); - return Token::Value(op + (BitOr - AssignBitOr)); + return Value(op + (BitOr - AssignBitOr)); } static bool isBitOp(Value op) { return (BitOr <= op && op <= SHR) || op == BitNot; } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index d529d8d08..af64f1cb5 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -430,12 +430,21 @@ public: Location _location = Location::Internal, bool _arbitraryParameters = false): FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), _location, _arbitraryParameters) {} - FunctionType(TypePointers const& _parameterTypes, TypePointers const& _returnParameterTypes, - Location _location = Location::Internal, - bool _arbitraryParameters = false, bool _gasSet = false, bool _valueSet = false): - m_parameterTypes(_parameterTypes), m_returnParameterTypes(_returnParameterTypes), - m_location(_location), - m_arbitraryParameters(_arbitraryParameters), m_gasSet(_gasSet), m_valueSet(_valueSet) {} + FunctionType( + TypePointers const& _parameterTypes, + TypePointers const& _returnParameterTypes, + Location _location = Location::Internal, + bool _arbitraryParameters = false, + bool _gasSet = false, + bool _valueSet = false + ): + m_parameterTypes (_parameterTypes), + m_returnParameterTypes (_returnParameterTypes), + m_location (_location), + m_arbitraryParameters (_arbitraryParameters), + m_gasSet (_gasSet), + m_valueSet (_valueSet) + {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } std::vector const& getParameterNames() const { return m_parameterNames; } @@ -490,7 +499,7 @@ private: bool const m_arbitraryParameters = false; bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack bool const m_valueSet = false; ///< true iff the value to be sent is on the stack - bool m_isConstant; + bool m_isConstant = false; mutable std::unique_ptr m_members; Declaration const* m_declaration = nullptr; }; From 03a9bc31fa2c047ec2944483dd957eadb16345db Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:06:13 +0100 Subject: [PATCH 39/59] Minor fix. --- libevmcore/Assembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmcore/Assembly.cpp b/libevmcore/Assembly.cpp index b3cb191b7..37c3ff18d 100644 --- a/libevmcore/Assembly.cpp +++ b/libevmcore/Assembly.cpp @@ -441,7 +441,7 @@ Assembly& Assembly::optimise(bool _enable) if (i.type() == PushTag) tags.erase(i.data()); - if (tags.empty()) + if (!tags.empty()) { auto t = *tags.begin(); unsigned i = t.second; From e185d9a117465a0b792144a99554947aede00eaa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:59:21 +0100 Subject: [PATCH 40/59] Add EVMJIT. --- evmjit/.gitignore | 1 + evmjit/CMakeLists.txt | 44 + evmjit/LICENSE.md | 21 + evmjit/README.md | 43 + evmjit/evmcc/CMakeLists.txt | 18 + evmjit/evmcc/evmcc.cpp | 210 ++++ evmjit/evmcc/test/arith/addmod.evm | 1 + evmjit/evmcc/test/arith/addmod.lll | 12 + evmjit/evmcc/test/arith/arith1.evm | 1 + evmjit/evmcc/test/arith/arith1.lll | 37 + evmjit/evmcc/test/arith/arith_bnot.evm | 1 + evmjit/evmcc/test/arith/arith_bnot.lll | 14 + evmjit/evmcc/test/arith/div.evm | 1 + evmjit/evmcc/test/arith/div.lll | 10 + evmjit/evmcc/test/arith/fib1.evm | 1 + evmjit/evmcc/test/arith/fib1.lll | 57 ++ evmjit/evmcc/test/arith/mul.evm | 1 + evmjit/evmcc/test/arith/mul.lll | 13 + evmjit/evmcc/test/arith/mulmod.evm | 1 + evmjit/evmcc/test/arith/mulmod.lll | 12 + evmjit/evmcc/test/except/badinst1.evm | 1 + evmjit/evmcc/test/ext/calldatacopy1.evm | 1 + evmjit/evmcc/test/ext/calldatacopy1.lll | 13 + evmjit/evmcc/test/ext/calldatacopy2.evm | 1 + evmjit/evmcc/test/ext/calldatacopy2.lll | 13 + evmjit/evmcc/test/ext/codecopy1.evm | 1 + evmjit/evmcc/test/ext/codecopy1.lll | 13 + evmjit/evmcc/test/ext/codecopy2.evm | 1 + evmjit/evmcc/test/ext/codecopy2.lll | 13 + evmjit/evmcc/test/ext/codecopy3.evm | 1 + evmjit/evmcc/test/ext/codecopy3.lll | 13 + evmjit/evmcc/test/ext/ext_test.evm | 1 + evmjit/evmcc/test/ext/ext_test.lll | 55 + evmjit/evmcc/test/ext/extcodecopy1.evm | 1 + evmjit/evmcc/test/ext/extcodecopy1.lll | 11 + evmjit/evmcc/test/ext/store_delete.evm | 1 + evmjit/evmcc/test/ext/store_delete.lll | 9 + evmjit/evmcc/test/ext/store_test.evm | 1 + evmjit/evmcc/test/ext/store_test.lll | 14 + evmjit/evmcc/test/jump/ackermann.ethel | 7 + evmjit/evmcc/test/jump/ackermann.evm | 1 + evmjit/evmcc/test/jump/badindirect1.evm | 1 + evmjit/evmcc/test/jump/badindirect1.lll | 9 + evmjit/evmcc/test/jump/badindirect2.evm | 1 + evmjit/evmcc/test/jump/badindirect2.lll | 12 + evmjit/evmcc/test/jump/badjump1.evm | 1 + evmjit/evmcc/test/jump/badjump1.lll | 6 + evmjit/evmcc/test/jump/badjump2.evm | 1 + evmjit/evmcc/test/jump/badjump2.lll | 9 + evmjit/evmcc/test/jump/call1.ethel | 5 + evmjit/evmcc/test/jump/call1.evm | 1 + evmjit/evmcc/test/jump/call2.ethel | 5 + evmjit/evmcc/test/jump/call2.evm | 1 + evmjit/evmcc/test/jump/fac.ethel | 5 + evmjit/evmcc/test/jump/fac.evm | 1 + evmjit/evmcc/test/jump/fac_tail.ethel | 5 + evmjit/evmcc/test/jump/fac_tail.evm | 1 + evmjit/evmcc/test/jump/fib1.ethel | 6 + evmjit/evmcc/test/jump/fib1.evm | 1 + evmjit/evmcc/test/jump/for1.evm | 1 + evmjit/evmcc/test/jump/for1.lll | 3 + evmjit/evmcc/test/jump/for2.evm | 1 + evmjit/evmcc/test/jump/for2.lll | 3 + evmjit/evmcc/test/jump/if1.ethel | 1 + evmjit/evmcc/test/jump/if1.evm | 1 + evmjit/evmcc/test/jump/if2.ethel | 1 + evmjit/evmcc/test/jump/if2.evm | 1 + evmjit/evmcc/test/jump/indirect1.evm | 1 + evmjit/evmcc/test/jump/indirect1.lll | 13 + evmjit/evmcc/test/jump/indirect2.evm | 1 + evmjit/evmcc/test/jump/indirect2.lll | 19 + evmjit/evmcc/test/jump/indirect3.evm | 1 + evmjit/evmcc/test/jump/indirect3.lll | 14 + evmjit/evmcc/test/jump/indirect4.evm | 1 + evmjit/evmcc/test/jump/indirect4.lll | 15 + evmjit/evmcc/test/jump/jump1.evm | 1 + evmjit/evmcc/test/jump/jump1.lll | 11 + evmjit/evmcc/test/jump/jump2.evm | 1 + evmjit/evmcc/test/jump/jump2.lll | 10 + evmjit/evmcc/test/jump/jump3.evm | 1 + evmjit/evmcc/test/jump/jump3.lll | 10 + evmjit/evmcc/test/jump/jump4.evm | 1 + evmjit/evmcc/test/jump/jump4.lll | 17 + evmjit/evmcc/test/jump/jump5.evm | 1 + evmjit/evmcc/test/jump/jump5.lll | 16 + evmjit/evmcc/test/jump/jump6.evm | 1 + evmjit/evmcc/test/jump/jump6.lll | 32 + evmjit/evmcc/test/jump/jumpi_at_the_end.evm | 1 + evmjit/evmcc/test/jump/jumpi_at_the_end.lll | 1 + evmjit/evmcc/test/jump/loop1.evm | 1 + evmjit/evmcc/test/jump/loop1.lll | 27 + evmjit/evmcc/test/jump/loop2.evm | 1 + evmjit/evmcc/test/jump/loop2.lll | 28 + evmjit/evmcc/test/jump/rec1.ethel | 4 + evmjit/evmcc/test/jump/rec1.evm | 1 + evmjit/evmcc/test/jump/when1.asm | 10 + evmjit/evmcc/test/jump/when1.evm | 1 + evmjit/evmcc/test/jump/when1.lll | 2 + evmjit/evmcc/test/kv.evm | 1 + evmjit/evmcc/test/kv.lll | 10 + evmjit/evmcc/test/mem/byte.evm | 1 + evmjit/evmcc/test/mem/byte.lll | 105 ++ evmjit/evmcc/test/mem/mem2.evm | 1 + evmjit/evmcc/test/mem/mem2.lll | 15 + evmjit/evmcc/test/mem/memtest1.evm | 1 + evmjit/evmcc/test/mem/memtest1.lll | 18 + evmjit/evmcc/test/mem/mstore1.evm | 1 + evmjit/evmcc/test/mem/mstore1.lll | 6 + evmjit/evmcc/test/ret/return1.evm | 1 + evmjit/evmcc/test/ret/return1.lll | 6 + evmjit/evmcc/test/ret/return2.evm | 1 + evmjit/evmcc/test/ret/return2.lll | 6 + evmjit/evmcc/test/ret/return_test.evm | 1 + evmjit/evmcc/test/ret/return_test.lll | 15 + evmjit/evmcc/test/stack/oos.evm | 1 + evmjit/evmcc/test/stack/oos.lll | 11 + evmjit/evmcc/test/stack/push_test.evm | 1 + evmjit/evmcc/test/stack/push_test.lll | 35 + evmjit/evmcc/test/stack/stack_test.evm | 1 + evmjit/evmcc/test/stack/stack_test.lll | 8 + evmjit/evmcc/test/stack/stackjump.evm | 1 + evmjit/evmcc/test/stack/stackjump.lll | 3 + evmjit/evmcc/test/stack/swap.evm | 1 + evmjit/evmcc/test/stack/swap.lll | 31 + evmjit/evmcc/test/stack/swapswap.evm | 1 + evmjit/evmcc/test/stack/swapswap.lll | 32 + evmjit/evmcc/test/stack/test.evm | 1 + .../test/vmtests/vmArithPerformanceTest.json | 260 +++++ .../evmcc/test/vmtests/vmPerformanceTest.json | 214 ++++ evmjit/evmcc/test/vmtests/vm_jump.json | 41 + evmjit/libevmjit-cpp/CMakeLists.txt | 24 + evmjit/libevmjit-cpp/Env.cpp | 117 +++ evmjit/libevmjit-cpp/JitVM.cpp | 83 ++ evmjit/libevmjit-cpp/JitVM.h | 26 + evmjit/libevmjit-cpp/Utils.h | 38 + evmjit/libevmjit/Arith256.cpp | 406 ++++++++ evmjit/libevmjit/Arith256.h | 47 + evmjit/libevmjit/BasicBlock.cpp | 381 +++++++ evmjit/libevmjit/BasicBlock.h | 126 +++ evmjit/libevmjit/BuildInfo.h.in | 10 + evmjit/libevmjit/CMakeLists.txt | 68 ++ evmjit/libevmjit/Cache.cpp | 120 +++ evmjit/libevmjit/Cache.h | 38 + evmjit/libevmjit/Common.h | 65 ++ evmjit/libevmjit/Compiler.cpp | 965 ++++++++++++++++++ evmjit/libevmjit/Compiler.h | 80 ++ evmjit/libevmjit/CompilerHelper.cpp | 51 + evmjit/libevmjit/CompilerHelper.h | 79 ++ evmjit/libevmjit/Endianness.cpp | 39 + evmjit/libevmjit/Endianness.h | 25 + evmjit/libevmjit/ExecStats.cpp | 97 ++ evmjit/libevmjit/ExecStats.h | 43 + evmjit/libevmjit/ExecutionEngine.cpp | 153 +++ evmjit/libevmjit/ExecutionEngine.h | 60 ++ evmjit/libevmjit/Ext.cpp | 192 ++++ evmjit/libevmjit/Ext.h | 81 ++ evmjit/libevmjit/GasMeter.cpp | 231 +++++ evmjit/libevmjit/GasMeter.h | 63 ++ evmjit/libevmjit/Instruction.cpp | 42 + evmjit/libevmjit/Instruction.h | 239 +++++ evmjit/libevmjit/Memory.cpp | 260 +++++ evmjit/libevmjit/Memory.h | 49 + evmjit/libevmjit/Runtime.cpp | 34 + evmjit/libevmjit/Runtime.h | 40 + evmjit/libevmjit/RuntimeData.h | 60 ++ evmjit/libevmjit/RuntimeManager.cpp | 242 +++++ evmjit/libevmjit/RuntimeManager.h | 60 ++ evmjit/libevmjit/Stack.cpp | 200 ++++ evmjit/libevmjit/Stack.h | 44 + evmjit/libevmjit/Type.cpp | 70 ++ evmjit/libevmjit/Type.h | 60 ++ evmjit/libevmjit/Utils.cpp | 13 + evmjit/libevmjit/Utils.h | 24 + evmjit/libevmjit/interface.cpp | 40 + evmjit/libevmjit/interface.h | 13 + .../preprocessor/llvm_includes_end.h | 5 + .../preprocessor/llvm_includes_start.h | 8 + 177 files changed, 7040 insertions(+) create mode 100644 evmjit/.gitignore create mode 100644 evmjit/CMakeLists.txt create mode 100644 evmjit/LICENSE.md create mode 100644 evmjit/README.md create mode 100644 evmjit/evmcc/CMakeLists.txt create mode 100644 evmjit/evmcc/evmcc.cpp create mode 100644 evmjit/evmcc/test/arith/addmod.evm create mode 100644 evmjit/evmcc/test/arith/addmod.lll create mode 100644 evmjit/evmcc/test/arith/arith1.evm create mode 100644 evmjit/evmcc/test/arith/arith1.lll create mode 100644 evmjit/evmcc/test/arith/arith_bnot.evm create mode 100644 evmjit/evmcc/test/arith/arith_bnot.lll create mode 100644 evmjit/evmcc/test/arith/div.evm create mode 100644 evmjit/evmcc/test/arith/div.lll create mode 100644 evmjit/evmcc/test/arith/fib1.evm create mode 100644 evmjit/evmcc/test/arith/fib1.lll create mode 100644 evmjit/evmcc/test/arith/mul.evm create mode 100644 evmjit/evmcc/test/arith/mul.lll create mode 100644 evmjit/evmcc/test/arith/mulmod.evm create mode 100644 evmjit/evmcc/test/arith/mulmod.lll create mode 100644 evmjit/evmcc/test/except/badinst1.evm create mode 100644 evmjit/evmcc/test/ext/calldatacopy1.evm create mode 100644 evmjit/evmcc/test/ext/calldatacopy1.lll create mode 100644 evmjit/evmcc/test/ext/calldatacopy2.evm create mode 100644 evmjit/evmcc/test/ext/calldatacopy2.lll create mode 100644 evmjit/evmcc/test/ext/codecopy1.evm create mode 100644 evmjit/evmcc/test/ext/codecopy1.lll create mode 100644 evmjit/evmcc/test/ext/codecopy2.evm create mode 100644 evmjit/evmcc/test/ext/codecopy2.lll create mode 100644 evmjit/evmcc/test/ext/codecopy3.evm create mode 100644 evmjit/evmcc/test/ext/codecopy3.lll create mode 100644 evmjit/evmcc/test/ext/ext_test.evm create mode 100644 evmjit/evmcc/test/ext/ext_test.lll create mode 100644 evmjit/evmcc/test/ext/extcodecopy1.evm create mode 100644 evmjit/evmcc/test/ext/extcodecopy1.lll create mode 100644 evmjit/evmcc/test/ext/store_delete.evm create mode 100644 evmjit/evmcc/test/ext/store_delete.lll create mode 100644 evmjit/evmcc/test/ext/store_test.evm create mode 100644 evmjit/evmcc/test/ext/store_test.lll create mode 100644 evmjit/evmcc/test/jump/ackermann.ethel create mode 100644 evmjit/evmcc/test/jump/ackermann.evm create mode 100644 evmjit/evmcc/test/jump/badindirect1.evm create mode 100644 evmjit/evmcc/test/jump/badindirect1.lll create mode 100644 evmjit/evmcc/test/jump/badindirect2.evm create mode 100644 evmjit/evmcc/test/jump/badindirect2.lll create mode 100644 evmjit/evmcc/test/jump/badjump1.evm create mode 100644 evmjit/evmcc/test/jump/badjump1.lll create mode 100644 evmjit/evmcc/test/jump/badjump2.evm create mode 100644 evmjit/evmcc/test/jump/badjump2.lll create mode 100644 evmjit/evmcc/test/jump/call1.ethel create mode 100644 evmjit/evmcc/test/jump/call1.evm create mode 100644 evmjit/evmcc/test/jump/call2.ethel create mode 100644 evmjit/evmcc/test/jump/call2.evm create mode 100644 evmjit/evmcc/test/jump/fac.ethel create mode 100644 evmjit/evmcc/test/jump/fac.evm create mode 100644 evmjit/evmcc/test/jump/fac_tail.ethel create mode 100644 evmjit/evmcc/test/jump/fac_tail.evm create mode 100644 evmjit/evmcc/test/jump/fib1.ethel create mode 100644 evmjit/evmcc/test/jump/fib1.evm create mode 100644 evmjit/evmcc/test/jump/for1.evm create mode 100644 evmjit/evmcc/test/jump/for1.lll create mode 100644 evmjit/evmcc/test/jump/for2.evm create mode 100644 evmjit/evmcc/test/jump/for2.lll create mode 100644 evmjit/evmcc/test/jump/if1.ethel create mode 100644 evmjit/evmcc/test/jump/if1.evm create mode 100644 evmjit/evmcc/test/jump/if2.ethel create mode 100644 evmjit/evmcc/test/jump/if2.evm create mode 100644 evmjit/evmcc/test/jump/indirect1.evm create mode 100644 evmjit/evmcc/test/jump/indirect1.lll create mode 100644 evmjit/evmcc/test/jump/indirect2.evm create mode 100644 evmjit/evmcc/test/jump/indirect2.lll create mode 100644 evmjit/evmcc/test/jump/indirect3.evm create mode 100644 evmjit/evmcc/test/jump/indirect3.lll create mode 100644 evmjit/evmcc/test/jump/indirect4.evm create mode 100644 evmjit/evmcc/test/jump/indirect4.lll create mode 100644 evmjit/evmcc/test/jump/jump1.evm create mode 100644 evmjit/evmcc/test/jump/jump1.lll create mode 100644 evmjit/evmcc/test/jump/jump2.evm create mode 100644 evmjit/evmcc/test/jump/jump2.lll create mode 100644 evmjit/evmcc/test/jump/jump3.evm create mode 100644 evmjit/evmcc/test/jump/jump3.lll create mode 100644 evmjit/evmcc/test/jump/jump4.evm create mode 100644 evmjit/evmcc/test/jump/jump4.lll create mode 100644 evmjit/evmcc/test/jump/jump5.evm create mode 100644 evmjit/evmcc/test/jump/jump5.lll create mode 100644 evmjit/evmcc/test/jump/jump6.evm create mode 100644 evmjit/evmcc/test/jump/jump6.lll create mode 100644 evmjit/evmcc/test/jump/jumpi_at_the_end.evm create mode 100644 evmjit/evmcc/test/jump/jumpi_at_the_end.lll create mode 100644 evmjit/evmcc/test/jump/loop1.evm create mode 100644 evmjit/evmcc/test/jump/loop1.lll create mode 100644 evmjit/evmcc/test/jump/loop2.evm create mode 100644 evmjit/evmcc/test/jump/loop2.lll create mode 100644 evmjit/evmcc/test/jump/rec1.ethel create mode 100644 evmjit/evmcc/test/jump/rec1.evm create mode 100644 evmjit/evmcc/test/jump/when1.asm create mode 100644 evmjit/evmcc/test/jump/when1.evm create mode 100644 evmjit/evmcc/test/jump/when1.lll create mode 100644 evmjit/evmcc/test/kv.evm create mode 100644 evmjit/evmcc/test/kv.lll create mode 100644 evmjit/evmcc/test/mem/byte.evm create mode 100644 evmjit/evmcc/test/mem/byte.lll create mode 100644 evmjit/evmcc/test/mem/mem2.evm create mode 100644 evmjit/evmcc/test/mem/mem2.lll create mode 100644 evmjit/evmcc/test/mem/memtest1.evm create mode 100644 evmjit/evmcc/test/mem/memtest1.lll create mode 100644 evmjit/evmcc/test/mem/mstore1.evm create mode 100644 evmjit/evmcc/test/mem/mstore1.lll create mode 100644 evmjit/evmcc/test/ret/return1.evm create mode 100644 evmjit/evmcc/test/ret/return1.lll create mode 100644 evmjit/evmcc/test/ret/return2.evm create mode 100644 evmjit/evmcc/test/ret/return2.lll create mode 100644 evmjit/evmcc/test/ret/return_test.evm create mode 100644 evmjit/evmcc/test/ret/return_test.lll create mode 100644 evmjit/evmcc/test/stack/oos.evm create mode 100644 evmjit/evmcc/test/stack/oos.lll create mode 100644 evmjit/evmcc/test/stack/push_test.evm create mode 100644 evmjit/evmcc/test/stack/push_test.lll create mode 100644 evmjit/evmcc/test/stack/stack_test.evm create mode 100644 evmjit/evmcc/test/stack/stack_test.lll create mode 100644 evmjit/evmcc/test/stack/stackjump.evm create mode 100644 evmjit/evmcc/test/stack/stackjump.lll create mode 100644 evmjit/evmcc/test/stack/swap.evm create mode 100644 evmjit/evmcc/test/stack/swap.lll create mode 100644 evmjit/evmcc/test/stack/swapswap.evm create mode 100644 evmjit/evmcc/test/stack/swapswap.lll create mode 100644 evmjit/evmcc/test/stack/test.evm create mode 100644 evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json create mode 100644 evmjit/evmcc/test/vmtests/vmPerformanceTest.json create mode 100644 evmjit/evmcc/test/vmtests/vm_jump.json create mode 100644 evmjit/libevmjit-cpp/CMakeLists.txt create mode 100644 evmjit/libevmjit-cpp/Env.cpp create mode 100644 evmjit/libevmjit-cpp/JitVM.cpp create mode 100644 evmjit/libevmjit-cpp/JitVM.h create mode 100644 evmjit/libevmjit-cpp/Utils.h create mode 100644 evmjit/libevmjit/Arith256.cpp create mode 100644 evmjit/libevmjit/Arith256.h create mode 100644 evmjit/libevmjit/BasicBlock.cpp create mode 100644 evmjit/libevmjit/BasicBlock.h create mode 100644 evmjit/libevmjit/BuildInfo.h.in create mode 100644 evmjit/libevmjit/CMakeLists.txt create mode 100644 evmjit/libevmjit/Cache.cpp create mode 100644 evmjit/libevmjit/Cache.h create mode 100644 evmjit/libevmjit/Common.h create mode 100644 evmjit/libevmjit/Compiler.cpp create mode 100644 evmjit/libevmjit/Compiler.h create mode 100644 evmjit/libevmjit/CompilerHelper.cpp create mode 100644 evmjit/libevmjit/CompilerHelper.h create mode 100644 evmjit/libevmjit/Endianness.cpp create mode 100644 evmjit/libevmjit/Endianness.h create mode 100644 evmjit/libevmjit/ExecStats.cpp create mode 100644 evmjit/libevmjit/ExecStats.h create mode 100644 evmjit/libevmjit/ExecutionEngine.cpp create mode 100644 evmjit/libevmjit/ExecutionEngine.h create mode 100644 evmjit/libevmjit/Ext.cpp create mode 100644 evmjit/libevmjit/Ext.h create mode 100644 evmjit/libevmjit/GasMeter.cpp create mode 100644 evmjit/libevmjit/GasMeter.h create mode 100644 evmjit/libevmjit/Instruction.cpp create mode 100644 evmjit/libevmjit/Instruction.h create mode 100644 evmjit/libevmjit/Memory.cpp create mode 100644 evmjit/libevmjit/Memory.h create mode 100644 evmjit/libevmjit/Runtime.cpp create mode 100644 evmjit/libevmjit/Runtime.h create mode 100644 evmjit/libevmjit/RuntimeData.h create mode 100644 evmjit/libevmjit/RuntimeManager.cpp create mode 100644 evmjit/libevmjit/RuntimeManager.h create mode 100644 evmjit/libevmjit/Stack.cpp create mode 100644 evmjit/libevmjit/Stack.h create mode 100644 evmjit/libevmjit/Type.cpp create mode 100644 evmjit/libevmjit/Type.h create mode 100644 evmjit/libevmjit/Utils.cpp create mode 100644 evmjit/libevmjit/Utils.h create mode 100644 evmjit/libevmjit/interface.cpp create mode 100644 evmjit/libevmjit/interface.h create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_end.h create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_start.h diff --git a/evmjit/.gitignore b/evmjit/.gitignore new file mode 100644 index 000000000..84c048a73 --- /dev/null +++ b/evmjit/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt new file mode 100644 index 000000000..14fca2cde --- /dev/null +++ b/evmjit/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(evmjit) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set(CMAKE_AUTOMOC OFF) + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas") +endif() + +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + # Do not allow unresovled symbols in shared library (default on linux) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") +endif() + +# LLVM +if(LLVM_DIR OR APPLE) # local LLVM build + find_package(LLVM REQUIRED CONFIG) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + add_definitions(${LLVM_DEFINITIONS}) + # TODO: bitwriter is needed only for evmcc + llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter) +else() + # Workaround for Ubuntu broken LLVM package + message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") + execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS) + message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") + set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") + add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) + link_directories(/usr/lib/llvm-3.5/lib) +endif() + +add_subdirectory(libevmjit) + +if(EVMJIT_CPP) + add_subdirectory(libevmjit-cpp) +endif() + +if(EVMJIT_TOOLS) + add_subdirectory(evmcc) +endif() diff --git a/evmjit/LICENSE.md b/evmjit/LICENSE.md new file mode 100644 index 000000000..630157f98 --- /dev/null +++ b/evmjit/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paweł Bylica + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/evmjit/README.md b/evmjit/README.md new file mode 100644 index 000000000..a480e83dc --- /dev/null +++ b/evmjit/README.md @@ -0,0 +1,43 @@ +# The Ethereum EVM JIT + +EVM JIT is a library for just-in-time compilation of Ethereum EVM code. +It can be used to substitute classic interpreter-like EVM Virtual Machine in Ethereum client. + +## Build + +### Linux / Ubuntu + +1. Install llvm-3.5-dev package + 1. For Ubuntu 14.04 using LLVM deb packages source: http://llvm.org/apt + 2. For Ubuntu 14.10 using Ubuntu packages +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake .. && make` +3. Install library + 1. `sudo make install` + 2. `sudo ldconfig` + +### OSX + +1. Install llvm35 + 1. `brew install llvm35 --disable-shared --HEAD` +2. Build library with cmake + 1. `mkdir build && cd $_` + 2. `cmake -DLLVM_DIR=/usr/local/lib/llvm-3.5/share/llvm/cmake .. && make` +3. Install library + 1. `make install` (with admin rights?) + +### Windows + +Ask me. + +## Options + +Options to evmjit library can be passed by environmental variables, e.g. `EVMJIT_CACHE=0 testeth --jit`. + +Option | Default value | Description +------------- | ------------- | ---------------------------------------------- +EVMJIT_CACHE | 1 | Enables on disk cache for compiled EVM objects +EVMJIT_DUMP | 0 | Dumps generated LLVM module to standard output + + diff --git a/evmjit/evmcc/CMakeLists.txt b/evmjit/evmcc/CMakeLists.txt new file mode 100644 index 000000000..4ffbf5fb5 --- /dev/null +++ b/evmjit/evmcc/CMakeLists.txt @@ -0,0 +1,18 @@ +set(TARGET_NAME evmcc) + +set(SOURCES + evmcc.cpp +) +source_group("" FILES ${SOURCES}) + +add_executable(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "tools") + +include_directories(../..) +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(${TARGET_NAME} ethereum) +target_link_libraries(${TARGET_NAME} ${Boost_PROGRAM_OPTIONS_LIBRARIES}) + +install(TARGETS ${TARGET_NAME} DESTINATION bin ) \ No newline at end of file diff --git a/evmjit/evmcc/evmcc.cpp b/evmjit/evmcc/evmcc.cpp new file mode 100644 index 000000000..e86f948f2 --- /dev/null +++ b/evmjit/evmcc/evmcc.cpp @@ -0,0 +1,210 @@ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +void parseProgramOptions(int _argc, char** _argv, boost::program_options::variables_map& _varMap) +{ + namespace opt = boost::program_options; + + opt::options_description explicitOpts("Allowed options"); + explicitOpts.add_options() + ("help,h", "show usage information") + ("compile,c", "compile the code to LLVM IR") + ("interpret,i", "compile the code to LLVM IR and execute") + ("gas,g", opt::value(), "set initial gas for execution") + ("disassemble,d", "dissassemble the code") + ("dump-cfg", "dump control flow graph to graphviz file") + ("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(), "dump generated LLVM IR to file") + ("output-bc", opt::value(), "dump generated LLVM bitcode to file") + ("show-logs", "output LOG statements to stderr") + ("verbose,V", "enable verbose output"); + + opt::options_description implicitOpts("Input files"); + implicitOpts.add_options() + ("input-file", opt::value(), "input file"); + + opt::options_description allOpts(""); + allOpts.add(explicitOpts).add(implicitOpts); + + opt::positional_options_description inputOpts; + inputOpts.add("input-file", 1); + + const char* errorMsg = nullptr; + try + { + auto parser = opt::command_line_parser(_argc, _argv).options(allOpts).positional(inputOpts); + opt::store(parser.run(), _varMap); + opt::notify(_varMap); + } + catch (boost::program_options::error& err) + { + errorMsg = err.what(); + } + + if (!errorMsg && _varMap.count("input-file") == 0) + errorMsg = "missing input file name"; + + if (_varMap.count("disassemble") == 0 + && _varMap.count("compile") == 0 + && _varMap.count("interpret") == 0) + { + errorMsg = "at least one of -c, -i, -d is required"; + } + + if (errorMsg || _varMap.count("help")) + { + if (errorMsg) + std::cerr << "Error: " << errorMsg << std::endl; + + std::cout << "Usage: " << _argv[0] << " input-file " << std::endl + << explicitOpts << std::endl; + std::exit(errorMsg ? 1 : 0); + } +} + +int main(int argc, char** argv) +{ + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram X(argc, argv); + + boost::program_options::variables_map options; + parseProgramOptions(argc, argv, options); + + auto inputFile = options["input-file"].as(); + std::ifstream ifs(inputFile); + if (!ifs.is_open()) + { + std::cerr << "cannot open input file " << inputFile << std::endl; + exit(1); + } + + std::string src((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + + boost::algorithm::trim(src); + + using namespace dev; + + bytes bytecode = fromHex(src); + + if (options.count("disassemble")) + { + std::string assembly = eth::disassemble(bytecode); + std::cout << assembly << std::endl; + } + + if (options.count("compile") || options.count("interpret")) + { + size_t initialGas = 10000; + + if (options.count("gas")) + initialGas = options["gas"].as(); + + auto compilationStartTime = std::chrono::high_resolution_clock::now(); + + eth::jit::Compiler::Options compilerOptions; + compilerOptions.dumpCFG = options.count("dump-cfg") > 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 module = compiler.compile(bytecode, "main"); + + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + + module->dump(); + + if (options.count("output-ll")) + { + auto outputFile = options["output-ll"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + module->print(ros, nullptr); + ofs.close(); + } + + if (options.count("output-bc")) + { + auto outputFile = options["output-bc"].as(); + std::ofstream ofs(outputFile); + if (!ofs.is_open()) + { + std::cerr << "cannot open output file " << outputFile << std::endl; + exit(1); + } + llvm::raw_os_ostream ros(ofs); + llvm::WriteBitcodeToFile(module.get(), ros); + ros.flush(); + ofs.close(); + } + + if (options.count("verbose")) + { + std::cerr << "*** Compilation time: " + << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count() + << std::endl; + } + + if (options.count("interpret")) + { + using namespace eth::jit; + + ExecutionEngine engine; + eth::jit::u256 gas = initialGas; + + // Create random runtime data + RuntimeData data; + data.set(RuntimeData::Gas, gas); + data.set(RuntimeData::Address, (u160)Address(1122334455667788)); + data.set(RuntimeData::Caller, (u160)Address(0xfacefacefaceface)); + data.set(RuntimeData::Origin, (u160)Address(101010101010101010)); + data.set(RuntimeData::CallValue, 0xabcd); + data.set(RuntimeData::CallDataSize, 3); + data.set(RuntimeData::GasPrice, 1003); + data.set(RuntimeData::CoinBase, (u160)Address(101010101010101015)); + data.set(RuntimeData::TimeStamp, 1005); + data.set(RuntimeData::Number, 1006); + data.set(RuntimeData::Difficulty, 16); + data.set(RuntimeData::GasLimit, 1008); + data.set(RuntimeData::CodeSize, bytecode.size()); + data.callData = (uint8_t*)"abc"; + data.code = bytecode.data(); + + // BROKEN: env_* functions must be implemented & RuntimeData struct created + // TODO: Do not compile module again + auto result = engine.run(bytecode, &data, nullptr); + return static_cast(result); + } + } + + return 0; +} diff --git a/evmjit/evmcc/test/arith/addmod.evm b/evmjit/evmcc/test/arith/addmod.evm new file mode 100644 index 000000000..4ca71e065 --- /dev/null +++ b/evmjit/evmcc/test/arith/addmod.evm @@ -0,0 +1 @@ +60646107b760271460005560006001f2 diff --git a/evmjit/evmcc/test/arith/addmod.lll b/evmjit/evmcc/test/arith/addmod.lll new file mode 100644 index 000000000..11a6b2cb9 --- /dev/null +++ b/evmjit/evmcc/test/arith/addmod.lll @@ -0,0 +1,12 @@ +;; Should return (1975 + 39) `mod` 100 = 14 = 0x0e +(asm +100 +1975 +39 +ADDMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/arith1.evm b/evmjit/evmcc/test/arith/arith1.evm new file mode 100644 index 000000000..c7a029f52 --- /dev/null +++ b/evmjit/evmcc/test/arith/arith1.evm @@ -0,0 +1 @@ +60016001900160070260050160029004600490066021900560150160030260059007600303600960110860005460086000f2 diff --git a/evmjit/evmcc/test/arith/arith1.lll b/evmjit/evmcc/test/arith/arith1.lll new file mode 100644 index 000000000..4757a7420 --- /dev/null +++ b/evmjit/evmcc/test/arith/arith1.lll @@ -0,0 +1,37 @@ + +(asm +1 +1 +SWAP1 +ADD ;; 2 +7 +MUL ;; 14 +5 +ADD ;; 19 +2 +SWAP1 +DIV ;; 9 +4 +SWAP1 +MOD ;; 1 +33 +SWAP1 +SDIV;; 0 +21 +ADD ;; 21 +3 +MUL ;; 63 +5 +SWAP1 +SMOD;; 3 +3 +SUB ;; 0 +9 +17 +EXP ;; 17^9 +0 +MSTORE +8 +0 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/arith_bnot.evm b/evmjit/evmcc/test/arith/arith_bnot.evm new file mode 100644 index 000000000..4cfaf8f55 --- /dev/null +++ b/evmjit/evmcc/test/arith/arith_bnot.evm @@ -0,0 +1 @@ +6201e2406000546000530960005460206000f2 diff --git a/evmjit/evmcc/test/arith/arith_bnot.lll b/evmjit/evmcc/test/arith/arith_bnot.lll new file mode 100644 index 000000000..a83b05a9a --- /dev/null +++ b/evmjit/evmcc/test/arith/arith_bnot.lll @@ -0,0 +1,14 @@ + +(asm +123456 +0 +MSTORE +0 +MLOAD +BNOT +0 +MSTORE +32 +0 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/div.evm b/evmjit/evmcc/test/arith/div.evm new file mode 100644 index 000000000..b68d5d202 --- /dev/null +++ b/evmjit/evmcc/test/arith/div.evm @@ -0,0 +1 @@ +60027ffedcba9876543210fedcba9876543210fedcba9876543210fedcba98765432100460005460206000f2 diff --git a/evmjit/evmcc/test/arith/div.lll b/evmjit/evmcc/test/arith/div.lll new file mode 100644 index 000000000..72c22bfdc --- /dev/null +++ b/evmjit/evmcc/test/arith/div.lll @@ -0,0 +1,10 @@ +(asm +0x2 +0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 +DIV +0 +MSTORE +32 +0 +RETURN +) diff --git a/evmjit/evmcc/test/arith/fib1.evm b/evmjit/evmcc/test/arith/fib1.evm new file mode 100644 index 000000000..4c141314e --- /dev/null +++ b/evmjit/evmcc/test/arith/fib1.evm @@ -0,0 +1 @@ +60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101 diff --git a/evmjit/evmcc/test/arith/fib1.lll b/evmjit/evmcc/test/arith/fib1.lll new file mode 100644 index 000000000..286bed275 --- /dev/null +++ b/evmjit/evmcc/test/arith/fib1.lll @@ -0,0 +1,57 @@ +;; Fibbonacci unrolled + +(asm +1 +1 +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +DUP2 +DUP2 +ADD +) \ No newline at end of file diff --git a/evmjit/evmcc/test/arith/mul.evm b/evmjit/evmcc/test/arith/mul.evm new file mode 100644 index 000000000..7e8afd268 --- /dev/null +++ b/evmjit/evmcc/test/arith/mul.evm @@ -0,0 +1 @@ +7001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba09876543217001234567890abcdef0fedcba0987654321020260005460206000f2 diff --git a/evmjit/evmcc/test/arith/mul.lll b/evmjit/evmcc/test/arith/mul.lll new file mode 100644 index 000000000..b0fa343bb --- /dev/null +++ b/evmjit/evmcc/test/arith/mul.lll @@ -0,0 +1,13 @@ +(asm +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +0x1234567890abcdef0fedcba0987654321 +MUL +MUL +0 +MSTORE +32 +0 +RETURN +;; 47d0817e4167b1eb4f9fc722b133ef9d7d9a6fb4c2c1c442d000107a5e419561 +) diff --git a/evmjit/evmcc/test/arith/mulmod.evm b/evmjit/evmcc/test/arith/mulmod.evm new file mode 100644 index 000000000..e34a06154 --- /dev/null +++ b/evmjit/evmcc/test/arith/mulmod.evm @@ -0,0 +1 @@ +6064601b60251560005560006001f2 diff --git a/evmjit/evmcc/test/arith/mulmod.lll b/evmjit/evmcc/test/arith/mulmod.lll new file mode 100644 index 000000000..5e87f0843 --- /dev/null +++ b/evmjit/evmcc/test/arith/mulmod.lll @@ -0,0 +1,12 @@ +;; Should return (27 * 37) `mod` 100 = 99 = 0x63 +(asm +100 +27 +37 +MULMOD +0 +MSTORE8 +0 +1 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/except/badinst1.evm b/evmjit/evmcc/test/except/badinst1.evm new file mode 100644 index 000000000..69aadac5e --- /dev/null +++ b/evmjit/evmcc/test/except/badinst1.evm @@ -0,0 +1 @@ +4a diff --git a/evmjit/evmcc/test/ext/calldatacopy1.evm b/evmjit/evmcc/test/ext/calldatacopy1.evm new file mode 100644 index 000000000..f20019651 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy1.evm @@ -0,0 +1 @@ +60326000600a37600053600a6014f2 diff --git a/evmjit/evmcc/test/ext/calldatacopy1.lll b/evmjit/evmcc/test/ext/calldatacopy1.lll new file mode 100644 index 000000000..3d2ae0a78 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy1.lll @@ -0,0 +1,13 @@ +(asm +50 ;; byte count +0 ;; source index in calldata array +10 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/calldatacopy2.evm b/evmjit/evmcc/test/ext/calldatacopy2.evm new file mode 100644 index 000000000..e8eea8da7 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000376000536000600af2 diff --git a/evmjit/evmcc/test/ext/calldatacopy2.lll b/evmjit/evmcc/test/ext/calldatacopy2.lll new file mode 100644 index 000000000..6bbea48d8 --- /dev/null +++ b/evmjit/evmcc/test/ext/calldatacopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in calldata array +0 ;; dest index in memory +CALLDATACOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/codecopy1.evm b/evmjit/evmcc/test/ext/codecopy1.evm new file mode 100644 index 000000000..d286f9232 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy1.evm @@ -0,0 +1 @@ +60146000600a39600053600a6014f2 diff --git a/evmjit/evmcc/test/ext/codecopy1.lll b/evmjit/evmcc/test/ext/codecopy1.lll new file mode 100644 index 000000000..85a02b5d7 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy1.lll @@ -0,0 +1,13 @@ +(asm +20 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +10 +20 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/codecopy2.evm b/evmjit/evmcc/test/ext/codecopy2.evm new file mode 100644 index 000000000..71cd92525 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy2.evm @@ -0,0 +1 @@ +606464e8d4a510006000396000536000600af2 diff --git a/evmjit/evmcc/test/ext/codecopy2.lll b/evmjit/evmcc/test/ext/codecopy2.lll new file mode 100644 index 000000000..dcbbcaa46 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy2.lll @@ -0,0 +1,13 @@ +(asm +100 ;; byte count +1000000000000 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/codecopy3.evm b/evmjit/evmcc/test/ext/codecopy3.evm new file mode 100644 index 000000000..e4b6a9253 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy3.evm @@ -0,0 +1 @@ +3860006000396000536000600af2 diff --git a/evmjit/evmcc/test/ext/codecopy3.lll b/evmjit/evmcc/test/ext/codecopy3.lll new file mode 100644 index 000000000..80d9982c6 --- /dev/null +++ b/evmjit/evmcc/test/ext/codecopy3.lll @@ -0,0 +1,13 @@ +(asm +CODESIZE ;; byte count +0 ;; source index in code array +0 ;; dest index in memory +CODECOPY + +0 +MLOAD ;; to dump memory + +0 +10 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/ext_test.evm b/evmjit/evmcc/test/ext/ext_test.evm new file mode 100644 index 000000000..580bd9675 --- /dev/null +++ b/evmjit/evmcc/test/ext/ext_test.evm @@ -0,0 +1 @@ +5a3031333234363a4041424344455a36600035602635601335387f1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff600054602060006000f06020600060206000600030610bb8f1600053611000545b60200260002030ff60016002f2 diff --git a/evmjit/evmcc/test/ext/ext_test.lll b/evmjit/evmcc/test/ext/ext_test.lll new file mode 100644 index 000000000..3287ae95f --- /dev/null +++ b/evmjit/evmcc/test/ext/ext_test.lll @@ -0,0 +1,55 @@ + +(asm +PC +ADDRESS +BALANCE +CALLER +ORIGIN +CALLVALUE +CALLDATASIZE +GASPRICE +PREVHASH +COINBASE +TIMESTAMP +NUMBER +DIFFICULTY +GASLIMIT +PC +CALLDATASIZE +0 +CALLDATALOAD +38 +CALLDATALOAD +19 +CALLDATALOAD +CODESIZE +0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff +0 +MSTORE +32 +0 +0 +CREATE +32 +0 +32 +0 +0 +ADDRESS +3000 +CALL +0 +MLOAD +4096 +MSTORE +MSIZE +32 +MUL +0 +SHA3 +ADDRESS +SUICIDE +1 +2 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/extcodecopy1.evm b/evmjit/evmcc/test/ext/extcodecopy1.evm new file mode 100644 index 000000000..6132b52d8 --- /dev/null +++ b/evmjit/evmcc/test/ext/extcodecopy1.evm @@ -0,0 +1 @@ +60c86000600a303c60005360006020f2 diff --git a/evmjit/evmcc/test/ext/extcodecopy1.lll b/evmjit/evmcc/test/ext/extcodecopy1.lll new file mode 100644 index 000000000..c37054574 --- /dev/null +++ b/evmjit/evmcc/test/ext/extcodecopy1.lll @@ -0,0 +1,11 @@ +(asm +200 ;; byte count +0 ;; source index in code array +10 ;; dest index in memory +ADDRESS +EXTCODECOPY + +0 MLOAD ;; to dump memory + +0 32 RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/store_delete.evm b/evmjit/evmcc/test/ext/store_delete.evm new file mode 100644 index 000000000..d6acae03d --- /dev/null +++ b/evmjit/evmcc/test/ext/store_delete.evm @@ -0,0 +1 @@ +6104d26063576000606357 diff --git a/evmjit/evmcc/test/ext/store_delete.lll b/evmjit/evmcc/test/ext/store_delete.lll new file mode 100644 index 000000000..3d8f0f23a --- /dev/null +++ b/evmjit/evmcc/test/ext/store_delete.lll @@ -0,0 +1,9 @@ + +(asm +1234 +99 +SSTORE +0 +99 +SSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ext/store_test.evm b/evmjit/evmcc/test/ext/store_test.evm new file mode 100644 index 000000000..54c9419b5 --- /dev/null +++ b/evmjit/evmcc/test/ext/store_test.evm @@ -0,0 +1 @@ +607b607c60015760005760015660005603 diff --git a/evmjit/evmcc/test/ext/store_test.lll b/evmjit/evmcc/test/ext/store_test.lll new file mode 100644 index 000000000..c40471c40 --- /dev/null +++ b/evmjit/evmcc/test/ext/store_test.lll @@ -0,0 +1,14 @@ + +(asm +123 +124 +1 +SSTORE +0 +SSTORE +1 +SLOAD +0 +SLOAD +SUB +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/ackermann.ethel b/evmjit/evmcc/test/jump/ackermann.ethel new file mode 100644 index 000000000..971fd2b8d --- /dev/null +++ b/evmjit/evmcc/test/jump/ackermann.ethel @@ -0,0 +1,7 @@ +let A m n = + if m == 0 then n+1 + else if n == 0 then A (m-1) 1 + else A (m-1) (A (m) (n-1)) + +return A 3 8 + diff --git a/evmjit/evmcc/test/jump/ackermann.evm b/evmjit/evmcc/test/jump/ackermann.evm new file mode 100644 index 000000000..964844045 --- /dev/null +++ b/evmjit/evmcc/test/jump/ackermann.evm @@ -0,0 +1 @@ +6009600360086012585d60005460206000f26000820e6047596000810e603859603460018303603084600185036012585d6012585d60445860436001830360016012585d604b5860018101905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badindirect1.evm b/evmjit/evmcc/test/jump/badindirect1.evm new file mode 100644 index 000000000..b2a8aad67 --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect1.evm @@ -0,0 +1 @@ +601b602502585d diff --git a/evmjit/evmcc/test/jump/badindirect1.lll b/evmjit/evmcc/test/jump/badindirect1.lll new file mode 100644 index 000000000..d6291be68 --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect1.lll @@ -0,0 +1,9 @@ +;; Indirect jump out of code + +(asm +27 +37 +MUL +JUMP +JUMPDEST +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badindirect2.evm b/evmjit/evmcc/test/jump/badindirect2.evm new file mode 100644 index 000000000..22217523d --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect2.evm @@ -0,0 +1 @@ +60016003600302596000600058 diff --git a/evmjit/evmcc/test/jump/badindirect2.lll b/evmjit/evmcc/test/jump/badindirect2.lll new file mode 100644 index 000000000..53a6294f7 --- /dev/null +++ b/evmjit/evmcc/test/jump/badindirect2.lll @@ -0,0 +1,12 @@ +;; Indirect jump into data + +(asm +1 ;; 0 +3 +3 +MUL ;; 6 +JUMPI ;; 7 +0 ;; 8 +0 +JUMP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badjump1.evm b/evmjit/evmcc/test/jump/badjump1.evm new file mode 100644 index 000000000..5c11a8661 --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump1.evm @@ -0,0 +1 @@ +6103e758 diff --git a/evmjit/evmcc/test/jump/badjump1.lll b/evmjit/evmcc/test/jump/badjump1.lll new file mode 100644 index 000000000..1834a62ef --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump1.lll @@ -0,0 +1,6 @@ +;; Direct jump out of code. + +(asm +999 +JUMP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/badjump2.evm b/evmjit/evmcc/test/jump/badjump2.evm new file mode 100644 index 000000000..900a1c15a --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump2.evm @@ -0,0 +1 @@ +6004586000600058 diff --git a/evmjit/evmcc/test/jump/badjump2.lll b/evmjit/evmcc/test/jump/badjump2.lll new file mode 100644 index 000000000..ce61276d7 --- /dev/null +++ b/evmjit/evmcc/test/jump/badjump2.lll @@ -0,0 +1,9 @@ +;; Direct jump into data + +(asm +4 ;; 0 0-3 +JUMP ;; 2 +0 ;; 3 3-4 +0 ;; 5 4-7 +JUMP ;; 6 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/call1.ethel b/evmjit/evmcc/test/jump/call1.ethel new file mode 100644 index 000000000..414ad0124 --- /dev/null +++ b/evmjit/evmcc/test/jump/call1.ethel @@ -0,0 +1,5 @@ +let f n = n + 1 + +return f 2 + + diff --git a/evmjit/evmcc/test/jump/call1.evm b/evmjit/evmcc/test/jump/call1.evm new file mode 100644 index 000000000..252aaf778 --- /dev/null +++ b/evmjit/evmcc/test/jump/call1.evm @@ -0,0 +1 @@ +600760026010585d60005460206000f28060010190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/call2.ethel b/evmjit/evmcc/test/jump/call2.ethel new file mode 100644 index 000000000..bdeb9b734 --- /dev/null +++ b/evmjit/evmcc/test/jump/call2.ethel @@ -0,0 +1,5 @@ +let f a b = a + b + +return f 2 3 + + diff --git a/evmjit/evmcc/test/jump/call2.evm b/evmjit/evmcc/test/jump/call2.evm new file mode 100644 index 000000000..6832e044d --- /dev/null +++ b/evmjit/evmcc/test/jump/call2.evm @@ -0,0 +1 @@ +6009600260036012585d60005460206000f2818101905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac.ethel b/evmjit/evmcc/test/jump/fac.ethel new file mode 100644 index 000000000..8bfe94dd6 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac.ethel @@ -0,0 +1,5 @@ +let fac n = + if n == 0 then 1 + else n * fac (n-1) + +return fac 60 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac.evm b/evmjit/evmcc/test/jump/fac.evm new file mode 100644 index 000000000..04cd3e4f4 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac.evm @@ -0,0 +1 @@ +6007603c6010585d60005460206000f26000810e6026596020600182036010585d8102602858600190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac_tail.ethel b/evmjit/evmcc/test/jump/fac_tail.ethel new file mode 100644 index 000000000..9ce5ecac7 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac_tail.ethel @@ -0,0 +1,5 @@ +let fac a n = + if n == 0 then a + else fac (a*n) (n-1) + +return fac 1 60 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fac_tail.evm b/evmjit/evmcc/test/jump/fac_tail.evm new file mode 100644 index 000000000..8384d94e4 --- /dev/null +++ b/evmjit/evmcc/test/jump/fac_tail.evm @@ -0,0 +1 @@ +60096001603c6012585d60005460206000f26000810e6029596025818302600183036012585d602a5881905090509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/fib1.ethel b/evmjit/evmcc/test/jump/fib1.ethel new file mode 100644 index 000000000..81b869f41 --- /dev/null +++ b/evmjit/evmcc/test/jump/fib1.ethel @@ -0,0 +1,6 @@ +let fib n = + if n < 3 then 1 + else fib (n-1) + fib (n-2) + +return fib 10 + diff --git a/evmjit/evmcc/test/jump/fib1.evm b/evmjit/evmcc/test/jump/fib1.evm new file mode 100644 index 000000000..5042a192f --- /dev/null +++ b/evmjit/evmcc/test/jump/fib1.evm @@ -0,0 +1 @@ +6007600a6010585d60005460206000f26003810a602f596020600282036010585d602a600183036010585d01603158600190509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/for1.evm b/evmjit/evmcc/test/jump/for1.evm new file mode 100644 index 000000000..f8e65cbf2 --- /dev/null +++ b/evmjit/evmcc/test/jump/for1.evm @@ -0,0 +1 @@ +600a60805460006080530b0f60255960a0536080530160a054600160805303608054600558 diff --git a/evmjit/evmcc/test/jump/for1.lll b/evmjit/evmcc/test/jump/for1.lll new file mode 100644 index 000000000..419fc9b54 --- /dev/null +++ b/evmjit/evmcc/test/jump/for1.lll @@ -0,0 +1,3 @@ +(for [i]:10 (> @i 0) [i](- @i 1) + [j](+ @i @j) +) diff --git a/evmjit/evmcc/test/jump/for2.evm b/evmjit/evmcc/test/jump/for2.evm new file mode 100644 index 000000000..628297778 --- /dev/null +++ b/evmjit/evmcc/test/jump/for2.evm @@ -0,0 +1 @@ +6000608054600a6080530a0f60255960a0536080530160a054600160805301608054600558 diff --git a/evmjit/evmcc/test/jump/for2.lll b/evmjit/evmcc/test/jump/for2.lll new file mode 100644 index 000000000..de17d65ac --- /dev/null +++ b/evmjit/evmcc/test/jump/for2.lll @@ -0,0 +1,3 @@ +(for [i]:0 (< @i 10) [i](+ @i 1) + [j](+ @i @j) +) diff --git a/evmjit/evmcc/test/jump/if1.ethel b/evmjit/evmcc/test/jump/if1.ethel new file mode 100644 index 000000000..85c3e126b --- /dev/null +++ b/evmjit/evmcc/test/jump/if1.ethel @@ -0,0 +1 @@ +return if 0 then 1 else 2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/if1.evm b/evmjit/evmcc/test/jump/if1.evm new file mode 100644 index 000000000..51fbe04bd --- /dev/null +++ b/evmjit/evmcc/test/jump/if1.evm @@ -0,0 +1 @@ +60006300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/if2.ethel b/evmjit/evmcc/test/jump/if2.ethel new file mode 100644 index 000000000..2a58d6365 --- /dev/null +++ b/evmjit/evmcc/test/jump/if2.ethel @@ -0,0 +1 @@ +return if 1 then 1 else 2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/if2.evm b/evmjit/evmcc/test/jump/if2.evm new file mode 100644 index 000000000..6d823b374 --- /dev/null +++ b/evmjit/evmcc/test/jump/if2.evm @@ -0,0 +1 @@ +60016300000010596002630000001258600160005460206000f2 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect1.evm b/evmjit/evmcc/test/jump/indirect1.evm new file mode 100644 index 000000000..ab6928304 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect1.evm @@ -0,0 +1 @@ +600460030158005d6001600054 diff --git a/evmjit/evmcc/test/jump/indirect1.lll b/evmjit/evmcc/test/jump/indirect1.lll new file mode 100644 index 000000000..1ee7dc347 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect1.lll @@ -0,0 +1,13 @@ +;; Indirect JUMP + +(asm +4 ;; 0 +3 ;; 2 +ADD ;; 4 +JUMP ;; 5 +STOP ;; 6 +JUMPDEST ;; 7 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect2.evm b/evmjit/evmcc/test/jump/indirect2.evm new file mode 100644 index 000000000..e9697eaa1 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect2.evm @@ -0,0 +1 @@ +600860060158005d6001600054005d600260005400 diff --git a/evmjit/evmcc/test/jump/indirect2.lll b/evmjit/evmcc/test/jump/indirect2.lll new file mode 100644 index 000000000..f2f068630 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect2.lll @@ -0,0 +1,19 @@ +;; Indirect JUMP + +(asm +8 ;; 0 +6 ;; 2 +ADD ;; 4 +JUMP ;; 5 --> 14 +STOP ;; 6 +JUMPDEST ;; 7 +1 ;; 8 +0 ;; 10 +MSTORE ;; 12 +STOP ;; 13 +JUMPDEST ;; 14 +2 +0 +MSTORE +STOP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect3.evm b/evmjit/evmcc/test/jump/indirect3.evm new file mode 100644 index 000000000..1fb0a356c --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect3.evm @@ -0,0 +1 @@ +6001600460050159005d6001600054 diff --git a/evmjit/evmcc/test/jump/indirect3.lll b/evmjit/evmcc/test/jump/indirect3.lll new file mode 100644 index 000000000..d6a679f9a --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect3.lll @@ -0,0 +1,14 @@ +;; Indirect JUMP + +(asm +1 ;; 0 +4 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +STOP ;; 8 +JUMPDEST ;; 9 +1 +0 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/indirect4.evm b/evmjit/evmcc/test/jump/indirect4.evm new file mode 100644 index 000000000..f0e31a8f4 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect4.evm @@ -0,0 +1 @@ +60006007600501596001600054005d00 diff --git a/evmjit/evmcc/test/jump/indirect4.lll b/evmjit/evmcc/test/jump/indirect4.lll new file mode 100644 index 000000000..7fbe0b833 --- /dev/null +++ b/evmjit/evmcc/test/jump/indirect4.lll @@ -0,0 +1,15 @@ +;; Indirect JUMP + +(asm +0 ;; 0 +7 ;; 2 +5 ;; 4 +ADD ;; 6 +JUMPI ;; 7 +1 ;; 8 +0 ;; 9 +MSTORE ;; 10 +STOP ;; 11 +JUMPDEST ;; 12 +STOP +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump1.evm b/evmjit/evmcc/test/jump/jump1.evm new file mode 100644 index 000000000..0df9b4036 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump1.evm @@ -0,0 +1 @@ +600458006001600154 diff --git a/evmjit/evmcc/test/jump/jump1.lll b/evmjit/evmcc/test/jump/jump1.lll new file mode 100644 index 000000000..33119edb3 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump1.lll @@ -0,0 +1,11 @@ +;; Direct JUMP. +;; output: memory[1] == 1 + +(asm +4 ;; 0 +JUMP ;; 2 +STOP ;; 3 +1 ;; 4 +1 ;; 6 +MSTORE ;; 8 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump2.evm b/evmjit/evmcc/test/jump/jump2.evm new file mode 100644 index 000000000..35d75941d --- /dev/null +++ b/evmjit/evmcc/test/jump/jump2.evm @@ -0,0 +1 @@ +6008586001600154 diff --git a/evmjit/evmcc/test/jump/jump2.lll b/evmjit/evmcc/test/jump/jump2.lll new file mode 100644 index 000000000..a70d50ecb --- /dev/null +++ b/evmjit/evmcc/test/jump/jump2.lll @@ -0,0 +1,10 @@ +;; Direct JUMP to the end of code. +;; output: memory should have size 0. + +(asm +8 ;; 0 +JUMP ;; 2 +1 ;; 3 +1 ;; 5 +MSTORE ;; 7 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump3.evm b/evmjit/evmcc/test/jump/jump3.evm new file mode 100644 index 000000000..599d4a764 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump3.evm @@ -0,0 +1 @@ +602a586001600154 diff --git a/evmjit/evmcc/test/jump/jump3.lll b/evmjit/evmcc/test/jump/jump3.lll new file mode 100644 index 000000000..bc897e30c --- /dev/null +++ b/evmjit/evmcc/test/jump/jump3.lll @@ -0,0 +1,10 @@ +;; Direct JUMP past the end of code. +;; output: memory should have size 0. + +(asm +42 +JUMP +1 +1 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump4.evm b/evmjit/evmcc/test/jump/jump4.evm new file mode 100644 index 000000000..41713f43e --- /dev/null +++ b/evmjit/evmcc/test/jump/jump4.evm @@ -0,0 +1 @@ +600b6009580000600558005d6001600154 diff --git a/evmjit/evmcc/test/jump/jump4.lll b/evmjit/evmcc/test/jump/jump4.lll new file mode 100644 index 000000000..131baee2d --- /dev/null +++ b/evmjit/evmcc/test/jump/jump4.lll @@ -0,0 +1,17 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +11 ;; 0 +9 ;; 2 +JUMP ;; 4 --> 9 +STOP ;; 5 +STOP ;; 6 +5 ;; 7 +JUMP ;; 9 --> 11 +STOP ;; 10 +JUMPDEST +1 ;; 11 +1 +MSTORE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump5.evm b/evmjit/evmcc/test/jump/jump5.evm new file mode 100644 index 000000000..c36d9615b --- /dev/null +++ b/evmjit/evmcc/test/jump/jump5.evm @@ -0,0 +1 @@ +6005600e585d600160015400600f5800 diff --git a/evmjit/evmcc/test/jump/jump5.lll b/evmjit/evmcc/test/jump/jump5.lll new file mode 100644 index 000000000..d28b7d4ac --- /dev/null +++ b/evmjit/evmcc/test/jump/jump5.lll @@ -0,0 +1,16 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +(asm +5 ;; 0 +14 ;; 2 +JUMP ;; 4 --> 14 +JUMPDEST ;; 5 +1 ;; 6 +1 ;; 8 +MSTORE ;; 10 +STOP ;; 11 +15 ;; 12 +JUMP ;; 14 --> 5 +STOP ;; 15 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jump6.evm b/evmjit/evmcc/test/jump/jump6.evm new file mode 100644 index 000000000..029db7191 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump6.evm @@ -0,0 +1 @@ +600358600f600d58006014600758005d6001600154005d600260025400 diff --git a/evmjit/evmcc/test/jump/jump6.lll b/evmjit/evmcc/test/jump/jump6.lll new file mode 100644 index 000000000..1116aa663 --- /dev/null +++ b/evmjit/evmcc/test/jump/jump6.lll @@ -0,0 +1,32 @@ +;; Direct JUMP. +;; output: memory[1] = 1 + +;; 0, 2 --> 3 .. 7 --> 13 -*-> 15 .. 19 + +(asm +3 ;; 0 +JUMP ;; 2 + +15 ;; 3 <- start +13 ;; 5 +JUMP ;; 7 <- b +STOP ;; 8 + +20 ;; 9 +7 ;; 11 + +JUMP ;; 13 <- a +STOP ;; 14 + +JUMPDEST ;; 15 <- c +1 ;; 16 +1 ;; 18 +MSTORE ;; 19 +STOP ;; 20 + +JUMPDEST ;; 21 <- d +2 ;; 22 +2 ;; 24 +MSTORE ;; 26 +STOP ;; 27 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/jumpi_at_the_end.evm b/evmjit/evmcc/test/jump/jumpi_at_the_end.evm new file mode 100644 index 000000000..2d7411761 --- /dev/null +++ b/evmjit/evmcc/test/jump/jumpi_at_the_end.evm @@ -0,0 +1 @@ +600a6000545d6000536001900380600054600659 diff --git a/evmjit/evmcc/test/jump/jumpi_at_the_end.lll b/evmjit/evmcc/test/jump/jumpi_at_the_end.lll new file mode 100644 index 000000000..263ada6a7 --- /dev/null +++ b/evmjit/evmcc/test/jump/jumpi_at_the_end.lll @@ -0,0 +1 @@ +(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI) \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/loop1.evm b/evmjit/evmcc/test/jump/loop1.evm new file mode 100644 index 000000000..7724d6308 --- /dev/null +++ b/evmjit/evmcc/test/jump/loop1.evm @@ -0,0 +1 @@ +600a600181038060025960005460015460025400 diff --git a/evmjit/evmcc/test/jump/loop1.lll b/evmjit/evmcc/test/jump/loop1.lll new file mode 100644 index 000000000..0044ec1fb --- /dev/null +++ b/evmjit/evmcc/test/jump/loop1.lll @@ -0,0 +1,27 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +1 +DUP2 +SUB +DUP1 +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +0 +MSTORE +1 +MSTORE +2 +MSTORE +;;3 +;;MSTORE + +STOP +) + + diff --git a/evmjit/evmcc/test/jump/loop2.evm b/evmjit/evmcc/test/jump/loop2.evm new file mode 100644 index 000000000..faffa4e5b --- /dev/null +++ b/evmjit/evmcc/test/jump/loop2.evm @@ -0,0 +1 @@ +600a80600190038060025960005460015460025400 diff --git a/evmjit/evmcc/test/jump/loop2.lll b/evmjit/evmcc/test/jump/loop2.lll new file mode 100644 index 000000000..9996c52ba --- /dev/null +++ b/evmjit/evmcc/test/jump/loop2.lll @@ -0,0 +1,28 @@ +;; Produces 1 2 3 4 5 6 7 8 9 10 on the stack and exits + +(asm +10 + +;; 2 +DUP1 +1 +SWAP1 +SUB +DUP1 +2 +JUMPI + +;; stack = 1 2 3 4 5 6 7 8 9 10 +0 +MSTORE +1 +MSTORE +2 +MSTORE +;;3 +;;MSTORE + +STOP +) + + diff --git a/evmjit/evmcc/test/jump/rec1.ethel b/evmjit/evmcc/test/jump/rec1.ethel new file mode 100644 index 000000000..f83c8e81e --- /dev/null +++ b/evmjit/evmcc/test/jump/rec1.ethel @@ -0,0 +1,4 @@ +let f n = + if n == 0 then 2 else f (n-1) + +return f 10 diff --git a/evmjit/evmcc/test/jump/rec1.evm b/evmjit/evmcc/test/jump/rec1.evm new file mode 100644 index 000000000..2ae62aff6 --- /dev/null +++ b/evmjit/evmcc/test/jump/rec1.evm @@ -0,0 +1 @@ +6007600a6010585d60005460206000f26000810e6024596020600182036010585d602658600290509058 \ No newline at end of file diff --git a/evmjit/evmcc/test/jump/when1.asm b/evmjit/evmcc/test/jump/when1.asm new file mode 100644 index 000000000..01d41c266 --- /dev/null +++ b/evmjit/evmcc/test/jump/when1.asm @@ -0,0 +1,10 @@ +.code: + PUSH 1 + NOT + PUSH [tag0] + JUMPI + PUSH 13 + PUSH 128 + MSTORE +tag0: + diff --git a/evmjit/evmcc/test/jump/when1.evm b/evmjit/evmcc/test/jump/when1.evm new file mode 100644 index 000000000..303b02623 --- /dev/null +++ b/evmjit/evmcc/test/jump/when1.evm @@ -0,0 +1 @@ +60010f600b59600d608054 diff --git a/evmjit/evmcc/test/jump/when1.lll b/evmjit/evmcc/test/jump/when1.lll new file mode 100644 index 000000000..990a6e64a --- /dev/null +++ b/evmjit/evmcc/test/jump/when1.lll @@ -0,0 +1,2 @@ +(when (> 1 0) [i] 13) + \ No newline at end of file diff --git a/evmjit/evmcc/test/kv.evm b/evmjit/evmcc/test/kv.evm new file mode 100644 index 000000000..55141ea59 --- /dev/null +++ b/evmjit/evmcc/test/kv.evm @@ -0,0 +1 @@ +33604557602a8060106000396000f200604556330e0f602a59366080530a0f602a59602060805301356080533557604060805301608054600958 diff --git a/evmjit/evmcc/test/kv.lll b/evmjit/evmcc/test/kv.lll new file mode 100644 index 000000000..c62d9fa70 --- /dev/null +++ b/evmjit/evmcc/test/kv.lll @@ -0,0 +1,10 @@ +{ + [[69]] (caller) + (return 0 (lll + (when (= (caller) @@69) + (for {} (< @i (calldatasize)) [i](+ @i 64) + [[ (calldataload @i) ]] (calldataload (+ @i 32)) + ) + ) + 0)) +} diff --git a/evmjit/evmcc/test/mem/byte.evm b/evmjit/evmcc/test/mem/byte.evm new file mode 100644 index 000000000..ab63431ee --- /dev/null +++ b/evmjit/evmcc/test/mem/byte.evm @@ -0,0 +1 @@ +7f112233445566778899001122334455667788990011223344556677889900aabb6000137f112233445566778899001122334455667788990011223344556677889900aabb6001137f112233445566778899001122334455667788990011223344556677889900aabb6002137f112233445566778899001122334455667788990011223344556677889900aabb6003137f112233445566778899001122334455667788990011223344556677889900aabb6004137f112233445566778899001122334455667788990011223344556677889900aabb6005137f112233445566778899001122334455667788990011223344556677889900aabb6006137f112233445566778899001122334455667788990011223344556677889900aabb6007137f112233445566778899001122334455667788990011223344556677889900aabb6008137f112233445566778899001122334455667788990011223344556677889900aabb6009137f112233445566778899001122334455667788990011223344556677889900aabb600a137f112233445566778899001122334455667788990011223344556677889900aabb600b137f112233445566778899001122334455667788990011223344556677889900aabb600c137f112233445566778899001122334455667788990011223344556677889900aabb600d137f112233445566778899001122334455667788990011223344556677889900aabb600e137f112233445566778899001122334455667788990011223344556677889900aabb600f137f112233445566778899001122334455667788990011223344556677889900aabb6010137f112233445566778899001122334455667788990011223344556677889900aabb6011137f112233445566778899001122334455667788990011223344556677889900aabb6012137f112233445566778899001122334455667788990011223344556677889900aabb6013137f112233445566778899001122334455667788990011223344556677889900aabb6014137f112233445566778899001122334455667788990011223344556677889900aabb6015137f112233445566778899001122334455667788990011223344556677889900aabb6016137f112233445566778899001122334455667788990011223344556677889900aabb6017137f112233445566778899001122334455667788990011223344556677889900aabb6018137f112233445566778899001122334455667788990011223344556677889900aabb6019137f112233445566778899001122334455667788990011223344556677889900aabb601a137f112233445566778899001122334455667788990011223344556677889900aabb601b137f112233445566778899001122334455667788990011223344556677889900aabb601c137f112233445566778899001122334455667788990011223344556677889900aabb601d137f112233445566778899001122334455667788990011223344556677889900aabb601e137f112233445566778899001122334455667788990011223344556677889900aabb601f137f112233445566778899001122334455667788990011223344556677889900aabb6020137f112233445566778899001122334455667788990011223344556677889900aabb6107de13 diff --git a/evmjit/evmcc/test/mem/byte.lll b/evmjit/evmcc/test/mem/byte.lll new file mode 100644 index 000000000..95b0f99dc --- /dev/null +++ b/evmjit/evmcc/test/mem/byte.lll @@ -0,0 +1,105 @@ + +(asm +0x112233445566778899001122334455667788990011223344556677889900aabb +0 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +1 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +3 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +4 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +5 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +6 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +7 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +8 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +9 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +10 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +11 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +12 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +13 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +14 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +15 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +16 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +17 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +18 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +19 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +20 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +21 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +22 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +23 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +24 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +25 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +26 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +27 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +28 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +29 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +30 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +31 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +32 +BYTE +0x112233445566778899001122334455667788990011223344556677889900aabb +2014 +BYTE +) \ No newline at end of file diff --git a/evmjit/evmcc/test/mem/mem2.evm b/evmjit/evmcc/test/mem/mem2.evm new file mode 100644 index 000000000..49cc6e8b1 --- /dev/null +++ b/evmjit/evmcc/test/mem/mem2.evm @@ -0,0 +1 @@ +6001610d805b01556504409585d6df620493e05462061a80535b01 diff --git a/evmjit/evmcc/test/mem/mem2.lll b/evmjit/evmcc/test/mem/mem2.lll new file mode 100644 index 000000000..5345ee47c --- /dev/null +++ b/evmjit/evmcc/test/mem/mem2.lll @@ -0,0 +1,15 @@ + +(asm ;; [] +1 +3456 +MSIZE +ADD +MSTORE8 ;; [02] +4675432994527 +300000 +MSTORE +400000 +MLOAD +MSIZE +ADD +) \ No newline at end of file diff --git a/evmjit/evmcc/test/mem/memtest1.evm b/evmjit/evmcc/test/mem/memtest1.evm new file mode 100644 index 000000000..0506bf928 --- /dev/null +++ b/evmjit/evmcc/test/mem/memtest1.evm @@ -0,0 +1 @@ +6002600055600360015560005360015301600254 diff --git a/evmjit/evmcc/test/mem/memtest1.lll b/evmjit/evmcc/test/mem/memtest1.lll new file mode 100644 index 000000000..4b4389ad8 --- /dev/null +++ b/evmjit/evmcc/test/mem/memtest1.lll @@ -0,0 +1,18 @@ + +(asm ;; [] +2 +0 +MSTORE8 ;; [02] +3 +1 +MSTORE8 ;; [02 03] +0 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +1 +MLOAD ;; [2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +ADD +2 +MSTORE ;; [2 3 5 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ;; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] +) \ No newline at end of file diff --git a/evmjit/evmcc/test/mem/mstore1.evm b/evmjit/evmcc/test/mem/mstore1.evm new file mode 100644 index 000000000..ba6141ab1 --- /dev/null +++ b/evmjit/evmcc/test/mem/mstore1.evm @@ -0,0 +1 @@ +6001600054 diff --git a/evmjit/evmcc/test/mem/mstore1.lll b/evmjit/evmcc/test/mem/mstore1.lll new file mode 100644 index 000000000..2d2ca32b5 --- /dev/null +++ b/evmjit/evmcc/test/mem/mstore1.lll @@ -0,0 +1,6 @@ + +(asm ;; [] +1 +0 +MSTORE ;; [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1] +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ret/return1.evm b/evmjit/evmcc/test/ret/return1.evm new file mode 100644 index 000000000..8092cb007 --- /dev/null +++ b/evmjit/evmcc/test/ret/return1.evm @@ -0,0 +1 @@ +600160805460006080530b601b59600160005460206000f2602a58602760005460206000f26002608054 diff --git a/evmjit/evmcc/test/ret/return1.lll b/evmjit/evmcc/test/ret/return1.lll new file mode 100644 index 000000000..159d15ca3 --- /dev/null +++ b/evmjit/evmcc/test/ret/return1.lll @@ -0,0 +1,6 @@ +;; code should return 39 +;; i should remain 1 +{ + [i] 1 + ( if (> @i 0) { (return 39) [i] 2 } (return 1) ) +} \ No newline at end of file diff --git a/evmjit/evmcc/test/ret/return2.evm b/evmjit/evmcc/test/ret/return2.evm new file mode 100644 index 000000000..e29da7664 --- /dev/null +++ b/evmjit/evmcc/test/ret/return2.evm @@ -0,0 +1 @@ +6001620f4240f2 diff --git a/evmjit/evmcc/test/ret/return2.lll b/evmjit/evmcc/test/ret/return2.lll new file mode 100644 index 000000000..f5ee68f6e --- /dev/null +++ b/evmjit/evmcc/test/ret/return2.lll @@ -0,0 +1,6 @@ + +(asm +1 +1000000 +RETURN ;; return 1 byte from index 1M +) \ No newline at end of file diff --git a/evmjit/evmcc/test/ret/return_test.evm b/evmjit/evmcc/test/ret/return_test.evm new file mode 100644 index 000000000..977cf7c19 --- /dev/null +++ b/evmjit/evmcc/test/ret/return_test.evm @@ -0,0 +1 @@ +60016064546002608454600360a45460606064f2 diff --git a/evmjit/evmcc/test/ret/return_test.lll b/evmjit/evmcc/test/ret/return_test.lll new file mode 100644 index 000000000..c87a2d812 --- /dev/null +++ b/evmjit/evmcc/test/ret/return_test.lll @@ -0,0 +1,15 @@ + +(asm +1 +100 +MSTORE +2 +132 +MSTORE +3 +164 +MSTORE +96 +100 +RETURN +) \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/oos.evm b/evmjit/evmcc/test/stack/oos.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmjit/evmcc/test/stack/oos.evm @@ -0,0 +1 @@ +60018194505050509150 diff --git a/evmjit/evmcc/test/stack/oos.lll b/evmjit/evmcc/test/stack/oos.lll new file mode 100644 index 000000000..5394b06ba --- /dev/null +++ b/evmjit/evmcc/test/stack/oos.lll @@ -0,0 +1,11 @@ +(asm ;; x . v y z +1 ;; 1 x . v y z +DUP2 ;; x 1 x . v y z +SWAP5 ;; y 1 x . v x z +POP ;; 1 x . v x z +POP ;; x . v x z +POP ;; . v x z +POP ;; v x z +SWAP2 ;; z x v +POP ;; x v +) diff --git a/evmjit/evmcc/test/stack/push_test.evm b/evmjit/evmcc/test/stack/push_test.evm new file mode 100644 index 000000000..d624cee1d --- /dev/null +++ b/evmjit/evmcc/test/stack/push_test.evm @@ -0,0 +1 @@ +60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a diff --git a/evmjit/evmcc/test/stack/push_test.lll b/evmjit/evmcc/test/stack/push_test.lll new file mode 100644 index 000000000..832daaec1 --- /dev/null +++ b/evmjit/evmcc/test/stack/push_test.lll @@ -0,0 +1,35 @@ + +(asm +101 ;; PUSH1 +2002 ;; PUSH2 +303303 ;; PUSH3 +40444404 ;; PUSH4 +50555555505 ;; PUSH5 +60666666666606 +7777777777777777 +888888888888888888 +99999999999999999999 +10000000000000000000001 +10111111111111111111111101 +2022222222222222222222222202 +303333333333333333333333333303 +4044444444444444444444444444444404 +505555555555555555555555555555555505 +60666666666666666666666666666666666606 +7077777777777777777777777777777777777707 +808888888888888888888888888888888888888808 +90999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222202 +303333333333333333333333333333333333333333333333333303 +40444444444444444444444444444444444444444444444444444404 +50555555555555555555555555555555555555555555555555555555505 +6066666666666666666666666666666666666666666666666666666666606 +707777777777777777777777777777777777777777777777777777777777707 +808888888888888888888888888888888888888888888888888888888888888808 +90999999999999999999999999999999999999999999999999999999999999999909 +100000000000000000000000000000000000000000000000000000000000000000000001 +10111111111111111111111111111111111111111111111111111111111111111111111101 +2022222222222222222222222222222222222222222222222222222222222222222222222202 ;; PUSH32 +) \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/stack_test.evm b/evmjit/evmcc/test/stack/stack_test.evm new file mode 100644 index 000000000..02417c967 --- /dev/null +++ b/evmjit/evmcc/test/stack/stack_test.evm @@ -0,0 +1 @@ +65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290 diff --git a/evmjit/evmcc/test/stack/stack_test.lll b/evmjit/evmcc/test/stack/stack_test.lll new file mode 100644 index 000000000..fdf83594c --- /dev/null +++ b/evmjit/evmcc/test/stack/stack_test.lll @@ -0,0 +1,8 @@ + +(asm +123 +SSTORE +SLOAD +123 +SUB +) \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/stackjump.evm b/evmjit/evmcc/test/stack/stackjump.evm new file mode 100644 index 000000000..baddec42e --- /dev/null +++ b/evmjit/evmcc/test/stack/stackjump.evm @@ -0,0 +1 @@ +600460066009601358600a036000545b6000f260005401600958 \ No newline at end of file diff --git a/evmjit/evmcc/test/stack/stackjump.lll b/evmjit/evmcc/test/stack/stackjump.lll new file mode 100644 index 000000000..f5da5e733 --- /dev/null +++ b/evmjit/evmcc/test/stack/stackjump.lll @@ -0,0 +1,3 @@ +(asm +0x4 0x6 0x9 0x13 JUMP 0xa SUB 0x0 MSTORE MSIZE 0x0 RETURN 0x0 MSTORE ADD 0x9 JUMP +) diff --git a/evmjit/evmcc/test/stack/swap.evm b/evmjit/evmcc/test/stack/swap.evm new file mode 100644 index 000000000..d17f0ee09 --- /dev/null +++ b/evmjit/evmcc/test/stack/swap.evm @@ -0,0 +1 @@ +600560026001600c59505000906001601559505000036000546001601ff2 diff --git a/evmjit/evmcc/test/stack/swap.lll b/evmjit/evmcc/test/stack/swap.lll new file mode 100644 index 000000000..90dee585d --- /dev/null +++ b/evmjit/evmcc/test/stack/swap.lll @@ -0,0 +1,31 @@ +(asm +5 ;; 0 +2 ;; 2 +1 ;; 4 +12 ;; 6 +JUMPI ;; 8 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 + +;; stack = 2,1 +SWAP1 ;; 12 +1 ;; 13 +21 ;; 15 +JUMPI ;; 17 + +POP ;; 18 +POP ;; 19 +STOP ;; 20 + +;; stack = 1,2 +SUB ;; 21 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmjit/evmcc/test/stack/swapswap.evm b/evmjit/evmcc/test/stack/swapswap.evm new file mode 100644 index 000000000..fb4f1bf75 --- /dev/null +++ b/evmjit/evmcc/test/stack/swapswap.evm @@ -0,0 +1 @@ +600260056001600c5950500090906001601659505000036000546001601ff2 diff --git a/evmjit/evmcc/test/stack/swapswap.lll b/evmjit/evmcc/test/stack/swapswap.lll new file mode 100644 index 000000000..1fedf726e --- /dev/null +++ b/evmjit/evmcc/test/stack/swapswap.lll @@ -0,0 +1,32 @@ +(asm +2 ;; 0 +5 ;; 2 +1 ;; 4 +12 ;; 6 +JUMPI ;; 8 + +POP ;; 9 +POP ;; 10 +STOP ;; 11 + +;; stack = 2,1 +SWAP1 ;; 12 +SWAP1 ;; 13 +1 ;; 14 +22 ;; 16 +JUMPI ;; 18 + +POP ;; 19 +POP ;; 20 +STOP ;; 21 + +;; stack = 2,1 +SUB ;; 22 +0 +MSTORE +1 +31 +RETURN ;; returns 03 +) + + diff --git a/evmjit/evmcc/test/stack/test.evm b/evmjit/evmcc/test/stack/test.evm new file mode 100644 index 000000000..ea2f1c890 --- /dev/null +++ b/evmjit/evmcc/test/stack/test.evm @@ -0,0 +1 @@ +60018194505050509150 diff --git a/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json b/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json new file mode 100644 index 000000000..d9017517f --- /dev/null +++ b/evmjit/evmcc/test/vmtests/vmArithPerformanceTest.json @@ -0,0 +1,260 @@ +{ + "arith-1" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "999538", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x600a60005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-2" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "995488", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x606460005260005160105760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600556", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-3" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "954988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e860005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + , + + "arith-4" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "549988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x61271060005260005160115760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600656", + "nonce" : "0", + "storage" : { } + } + } + } + + + , + + + "arith-5" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5499988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620186a060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +, + + "arith-6" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "data" : "0x", + "gas" : "100000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "54999988", + "out" : "0x0000000000000000000000000000000000000000000000000000001b9c636491", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f424060005260005160125760206020f26001600190016007026005016002900460049006602190056015016003026005900760030360090160110a60205260005160019003600052600756", + "nonce" : "0", + "storage" : { } + } + } + } + +} diff --git a/evmjit/evmcc/test/vmtests/vmPerformanceTest.json b/evmjit/evmcc/test/vmtests/vmPerformanceTest.json new file mode 100644 index 000000000..604e45993 --- /dev/null +++ b/evmjit/evmcc/test/vmtests/vmPerformanceTest.json @@ -0,0 +1,214 @@ +{ + "mulmodloop" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x60015b68010000000000000000908060010109600356", + "data" : "0x", + "gas" : "10000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "0", + "out" : "0x0", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015b68010000000000000000908060010109600356", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x60015b68010000000000000000908060010109600356", + "nonce" : "0", + "storage" : { } + } + } + }, + + + "for-1e06" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "data" : "0x", + "gas" : "30000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "6999982", + "out" : "0x00", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x620f42406080525b6000608051111560285760a0516080510160a0526001608051036080526007565b", + "nonce" : "0", + "storage" : { } + } + } + }, + + "fib25" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "100000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "data" : "0x", + "gas" : "40000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "5886377", + "out" : "0x00000000000000000000000000000000000000000000000000000000000cb228", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6007601e6010565b60005260206000f25b600381106030576021600282036010565b602b600183036010565b016033565b60015b90509056", + "nonce" : "0", + "storage" : { + } + } + } + }, + + "ackermann37" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "20000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "data" : "0x", + "gas" : "20000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "913456", + "out" : "0x00000000000000000000000000000000000000000000000000000000000003fd", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6009600360076012565b60005260206000f25b60008214604a5760008114603957603560018303603184600185036012565b6012565b6046565b60456001830360016012565b5b604f565b600181015b905090509056", + "nonce" : "0", + "storage" : { + } + } + } + }, + + "jumptable100" : { + "callcreates" : [ + ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "data" : "0x", + "gas" : "1000000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "389596", + "out" : "0x0000000000000000000000000000000000000000000000000000000000000064", + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "nonce" : "0", + "storage" : { + } + } + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "0x6103e85b60019003806000146104605761001a600160005256005b610025600260005256005b610030600360005256005b61003b600460005256005b610046600560005256005b610051600660005256005b61005c600760005256005b610067600860005256005b610072600960005256005b61007d600a60005256005b610088600b60005256005b610093600c60005256005b61009e600d60005256005b6100a9600e60005256005b6100b4600f60005256005b6100bf601060005256005b6100ca601160005256005b6100d5601260005256005b6100e0601360005256005b6100eb601460005256005b6100f6601560005256005b610101601660005256005b61010c601760005256005b610117601860005256005b610122601960005256005b61012d601a60005256005b610138601b60005256005b610143601c60005256005b61014e601d60005256005b610159601e60005256005b610164601f60005256005b61016f602060005256005b61017a602160005256005b610185602260005256005b610190602360005256005b61019b602460005256005b6101a6602560005256005b6101b1602660005256005b6101bc602760005256005b6101c7602860005256005b6101d2602960005256005b6101dd602a60005256005b6101e8602b60005256005b6101f3602c60005256005b6101fe602d60005256005b610209602e60005256005b610214602f60005256005b61021f603060005256005b61022a603160005256005b610235603260005256005b610240603360005256005b61024b603460005256005b610256603560005256005b610261603660005256005b61026c603760005256005b610277603860005256005b610282603960005256005b61028d603a60005256005b610298603b60005256005b6102a3603c60005256005b6102ae603d60005256005b6102b9603e60005256005b6102c4603f60005256005b6102cf604060005256005b6102da604160005256005b6102e5604260005256005b6102f0604360005256005b6102fb604460005256005b610306604560005256005b610311604660005256005b61031c604760005256005b610327604860005256005b610332604960005256005b61033d604a60005256005b610348604b60005256005b610353604c60005256005b61035e604d60005256005b610369604e60005256005b610374604f60005256005b61037f605060005256005b61038a605160005256005b610395605260005256005b6103a0605360005256005b6103ab605460005256005b6103b6605560005256005b6103c1605660005256005b6103cc605760005256005b6103d7605860005256005b6103e2605960005256005b6103ed605a60005256005b6103f8605b60005256005b610403605c60005256005b61040e605d60005256005b610419605e60005256005b610424605f60005256005b61042f606060005256005b61043a606160005256005b610445606260005256005b610450606360005256005b61045b606460005256005b610003565b60206000f2", + "nonce" : "0", + "storage" : { + } + } + } + }, + +} diff --git a/evmjit/evmcc/test/vmtests/vm_jump.json b/evmjit/evmcc/test/vmtests/vm_jump.json new file mode 100644 index 000000000..6b63edeae --- /dev/null +++ b/evmjit/evmcc/test/vmtests/vm_jump.json @@ -0,0 +1,41 @@ +{ + "jumpi_at_the_end" : { + "callcreates" : [ ], + "env" : { + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentDifficulty" : "256", + "currentGasLimit" : "10000000", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "data" : "0x", + "gas" : "1000", + "gasPrice" : "100000000000000", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000" + }, + "gas" : "895", + "out" : "0x0", + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + }, + "post" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "code" : "(asm 10 0 MSTORE JUMPDEST 0 MLOAD 1 SWAP1 SUB DUP1 0 MSTORE 6 JUMPI)", + "nonce" : "0", + "storage" : {} + } + } + } +} diff --git a/evmjit/libevmjit-cpp/CMakeLists.txt b/evmjit/libevmjit-cpp/CMakeLists.txt new file mode 100644 index 000000000..53448332b --- /dev/null +++ b/evmjit/libevmjit-cpp/CMakeLists.txt @@ -0,0 +1,24 @@ +set(TARGET_NAME evmjit-cpp) + +# Boost +find_package(Boost REQUIRED) + +set(SOURCES + Env.cpp + JitVM.cpp JitVM.h +) +source_group("" FILES ${SOURCES}) + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # add PIC for archive +endif() + +add_library(${TARGET_NAME} ${SOURCES}) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "libs") + +include_directories(../..) +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +target_link_libraries(${TARGET_NAME} evmjit) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp new file mode 100644 index 000000000..11882d79d --- /dev/null +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -0,0 +1,117 @@ + +#pragma GCC diagnostic ignored "-Wconversion" +#include +#include +#include + +#include "Utils.h" + +extern "C" +{ + #ifdef _MSC_VER + #define EXPORT __declspec(dllexport) + #else + #define EXPORT + #endif + + using namespace dev; + using namespace dev::eth; + using jit::i256; + + EXPORT void env_sload(ExtVMFace* _env, i256* _index, i256* o_value) + { + auto index = llvm2eth(*_index); + auto value = _env->store(index); // Interface uses native endianness + *o_value = eth2llvm(value); + } + + EXPORT void env_sstore(ExtVMFace* _env, i256* _index, i256* _value) + { + auto index = llvm2eth(*_index); + auto value = llvm2eth(*_value); + + if (value == 0 && _env->store(index) != 0) // If delete + _env->sub.refunds += c_sstoreRefundGas; // Increase refund counter + + _env->setStore(index, value); // Interface uses native endianness + } + + EXPORT void env_balance(ExtVMFace* _env, h256* _address, i256* o_value) + { + auto u = _env->balance(right160(*_address)); + *o_value = eth2llvm(u); + } + + EXPORT void env_blockhash(ExtVMFace* _env, i256* _number, h256* o_hash) + { + *o_hash = _env->blockhash(llvm2eth(*_number)); + } + + EXPORT void env_create(ExtVMFace* _env, int64_t* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + { + auto endowment = llvm2eth(*_endowment); + if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) + { + _env->subBalance(endowment); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); + *o_address = address; + } + else + *o_address = {}; + } + + EXPORT bool env_call(ExtVMFace* _env, int64_t* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + { + auto value = llvm2eth(*_value); + if (_env->balance(_env->myAddress) >= value && _env->depth < 1024) + { + _env->subBalance(value); + auto receiveAddress = right160(*_receiveAddress); + auto inRef = bytesConstRef{_inBeg, _inSize}; + auto outRef = bytesRef{_outBeg, _outSize}; + auto codeAddress = right160(*_codeAddress); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); + return ret; + } + + return false; + } + + EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) + { + auto hash = sha3({_begin, _size}); + *o_hash = hash; + } + + EXPORT byte const* env_extcode(ExtVMFace* _env, h256* _addr256, uint64_t* o_size) + { + auto addr = right160(*_addr256); + auto& code = _env->codeAt(addr); + *o_size = code.size(); + return code.data(); + } + + EXPORT void env_log(ExtVMFace* _env, byte* _beg, uint64_t _size, h256* _topic1, h256* _topic2, h256* _topic3, h256* _topic4) + { + dev::h256s topics; + + if (_topic1) + topics.push_back(*_topic1); + + if (_topic2) + topics.push_back(*_topic2); + + if (_topic3) + topics.push_back(*_topic3); + + if (_topic4) + topics.push_back(*_topic4); + + _env->log(std::move(topics), {_beg, _size}); + } +} + diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp new file mode 100644 index 000000000..55dcd94f8 --- /dev/null +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -0,0 +1,83 @@ + +#pragma GCC diagnostic ignored "-Wconversion" +#include "JitVM.h" +#include +#include +#include +#include +#include "Utils.h" + +namespace dev +{ +namespace eth +{ + +extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below + +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) +{ + using namespace jit; + + auto rejected = false; + // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope + rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= _ext.gasPrice > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + + if (rejected) + { + UNTESTED; + std::cerr << "Rejected\n"; + VMFactory::setKind(VMKind::Interpreter); + m_fallbackVM = VMFactory::create(m_gas); + VMFactory::setKind(VMKind::JIT); + return m_fallbackVM->go(_ext, _onOp, _step); + } + + m_data.gas = static_cast(m_gas); + m_data.gasPrice = static_cast(_ext.gasPrice); + m_data.callData = _ext.data.data(); + m_data.callDataSize = _ext.data.size(); + m_data.address = eth2llvm(fromAddress(_ext.myAddress)); + m_data.caller = eth2llvm(fromAddress(_ext.caller)); + m_data.origin = eth2llvm(fromAddress(_ext.origin)); + m_data.callValue = eth2llvm(_ext.value); + m_data.coinBase = eth2llvm(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.difficulty = eth2llvm(_ext.currentBlock.difficulty); + m_data.gasLimit = eth2llvm(_ext.currentBlock.gasLimit); + m_data.number = static_cast(_ext.currentBlock.number); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.code = _ext.code.data(); + m_data.codeSize = _ext.code.size(); + m_data.codeHash = eth2llvm(sha3(_ext.code)); + + auto env = reinterpret_cast(&_ext); + auto exitCode = m_engine.run(&m_data, env); + switch (exitCode) + { + case ReturnCode::Suicide: + _ext.suicide(right160(llvm2eth(m_data.address))); + break; + + case ReturnCode::BadJumpDestination: + BOOST_THROW_EXCEPTION(BadJumpDestination()); + case ReturnCode::OutOfGas: + BOOST_THROW_EXCEPTION(OutOfGas()); + case ReturnCode::StackTooSmall: + BOOST_THROW_EXCEPTION(StackTooSmall()); + case ReturnCode::BadInstruction: + BOOST_THROW_EXCEPTION(BadInstruction()); + case ReturnCode::LinkerWorkaround: // never happens + env_sload(); // but forces linker to include env_* JIT callback functions + break; + default: + break; + } + + m_gas = m_data.gas; // TODO: Remove m_gas field + return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)}; +} + +} +} diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h new file mode 100644 index 000000000..58caa3648 --- /dev/null +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ + +class JitVM: public VMFace +{ + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + +private: + friend class VMFactory; + explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} + + jit::RuntimeData m_data; + jit::ExecutionEngine m_engine; + std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT +}; + + +} +} diff --git a/evmjit/libevmjit-cpp/Utils.h b/evmjit/libevmjit-cpp/Utils.h new file mode 100644 index 000000000..ac796920b --- /dev/null +++ b/evmjit/libevmjit-cpp/Utils.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +namespace dev +{ +namespace eth +{ + +inline u256 llvm2eth(jit::i256 _i) +{ + u256 u = 0; + u |= _i.d; + u <<= 64; + u |= _i.c; + u <<= 64; + u |= _i.b; + u <<= 64; + u |= _i.a; + return u; +} + +inline jit::i256 eth2llvm(u256 _u) +{ + jit::i256 i; + u256 mask = 0xFFFFFFFFFFFFFFFF; + i.a = static_cast(_u & mask); + _u >>= 64; + i.b = static_cast(_u & mask); + _u >>= 64; + i.c = static_cast(_u & mask); + _u >>= 64; + i.d = static_cast(_u & mask); + return i; +} + +} +} diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp new file mode 100644 index 000000000..ddf06b463 --- /dev/null +++ b/evmjit/libevmjit/Arith256.cpp @@ -0,0 +1,406 @@ +#include "Arith256.h" + +#include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Endianness.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Arith256::Arith256(llvm::IRBuilder<>& _builder) : + CompilerHelper(_builder) +{} + +void Arith256::debug(llvm::Value* _value, char _c) +{ + if (!m_debug) + { + llvm::Type* argTypes[] = {Type::Word, m_builder.getInt8Ty()}; + m_debug = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "debug", getModule()); + } + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); +} + +llvm::Function* Arith256::getMulFunc() +{ + auto& func = m_mul; + if (!func) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mul", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i64 = Type::Size; + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i64, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i64, "y.lo"); + auto x_mi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(64)), i64); + auto y_mi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(64)), i64); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128); + + auto t1 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_lo, i128)); + auto t2 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), m_builder.CreateZExt(y_mi, i128)); + auto t3 = m_builder.CreateMul(m_builder.CreateZExt(x_lo, i128), y_hi); + auto t4 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_lo, i128)); + auto t5 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), m_builder.CreateZExt(y_mi, i128)); + auto t6 = m_builder.CreateMul(m_builder.CreateZExt(x_mi, i128), y_hi); + auto t7 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_lo, i128)); + auto t8 = m_builder.CreateMul(x_hi, m_builder.CreateZExt(y_mi, i128)); + + auto p = m_builder.CreateZExt(t1, i256); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i256), Constant::get(64))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t5, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t6, i256), Constant::get(192))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t7, i256), Constant::get(128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); + m_builder.CreateRet(p); + } + return func; +} + +llvm::Function* Arith256::getMul512Func() +{ + auto& func = m_mul512; + if (!func) + { + auto i512 = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + + InsertPointGuard guard{m_builder}; + auto bb = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + m_builder.SetInsertPoint(bb); + auto i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateZExt(m_builder.CreateTrunc(x, i128, "x.lo"), i256); + auto y_lo = m_builder.CreateZExt(m_builder.CreateTrunc(y, i128, "y.lo"), i256); + auto x_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"), i256); + auto y_hi = m_builder.CreateZExt(m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"), i256); + + auto t1 = createCall(getMulFunc(), {x_lo, y_lo}); + auto t2 = createCall(getMulFunc(), {x_lo, y_hi}); + auto t3 = createCall(getMulFunc(), {x_hi, y_lo}); + auto t4 = createCall(getMulFunc(), {x_hi, y_hi}); + + auto p = m_builder.CreateZExt(t1, i512); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t2, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t3, i512), m_builder.getIntN(512, 128))); + p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t4, i512), m_builder.getIntN(512, 256))); + m_builder.CreateRet(p); + } + return func; +} + +llvm::Function* Arith256::getDivFunc(llvm::Type* _type) +{ + auto& func = _type == Type::Word ? m_div : m_div512; + + if (!func) + { + // Based of "Improved shift divisor algorithm" from "Software Integer Division" by Microsoft Research + // The following algorithm also handles divisor of value 0 returning 0 for both quotient and reminder + + llvm::Type* argTypes[] = {_type, _type}; + auto retType = llvm::StructType::get(m_builder.getContext(), llvm::ArrayRef{argTypes}); + auto funcName = _type == Type::Word ? "div" : "div512"; + func = llvm::Function::Create(llvm::FunctionType::get(retType, argTypes, false), llvm::Function::PrivateLinkage, funcName, getModule()); + + auto zero = llvm::ConstantInt::get(_type, 0); + auto one = llvm::ConstantInt::get(_type, 1); + + auto x = &func->getArgumentList().front(); + x->setName("x"); + auto yArg = x->getNextNode(); + yArg->setName("y"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func); + auto mainBB = llvm::BasicBlock::Create(m_builder.getContext(), "Main", func); + auto loopBB = llvm::BasicBlock::Create(m_builder.getContext(), "Loop", func); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto yNonZero = m_builder.CreateICmpNE(yArg, zero); + auto yLEx = m_builder.CreateICmpULE(yArg, x); + auto r0 = m_builder.CreateSelect(yNonZero, x, zero, "r0"); + m_builder.CreateCondBr(m_builder.CreateAnd(yLEx, yNonZero), mainBB, returnBB); + + m_builder.SetInsertPoint(mainBB); + auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, _type); + // both y and r are non-zero + auto yLz = m_builder.CreateCall2(ctlzIntr, yArg, m_builder.getInt1(true), "y.lz"); + auto rLz = m_builder.CreateCall2(ctlzIntr, r0, m_builder.getInt1(true), "r.lz"); + auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); + auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); + auto y0 = m_builder.CreateShl(yArg, i0); + if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts + { + const auto treshold = m_builder.getIntN(512, 128); + auto highShift = m_builder.CreateICmpUGT(i0, treshold); + auto s = m_builder.CreateNUWSub(i0, treshold); + auto yhs = m_builder.CreateShl(yArg, treshold); + yhs = m_builder.CreateShl(yhs, s); + y0 = m_builder.CreateSelect(highShift, yhs, y0); + } + y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result + m_builder.CreateBr(loopBB); + + m_builder.SetInsertPoint(loopBB); + auto yPhi = m_builder.CreatePHI(_type, 2, "y.phi"); + auto rPhi = m_builder.CreatePHI(_type, 2, "r.phi"); + auto iPhi = m_builder.CreatePHI(_type, 2, "i.phi"); + auto qPhi = m_builder.CreatePHI(_type, 2, "q.phi"); + auto rUpdate = m_builder.CreateNUWSub(rPhi, yPhi); + auto qUpdate = m_builder.CreateOr(qPhi, one); // q += 1, q lowest bit is 0 + auto rGEy = m_builder.CreateICmpUGE(rPhi, yPhi); + auto r1 = m_builder.CreateSelect(rGEy, rUpdate, rPhi, "r1"); + auto q1 = m_builder.CreateSelect(rGEy, qUpdate, qPhi, "q"); + auto iZero = m_builder.CreateICmpEQ(iPhi, zero); + m_builder.CreateCondBr(iZero, returnBB, continueBB); + + m_builder.SetInsertPoint(continueBB); + auto i2 = m_builder.CreateNUWSub(iPhi, one); + auto q2 = m_builder.CreateShl(q1, one); + auto y2 = m_builder.CreateLShr(yPhi, one); + m_builder.CreateBr(loopBB); + + yPhi->addIncoming(y0, mainBB); + yPhi->addIncoming(y2, continueBB); + rPhi->addIncoming(r0, mainBB); + rPhi->addIncoming(r1, continueBB); + iPhi->addIncoming(i0, mainBB); + iPhi->addIncoming(i2, continueBB); + qPhi->addIncoming(zero, mainBB); + qPhi->addIncoming(q2, continueBB); + + m_builder.SetInsertPoint(returnBB); + auto qRet = m_builder.CreatePHI(_type, 2, "q.ret"); + qRet->addIncoming(zero, entryBB); + qRet->addIncoming(q1, loopBB); + auto rRet = m_builder.CreatePHI(_type, 2, "r.ret"); + rRet->addIncoming(r0, entryBB); + rRet->addIncoming(r1, loopBB); + auto ret = m_builder.CreateInsertValue(llvm::UndefValue::get(retType), qRet, 0, "ret0"); + ret = m_builder.CreateInsertValue(ret, rRet, 1, "ret"); + m_builder.CreateRet(ret); + } + return func; +} + +llvm::Function* Arith256::getExpFunc() +{ + if (!m_exp) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word}; + m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "exp", getModule()); + + auto base = &m_exp->getArgumentList().front(); + base->setName("base"); + auto exponent = base->getNextNode(); + exponent->setName("exponent"); + + InsertPointGuard guard{m_builder}; + + // while (e != 0) { + // if (e % 2 == 1) + // r *= b; + // b *= b; + // e /= 2; + // } + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", m_exp); + auto headerBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopHeader", m_exp); + auto bodyBB = llvm::BasicBlock::Create(m_builder.getContext(), "LoopBody", m_exp); + auto updateBB = llvm::BasicBlock::Create(m_builder.getContext(), "ResultUpdate", m_exp); + auto continueBB = llvm::BasicBlock::Create(m_builder.getContext(), "Continue", m_exp); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); + + m_builder.SetInsertPoint(entryBB); + m_builder.CreateBr(headerBB); + + m_builder.SetInsertPoint(headerBB); + auto r = m_builder.CreatePHI(Type::Word, 2, "r"); + auto b = m_builder.CreatePHI(Type::Word, 2, "b"); + auto e = m_builder.CreatePHI(Type::Word, 2, "e"); + auto eNonZero = m_builder.CreateICmpNE(e, Constant::get(0), "e.nonzero"); + m_builder.CreateCondBr(eNonZero, bodyBB, returnBB); + + m_builder.SetInsertPoint(bodyBB); + auto eOdd = m_builder.CreateICmpNE(m_builder.CreateAnd(e, Constant::get(1)), Constant::get(0), "e.isodd"); + m_builder.CreateCondBr(eOdd, updateBB, continueBB); + + m_builder.SetInsertPoint(updateBB); + auto r0 = createCall(getMulFunc(), {r, b}); + m_builder.CreateBr(continueBB); + + m_builder.SetInsertPoint(continueBB); + auto r1 = m_builder.CreatePHI(Type::Word, 2, "r1"); + r1->addIncoming(r, bodyBB); + r1->addIncoming(r0, updateBB); + auto b1 = createCall(getMulFunc(), {b, b}); + auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); + m_builder.CreateBr(headerBB); + + r->addIncoming(Constant::get(1), entryBB); + r->addIncoming(r1, continueBB); + b->addIncoming(base, entryBB); + b->addIncoming(b1, continueBB); + e->addIncoming(exponent, entryBB); + e->addIncoming(e1, continueBB); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(r); + } + return m_exp; +} + +llvm::Function* Arith256::getAddModFunc() +{ + if (!m_addmod) + { + auto i512Ty = m_builder.getIntNTy(512); + llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; + m_addmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "addmod", getModule()); + + auto x = &m_addmod->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + auto mod = y->getNextNode(); + mod->setName("m"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_addmod); + m_builder.SetInsertPoint(entryBB); + auto x512 = m_builder.CreateZExt(x, i512Ty, "x512"); + auto y512 = m_builder.CreateZExt(y, i512Ty, "y512"); + auto m512 = m_builder.CreateZExt(mod, i512Ty, "m512"); + auto s = m_builder.CreateAdd(x512, y512, "s"); + auto d = createCall(getDivFunc(i512Ty), {s, m512}); + auto r = m_builder.CreateExtractValue(d, 1, "r"); + m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + } + return m_addmod; +} + +llvm::Function* Arith256::getMulModFunc() +{ + if (!m_mulmod) + { + llvm::Type* argTypes[] = {Type::Word, Type::Word, Type::Word}; + m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); + + auto i512Ty = m_builder.getIntNTy(512); + auto x = &m_mulmod->getArgumentList().front(); + x->setName("x"); + auto y = x->getNextNode(); + y->setName("y"); + auto mod = y->getNextNode(); + mod->setName("mod"); + + InsertPointGuard guard{m_builder}; + + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); + m_builder.SetInsertPoint(entryBB); + auto p = createCall(getMul512Func(), {x, y}); + auto m = m_builder.CreateZExt(mod, i512Ty, "m"); + auto d = createCall(getDivFunc(i512Ty), {p, m}); + auto r = m_builder.CreateExtractValue(d, 1, "r"); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); + } + return m_mulmod; +} + +llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return createCall(getMulFunc(), {_arg1, _arg2}); +} + +std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) +{ + auto div = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 0, "div"); + auto mod = m_builder.CreateExtractValue(createCall(getDivFunc(Type::Word), {_arg1, _arg2}), 1, "mod"); + return std::make_pair(div, mod); +} + +std::pair Arith256::sdiv(llvm::Value* _x, llvm::Value* _y) +{ + auto xIsNeg = m_builder.CreateICmpSLT(_x, Constant::get(0)); + auto xNeg = m_builder.CreateSub(Constant::get(0), _x); + auto xAbs = m_builder.CreateSelect(xIsNeg, xNeg, _x); + + auto yIsNeg = m_builder.CreateICmpSLT(_y, Constant::get(0)); + auto yNeg = m_builder.CreateSub(Constant::get(0), _y); + auto yAbs = m_builder.CreateSelect(yIsNeg, yNeg, _y); + + auto res = div(xAbs, yAbs); + + // the reminder has the same sign as dividend + auto rNeg = m_builder.CreateSub(Constant::get(0), res.second); + res.second = m_builder.CreateSelect(xIsNeg, rNeg, res.second); + + auto qNeg = m_builder.CreateSub(Constant::get(0), res.first); + auto xyOpposite = m_builder.CreateXor(xIsNeg, yIsNeg); + res.first = m_builder.CreateSelect(xyOpposite, qNeg, res.first); + + return res; +} + +llvm::Value* Arith256::exp(llvm::Value* _arg1, llvm::Value* _arg2) +{ + return createCall(getExpFunc(), {_arg1, _arg2}); +} + +llvm::Value* Arith256::addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return createCall(getAddModFunc(), {_arg1, _arg2, _arg3}); +} + +llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3) +{ + return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); +} + + +} +} +} + +extern "C" +{ + EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) + { + std::cerr << "DEBUG " << std::dec << z << ": " //<< d << c << b << a + << " [" << std::hex << std::setfill('0') << std::setw(16) << d << std::setw(16) << c << std::setw(16) << b << std::setw(16) << a << "]\n"; + } +} diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h new file mode 100644 index 000000000..2513ca568 --- /dev/null +++ b/evmjit/libevmjit/Arith256.h @@ -0,0 +1,47 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Arith256 : public CompilerHelper +{ +public: + Arith256(llvm::IRBuilder<>& _builder); + + llvm::Value* mul(llvm::Value* _arg1, llvm::Value* _arg2); + std::pair div(llvm::Value* _arg1, llvm::Value* _arg2); + std::pair sdiv(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* exp(llvm::Value* _arg1, llvm::Value* _arg2); + llvm::Value* mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + llvm::Value* addmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Value* _arg3); + + void debug(llvm::Value* _value, char _c); + +private: + llvm::Function* getMulFunc(); + llvm::Function* getMul512Func(); + llvm::Function* getDivFunc(llvm::Type* _type); + llvm::Function* getExpFunc(); + llvm::Function* getAddModFunc(); + llvm::Function* getMulModFunc(); + + llvm::Function* m_mul = nullptr; + llvm::Function* m_mul512 = nullptr; + llvm::Function* m_div = nullptr; + llvm::Function* m_div512 = nullptr; + llvm::Function* m_exp = nullptr; + llvm::Function* m_addmod = nullptr; + llvm::Function* m_mulmod = nullptr; + llvm::Function* m_debug = nullptr; +}; + + +} +} +} diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp new file mode 100644 index 000000000..c9e71be9a --- /dev/null +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -0,0 +1,381 @@ +#include "BasicBlock.h" + +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; + +BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_firstInstrIdx{_firstInstrIdx}, + m_begin(_begin), + m_end(_end), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), + m_stack(*this), + m_builder(_builder), + m_isJumpDest(isJumpDest) +{} + +BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)), + m_stack(*this), + m_builder(_builder), + m_isJumpDest(isJumpDest) +{} + +BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) : + m_bblock(_owner) +{} + +void BasicBlock::LocalStack::push(llvm::Value* _value) +{ + assert(_value->getType() == Type::Word); + m_bblock.m_currentStack.push_back(_value); + m_bblock.m_tosOffset += 1; +} + +llvm::Value* BasicBlock::LocalStack::pop() +{ + auto result = get(0); + + if (m_bblock.m_currentStack.size() > 0) + m_bblock.m_currentStack.pop_back(); + + m_bblock.m_tosOffset -= 1; + return result; +} + +/** + * Pushes a copy of _index-th element (tos is 0-th elem). + */ +void BasicBlock::LocalStack::dup(size_t _index) +{ + auto val = get(_index); + push(val); +} + +/** + * Swaps tos with _index-th element (tos is 0-th elem). + * _index must be > 0. + */ +void BasicBlock::LocalStack::swap(size_t _index) +{ + assert(_index > 0); + auto val = get(_index); + auto tos = get(0); + set(_index, tos); + set(0, val); +} + +std::vector::iterator BasicBlock::LocalStack::getItemIterator(size_t _index) +{ + auto& currentStack = m_bblock.m_currentStack; + if (_index < currentStack.size()) + return currentStack.end() - _index - 1; + + // Need to map more elements from the EVM stack + auto nNewItems = 1 + _index - currentStack.size(); + currentStack.insert(currentStack.begin(), nNewItems, nullptr); + + return currentStack.end() - _index - 1; +} + +llvm::Value* BasicBlock::LocalStack::get(size_t _index) +{ + auto& initialStack = m_bblock.m_initialStack; + auto itemIter = getItemIterator(_index); + + if (*itemIter == nullptr) + { + // Need to fetch a new item from the EVM stack + assert(static_cast(_index) >= m_bblock.m_tosOffset); + size_t initialIdx = _index - m_bblock.m_tosOffset; + if (initialIdx >= initialStack.size()) + { + auto nNewItems = 1 + initialIdx - initialStack.size(); + initialStack.insert(initialStack.end(), nNewItems, nullptr); + } + + assert(initialStack[initialIdx] == nullptr); + // Create a dummy value. + std::string name = "get_" + std::to_string(_index); + initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, std::move(name)); + *itemIter = initialStack[initialIdx]; + } + + return *itemIter; +} + +void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word) +{ + auto itemIter = getItemIterator(_index); + *itemIter = _word; +} + + + + + +void BasicBlock::synchronizeLocalStack(Stack& _evmStack) +{ + auto blockTerminator = m_llvmBB->getTerminator(); + assert(blockTerminator != nullptr); + m_builder.SetInsertPoint(blockTerminator); + + auto currIter = m_currentStack.begin(); + auto endIter = m_currentStack.end(); + + // Update (emit set()) changed values + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; + currIter < endIter && idx >= 0; + ++currIter, --idx) + { + assert(static_cast(idx) < m_initialStack.size()); + if (*currIter != m_initialStack[idx]) // value needs update + _evmStack.set(static_cast(idx), *currIter); + } + + if (m_tosOffset < 0) + { + // Pop values + _evmStack.pop(static_cast(-m_tosOffset)); + } + + // Push new values + for (; currIter < endIter; ++currIter) + { + assert(*currIter != nullptr); + _evmStack.push(*currIter); + } + + // Emit get() for all (used) values from the initial stack + for (size_t idx = 0; idx < m_initialStack.size(); ++idx) + { + auto val = m_initialStack[idx]; + if (val == nullptr) + continue; + + llvm::PHINode* phi = llvm::cast(val); + // Insert call to get() just before the PHI node and replace + // the uses of PHI with the uses of this new instruction. + m_builder.SetInsertPoint(phi); + auto newVal = _evmStack.get(idx); // OPT: Value may be never user but we need to check stack heigth + // It is probably a good idea to keep heigth as a local variable accesible by LLVM directly + phi->replaceAllUsesWith(newVal); + phi->eraseFromParent(); + } + + // Reset the stack + m_initialStack.erase(m_initialStack.begin(), m_initialStack.end()); + m_currentStack.erase(m_currentStack.begin(), m_currentStack.end()); + m_tosOffset = 0; +} + +void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRBuilder<>& _builder) +{ + struct BBInfo + { + BasicBlock& bblock; + std::vector predecessors; + size_t inputItems; + size_t outputItems; + std::vector phisToRewrite; + + BBInfo(BasicBlock& _bblock) : + bblock(_bblock), + predecessors(), + inputItems(0), + outputItems(0) + { + auto& initialStack = bblock.m_initialStack; + for (auto it = initialStack.begin(); + it != initialStack.end() && *it != nullptr; + ++it, ++inputItems); + + //if (bblock.localStack().m_tosOffset > 0) + // outputItems = bblock.localStack().m_tosOffset; + auto& exitStack = bblock.m_currentStack; + for (auto it = exitStack.rbegin(); + it != exitStack.rend() && *it != nullptr; + ++it, ++outputItems); + } + }; + + std::map cfg; + + // Create nodes in cfg + for (auto bb : basicBlocks) + cfg.emplace(bb->llvm(), *bb); + + // Create edges in cfg: for each bb info fill the list + // of predecessor infos. + for (auto& pair : cfg) + { + auto bb = pair.first; + auto& info = pair.second; + + for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt) + { + auto predInfoEntry = cfg.find(*predIt); + if (predInfoEntry != cfg.end()) + info.predecessors.push_back(&predInfoEntry->second); + } + } + + // Iteratively compute inputs and outputs of each block, until reaching fixpoint. + bool valuesChanged = true; + while (valuesChanged) + { + if (getenv("EVMCC_DEBUG_BLOCKS")) + { + for (auto& pair : cfg) + std::cerr << pair.second.bblock.llvm()->getName().str() + << ": in " << pair.second.inputItems + << ", out " << pair.second.outputItems + << "\n"; + } + + valuesChanged = false; + for (auto& pair : cfg) + { + auto& info = pair.second; + + if (info.predecessors.empty()) + info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false + + for (auto predInfo : info.predecessors) + { + if (predInfo->outputItems < info.inputItems) + { + info.inputItems = predInfo->outputItems; + valuesChanged = true; + } + else if (predInfo->outputItems > info.inputItems) + { + predInfo->outputItems = info.inputItems; + valuesChanged = true; + } + } + } + } + + // Propagate values between blocks. + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI()); + auto phiIter = bblock.m_initialStack.begin(); + for (size_t index = 0; index < info.inputItems; ++index, ++phiIter) + { + assert(llvm::isa(*phiIter)); + auto phi = llvm::cast(*phiIter); + + for (auto predIt : info.predecessors) + { + auto& predExitStack = predIt->bblock.m_currentStack; + auto value = *(predExitStack.end() - 1 - index); + phi->addIncoming(value, predIt->bblock.llvm()); + } + + // Move phi to the front + if (llvm::BasicBlock::iterator(phi) != bblock.llvm()->begin()) + { + phi->removeFromParent(); + _builder.SetInsertPoint(bblock.llvm(), bblock.llvm()->begin()); + _builder.Insert(phi); + } + } + + // The items pulled directly from predecessors block must be removed + // from the list of items that has to be popped from the initial stack. + auto& initialStack = bblock.m_initialStack; + initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); + // Initial stack shrinks, so the size difference grows: + bblock.m_tosOffset += (int)info.inputItems; + } + + // We must account for the items that were pushed directly to successor + // blocks and thus should not be on the list of items to be pushed onto + // to EVM stack + for (auto& entry : cfg) + { + auto& info = entry.second; + auto& bblock = info.bblock; + + auto& exitStack = bblock.m_currentStack; + exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types + } +} + +void BasicBlock::dump() +{ + dump(std::cerr, false); +} + +void BasicBlock::dump(std::ostream& _out, bool _dotOutput) +{ + llvm::raw_os_ostream out(_out); + + out << (_dotOutput ? "" : "Initial stack:\n"); + for (auto val : m_initialStack) + { + if (val == nullptr) + out << " ?"; + else if (llvm::isa(val)) + out << *val; + else + out << " " << *val; + + out << (_dotOutput ? "\\l" : "\n"); + } + + out << (_dotOutput ? "| " : "Instructions:\n"); + for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins) + out << *ins << (_dotOutput ? "\\l" : "\n"); + + if (! _dotOutput) + out << "Current stack (offset = " << m_tosOffset << "):\n"; + else + out << "|"; + + for (auto val = m_currentStack.rbegin(); val != m_currentStack.rend(); ++val) + { + if (*val == nullptr) + out << " ?"; + else if (llvm::isa(*val)) + out << **val; + else + out << " " << **val; + out << (_dotOutput ? "\\l" : "\n"); + } + + if (! _dotOutput) + out << " ...\n----------------------------------------\n"; +} + + + + +} +} +} + diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h new file mode 100644 index 000000000..7469b7b69 --- /dev/null +++ b/evmjit/libevmjit/BasicBlock.h @@ -0,0 +1,126 @@ +#pragma once + +#include + +#include "Common.h" +#include "Stack.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using instr_idx = uint64_t; + +class BasicBlock +{ +public: + class LocalStack + { + public: + /// Pushes value on stack + void push(llvm::Value* _value); + + /// Pops and returns top value + llvm::Value* pop(); + + /// Duplicates _index'th value on stack + void dup(size_t _index); + + /// Swaps _index'th value on stack with a value on stack top. + /// @param _index Index of value to be swaped. Must be > 0. + void swap(size_t _index); + + private: + LocalStack(BasicBlock& _owner); + LocalStack(LocalStack const&) = delete; + void operator=(LocalStack const&) = delete; + friend BasicBlock; + + /// Gets _index'th value from top (counting from 0) + llvm::Value* get(size_t _index); + + /// Sets _index'th value from top (counting from 0) + void set(size_t _index, llvm::Value* _value); + + std::vector::iterator getItemIterator(size_t _index); + + private: + BasicBlock& m_bblock; + }; + + explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + + BasicBlock(const BasicBlock&) = delete; + BasicBlock& operator=(const BasicBlock&) = delete; + + llvm::BasicBlock* llvm() { return m_llvmBB; } + + instr_idx firstInstrIdx() const { return m_firstInstrIdx; } + code_iterator begin() const { return m_begin; } + code_iterator end() const { return m_end; } + + bool isJumpDest() const { return m_isJumpDest; } + + llvm::Value* getJumpTarget() const { return m_jumpTarget; } + void setJumpTarget(llvm::Value* _jumpTarget) { m_jumpTarget = _jumpTarget; } + + LocalStack& localStack() { return m_stack; } + + /// Optimization: propagates values between local stacks in basic blocks + /// to avoid excessive pushing/popping on the EVM stack. + static void linkLocalStacks(std::vector _basicBlocks, llvm::IRBuilder<>& _builder); + + /// Synchronize current local stack with the EVM stack. + void synchronizeLocalStack(Stack& _evmStack); + + /// Prints local stack and block instructions to stderr. + /// Useful for calling in a debugger session. + void dump(); + void dump(std::ostream& os, bool _dotOutput = false); + +private: + instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block + code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block + code_iterator const m_end = {}; ///< Iterator pointing code end of the block + + llvm::BasicBlock* const m_llvmBB; + + /// Basic black state vector (stack) - current/end values and their positions on stack + /// @internal Must be AFTER m_llvmBB + LocalStack m_stack; + + llvm::IRBuilder<>& m_builder; + + /// This stack contains LLVM values that correspond to items found at + /// the EVM stack when the current basic block starts executing. + /// Location 0 corresponds to the top of the EVM stack, location 1 is + /// the item below the top and so on. The stack grows as the code + /// accesses more items on the EVM stack but once a value is put on + /// the stack, it will never be replaced. + std::vector m_initialStack; + + /// This stack tracks the contents of the EVM stack as the basic block + /// executes. It may grow on both sides, as the code pushes items on + /// top of the stack or changes existing items. + std::vector m_currentStack; + + /// How many items higher is the current stack than the initial one. + /// May be negative. + int m_tosOffset = 0; + + /// Is the basic block a valid jump destination. + /// JUMPDEST is the first instruction of the basic block. + bool const m_isJumpDest = false; + + /// If block finishes with dynamic jump target index is stored here + llvm::Value* m_jumpTarget = nullptr; +}; + +} +} +} + diff --git a/evmjit/libevmjit/BuildInfo.h.in b/evmjit/libevmjit/BuildInfo.h.in new file mode 100644 index 000000000..204b4d89b --- /dev/null +++ b/evmjit/libevmjit/BuildInfo.h.in @@ -0,0 +1,10 @@ + +#define EVMJIT_VERSION "${EVMJIT_VERSION}" +#define EVMJIT_VERSION_MAJOR ${EVMJIT_VERSION_MAJOR} +#define EVMJIT_VERSION_MINOR ${EVMJIT_VERSION_MINOR} +#define EVMJIT_VERSION_PATCH ${EVMJIT_VERSION_PATCH} +#define EVMJIT_VERSION_PRERELEASE "${EVMJIT_VERSION_PRERELEASE}" +#define EVMJIT_VERSION_FULL "${EVMJIT_VERSION_FULL}" + +#define LLVM_VERSION "${LLVM_PACKAGE_VERSION}" +#define LLVM_ASSERTIONS "${LLVM_ENABLE_ASSERTIONS}" diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt new file mode 100644 index 000000000..943c64e42 --- /dev/null +++ b/evmjit/libevmjit/CMakeLists.txt @@ -0,0 +1,68 @@ +set(TARGET_NAME evmjit) + +file(GLOB SOURCES "*.cpp") +file(GLOB HEADERS "*.h") +set(INTERFACE_HEADERS interface.h) +source_group("" FILES ${HEADERS}) +source_group("" FILES ${SOURCES}) + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") +endif() + + +set(EVMJIT_VERSION "0.0.0") +set(EVMJIT_VERSION_MAJOR 0) +set(EVMJIT_VERSION_MINOR 0) +set(EVMJIT_VERSION_PATCH 0) +set(EVMJIT_VERSION_FULL "v0.0.0-nogit") + +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always --match v* + OUTPUT_VARIABLE EVMJIT_VERSION_FULL OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") + string(SUBSTRING ${EVMJIT_VERSION_FULL} 1 -1 EVMJIT_VERSION_FULL) # skip "v" + string(REPLACE "-" ";" VERSION_COMPONENTS ${EVMJIT_VERSION_FULL}) + list(LENGTH VERSION_COMPONENTS NUM_VERSION_COMPONENTS) + list(GET VERSION_COMPONENTS 0 EVMJIT_VERSION) + string(REPLACE "." ";" VERSION_NUMBERS ${EVMJIT_VERSION}) + list(LENGTH VERSION_NUMBERS NUM_VERSION_NUMBERS) + list(GET VERSION_NUMBERS 0 EVMJIT_VERSION_MAJOR) + list(GET VERSION_NUMBERS 1 EVMJIT_VERSION_MINOR) + if(${NUM_VERSION_NUMBERS} GREATER 2) + list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional + endif() + if(${NUM_VERSION_COMPONENTS} GREATER 1) + list(GET VERSION_COMPONENTS 1 VERSION_PRERELEASE_CANDIDATE) + string(REGEX MATCH "^[a-zA-Z]+.*" EVMJIT_VERSION_PRERELEASE ${VERSION_PRERELEASE_CANDIDATE}) # prerelease starts with letter + endif() +endif() + +if(${EVMJIT_VERSION_MAJOR} EQUAL 0) + set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}") +else() + set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) +endif() + +configure_file(BuildInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/BuildInfo.gen.h) + +message(STATUS "EVM JIT version: ${EVMJIT_VERSION_MAJOR}.${EVMJIT_VERSION_MINOR}.${EVMJIT_VERSION_PATCH} ${EVMJIT_VERSION_PRERELEASE} (${EVMJIT_VERSION_FULL})") + +add_library(${TARGET_NAME} SHARED ${SOURCES} ${HEADERS} gen/BuildInfo.gen.h) +set_target_properties(${TARGET_NAME} PROPERTIES + VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} + FOLDER "libs") + +include_directories(${LLVM_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/gen) + +target_link_libraries(${TARGET_NAME} PRIVATE ${LLVM_LIBS}) + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") + +install(TARGETS ${TARGET_NAME} LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin) +#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) \ No newline at end of file diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp new file mode 100644 index 000000000..fe226eefb --- /dev/null +++ b/evmjit/libevmjit/Cache.cpp @@ -0,0 +1,120 @@ +#include "Cache.h" + +#include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "ExecutionEngine.h" +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) + +namespace +{ + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; +} + +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) +{ + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; +} + +std::unique_ptr Cache::getObject(std::string const& id) +{ + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + CACHE_LOG << id << ": search\n"; + if (!CHECK(!g_lastObject)) + g_lastObject = nullptr; + + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs", id); + +#if defined(__GNUC__) && !defined(NDEBUG) + llvm::sys::fs::file_status st; + auto err = llvm::sys::fs::status(cachePath.str(), st); + if (err) + return nullptr; + auto mtime = st.getLastModificationTime().toEpochTime(); + + std::tm tm; + strptime(__DATE__ __TIME__, " %b %d %Y %H:%M:%S", &tm); + auto btime = (uint64_t)std::mktime(&tm); + if (btime > mtime) + return nullptr; +#endif + + if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) + g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory)) + std::cerr << r.getError().message(); // TODO: Add log + + if (g_lastObject) // if object found create fake module + { + CACHE_LOG << id << ": found\n"; + auto&& context = llvm::getGlobalContext(); + auto module = std::unique_ptr(new llvm::Module(id, context)); + auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(context), {}, false); + auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); + return module; + } + CACHE_LOG << id << ": not found\n"; + return nullptr; +} + + +void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) +{ + if (g_listener) + g_listener->stateChanged(ExecState::CacheWrite); + + auto&& id = _module->getModuleIdentifier(); + llvm::SmallString<256> cachePath; + llvm::sys::path::system_temp_directory(false, cachePath); + llvm::sys::path::append(cachePath, "evm_objs"); + + if (llvm::sys::fs::create_directory(cachePath.str())) + return; // TODO: Add log + + llvm::sys::path::append(cachePath, id); + + CACHE_LOG << id << ": write\n"; + std::string error; + llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); + cacheFile << _object->getBuffer(); +} + +llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) +{ + CACHE_LOG << _module->getModuleIdentifier() << ": use\n"; + auto o = g_lastObject; + g_lastObject = nullptr; + return o; +} + +} +} +} diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h new file mode 100644 index 000000000..e8f01d38d --- /dev/null +++ b/evmjit/libevmjit/Cache.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class ExecutionEngineListener; + +class ObjectCache : public llvm::ObjectCache +{ +public: + /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. + virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) final override; + + /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that + /// contains the object which corresponds with Module M, or 0 if an object is + /// not available. The caller owns both the MemoryBuffer returned by this + /// and the memory it references. + virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; +}; + + +class Cache +{ +public: + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); + static std::unique_ptr getObject(std::string const& id); +}; + +} +} +} diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h new file mode 100644 index 000000000..62731292f --- /dev/null +++ b/evmjit/libevmjit/Common.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +#ifdef _MSC_VER +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using byte = uint8_t; +using bytes = std::vector; +using bytes_ref = std::tuple; +using code_iterator = byte const*; + +struct NoteChannel {}; // FIXME: Use some log library? + +enum class ReturnCode +{ + // Success codes + Stop = 0, + Return = 1, + Suicide = 2, + + // Standard error codes + OutOfGas = -1, + StackTooSmall = -2, + BadJumpDestination = -3, + BadInstruction = -4, + Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected + + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, + + UnexpectedException = -111, + + LinkerWorkaround = -299, +}; + +/// Representation of 256-bit value binary compatible with LLVM i256 +struct i256 +{ + uint64_t a = 0; + uint64_t b = 0; + uint64_t c = 0; + uint64_t d = 0; +}; +static_assert(sizeof(i256) == 32, "Wrong i265 size"); + +#define UNTESTED assert(false) + +} +} +} diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp new file mode 100644 index 000000000..de48e8ef9 --- /dev/null +++ b/evmjit/libevmjit/Compiler.cpp @@ -0,0 +1,965 @@ +#include "Compiler.h" + +#include +#include +#include +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Instruction.h" +#include "Type.h" +#include "Memory.h" +#include "Stack.h" +#include "Ext.h" +#include "GasMeter.h" +#include "Utils.h" +#include "Endianness.h" +#include "Arith256.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Compiler::Compiler(Options const& _options): + m_options(_options), + m_builder(llvm::getGlobalContext()) +{ + Type::init(m_builder.getContext()); +} + +void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd) +{ + /// Helper function that skips push data and finds next iterator (can be the end) + auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end) + { + static const auto push1 = static_cast(Instruction::PUSH1); + static const auto push32 = static_cast(Instruction::PUSH32); + size_t offset = 1; + if (*_curr >= push1 && *_curr <= push32) + offset += std::min(*_curr - push1 + 1, (_end - _curr) - 1); + return _curr + offset; + }; + + auto begin = _codeBegin; // begin of current block + bool nextJumpDest = false; + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) + { + next = skipPushDataAndGetNext(curr, _codeEnd); + + bool isEnd = false; + switch (Instruction(*curr)) + { + case Instruction::JUMP: + case Instruction::JUMPI: + case Instruction::RETURN: + case Instruction::STOP: + case Instruction::SUICIDE: + isEnd = true; + break; + + case Instruction::JUMPDEST: + nextJumpDest = true; + break; + + default: + break; + } + + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) + isEnd = true; + + if (isEnd) + { + auto beginIdx = begin - _codeBegin; + m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); + nextJumpDest = false; + begin = next; + } + } +} + +llvm::BasicBlock* Compiler::getJumpTableBlock() +{ + if (!m_jumpTableBlock) + { + m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true)); + InsertPointGuard g{m_builder}; + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + auto dest = m_builder.CreatePHI(Type::Word, 8, "target"); + auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); + for (auto&& p : m_basicBlocks) + { + if (p.second.isJumpDest()) + switchInstr->addCase(Constant::get(p.first), p.second.llvm()); + } + } + return m_jumpTableBlock->llvm(); +} + +llvm::BasicBlock* Compiler::getBadJumpBlock() +{ + if (!m_badJumpBlock) + { + m_badJumpBlock.reset(new BasicBlock("BadJump", m_mainFunc, m_builder, true)); + InsertPointGuard g{m_builder}; + m_builder.SetInsertPoint(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); + } + return m_badJumpBlock->llvm(); +} + +std::unique_ptr Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) +{ + auto compilationStartTime = std::chrono::high_resolution_clock::now(); + auto module = std::unique_ptr(new llvm::Module(_id, m_builder.getContext())); + + // Create main function + auto mainFuncType = llvm::FunctionType::get(Type::MainReturn, Type::RuntimePtr, false); + m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); + m_mainFunc->getArgumentList().front().setName("rt"); + + // Create entry basic block + auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); + m_builder.SetInsertPoint(entryBlock); + + auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words"); + auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress); + auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); + m_builder.CreateStore(fp, jmpBufWords); + auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); + auto sp = m_builder.CreateCall(stacksave, "sp"); + auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); + m_builder.CreateStore(sp, jmpBufSp); + auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); + auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf"); + auto r = m_builder.CreateCall(setjmp, jmpBuf); + auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); + + createBasicBlocks(_begin, _end); + + // Init runtime structures. + RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end); + GasMeter gasMeter(m_builder, runtimeManager); + Memory memory(runtimeManager, gasMeter); + Ext ext(runtimeManager, memory); + Stack stack(m_builder, runtimeManager); + Arith256 arith(m_builder); + + // TODO: Create Stop basic block on demand + m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); + auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc); + + auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); + auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0); + m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue); + + for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt) + { + auto& basicBlock = basicBlockPairIt->second; + auto iterCopy = basicBlockPairIt; + ++iterCopy; + auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + } + + // Code for special blocks: + // TODO: move to separate function. + m_builder.SetInsertPoint(m_stopBB); + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + + m_builder.SetInsertPoint(abortBB); + m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas)); + + removeDeadBlocks(); + + // Link jump table target index + if (m_jumpTableBlock) + { + auto phi = llvm::cast(&m_jumpTableBlock->llvm()->getInstList().front()); + for (auto predIt = llvm::pred_begin(m_jumpTableBlock->llvm()); predIt != llvm::pred_end(m_jumpTableBlock->llvm()); ++predIt) + { + BasicBlock* pred = nullptr; + for (auto&& p : m_basicBlocks) + { + if (p.second.llvm() == *predIt) + { + pred = &p.second; + break; + } + } + + phi->addIncoming(pred->getJumpTarget(), pred->llvm()); + } + } + + dumpCFGifRequired("blocks-init.dot"); + + if (m_options.optimizeStack) + { + std::vector blockList; + for (auto& entry : m_basicBlocks) + blockList.push_back(&entry.second); + + if (m_jumpTableBlock) + blockList.push_back(m_jumpTableBlock.get()); + + BasicBlock::linkLocalStacks(blockList, m_builder); + + dumpCFGifRequired("blocks-opt.dot"); + } + + for (auto& entry : m_basicBlocks) + entry.second.synchronizeLocalStack(stack); + if (m_jumpTableBlock) + m_jumpTableBlock->synchronizeLocalStack(stack); + + dumpCFGifRequired("blocks-sync.dot"); + + if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) + { + llvm::FunctionPassManager fpManager(module.get()); + fpManager.add(llvm::createLowerSwitchPass()); + fpManager.doInitialization(); + fpManager.run(*m_mainFunc); + } + + auto compilationEndTime = std::chrono::high_resolution_clock::now(); + clog(JIT) << "JIT: " << std::chrono::duration_cast(compilationEndTime - compilationStartTime).count(); + return module; +} + + +void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, + Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) +{ + if (!_nextBasicBlock) // this is the last block in the code + _nextBasicBlock = m_stopBB; + + m_builder.SetInsertPoint(_basicBlock.llvm()); + auto& stack = _basicBlock.localStack(); + + for (auto it = _basicBlock.begin(); it != _basicBlock.end(); ++it) + { + auto inst = Instruction(*it); + + _gasMeter.count(inst); + + switch (inst) + { + + case Instruction::ADD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateAdd(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::SUB: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto result = m_builder.CreateSub(lhs, rhs); + stack.push(result); + break; + } + + case Instruction::MUL: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.mul(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::DIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.div(lhs, rhs); + stack.push(res.first); + break; + } + + case Instruction::SDIV: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res.first); + break; + } + + case Instruction::MOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.div(lhs, rhs); + stack.push(res.second); + break; + } + + case Instruction::SMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = _arith.sdiv(lhs, rhs); + stack.push(res.second); + break; + } + + case Instruction::EXP: + { + auto base = stack.pop(); + auto exponent = stack.pop(); + _gasMeter.countExp(exponent); + auto ret = _arith.exp(base, exponent); + stack.push(ret); + break; + } + + case Instruction::NOT: + { + auto value = stack.pop(); + auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot"); + stack.push(ret); + break; + } + + case Instruction::LT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpULT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::GT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpUGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::SLT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSLT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::SGT: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpSGT(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::EQ: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res1 = m_builder.CreateICmpEQ(lhs, rhs); + auto res256 = m_builder.CreateZExt(res1, Type::Word); + stack.push(res256); + break; + } + + case Instruction::ISZERO: + { + auto top = stack.pop(); + auto iszero = m_builder.CreateICmpEQ(top, Constant::get(0), "iszero"); + auto result = m_builder.CreateZExt(iszero, Type::Word); + stack.push(result); + break; + } + + case Instruction::AND: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateAnd(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::OR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateOr(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::XOR: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto res = m_builder.CreateXor(lhs, rhs); + stack.push(res); + break; + } + + case Instruction::BYTE: + { + const auto byteNum = stack.pop(); + auto value = stack.pop(); + + value = Endianness::toBE(m_builder, value); + auto bytes = m_builder.CreateBitCast(value, llvm::VectorType::get(Type::Byte, 32), "bytes"); + auto safeByteNum = m_builder.CreateZExt(m_builder.CreateTrunc(byteNum, m_builder.getIntNTy(5)), Type::lowPrecision); // Trim index, large values can crash + auto byte = m_builder.CreateExtractElement(bytes, safeByteNum, "byte"); + value = m_builder.CreateZExt(byte, Type::Word); + + auto byteNumValid = m_builder.CreateICmpULT(byteNum, Constant::get(32)); + value = m_builder.CreateSelect(byteNumValid, value, Constant::get(0)); + stack.push(value); + break; + } + + case Instruction::ADDMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.addmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::MULMOD: + { + auto lhs = stack.pop(); + auto rhs = stack.pop(); + auto mod = stack.pop(); + auto res = _arith.mulmod(lhs, rhs, mod); + stack.push(res); + break; + } + + case Instruction::SIGNEXTEND: + { + auto idx = stack.pop(); + auto word = stack.pop(); + + auto k32_ = m_builder.CreateTrunc(idx, m_builder.getIntNTy(5), "k_32"); + auto k32 = m_builder.CreateZExt(k32_, Type::lowPrecision); + auto k32x8 = m_builder.CreateMul(k32, m_builder.getInt64(8), "kx8"); + + // test for word >> (k * 8 + 7) + auto bitpos = m_builder.CreateAdd(k32x8, m_builder.getInt64(7), "bitpos"); + auto bitposEx = m_builder.CreateZExt(bitpos, Type::Word); + auto bittester = m_builder.CreateShl(Constant::get(1), bitposEx); + auto bitresult = m_builder.CreateAnd(word, bittester); + auto bittest = m_builder.CreateICmpUGT(bitresult, Constant::get(0)); + // FIXME: The following does not work - LLVM bug, report! + //auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); + //auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest"); + + auto mask_ = m_builder.CreateShl(Constant::get(1), bitposEx); + auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); + + auto negmask = m_builder.CreateXor(mask, llvm::ConstantInt::getAllOnesValue(Type::Word), "negmask"); + auto val1 = m_builder.CreateOr(word, negmask); + auto val0 = m_builder.CreateAnd(word, mask); + + auto kInRange = m_builder.CreateICmpULE(idx, llvm::ConstantInt::get(Type::Word, 30)); + auto result = m_builder.CreateSelect(kInRange, + m_builder.CreateSelect(bittest, val1, val0), + word); + stack.push(result); + break; + } + + case Instruction::SHA3: + { + auto inOff = stack.pop(); + auto inSize = stack.pop(); + _memory.require(inOff, inSize); + _gasMeter.countSha3Data(inSize); + auto hash = _ext.sha3(inOff, inSize); + stack.push(hash); + break; + } + + case Instruction::POP: + { + auto val = stack.pop(); + static_cast(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; + } + + case Instruction::ANY_PUSH: + { + auto value = readPushData(it, _basicBlock.end()); + stack.push(Constant::get(value)); + break; + } + + case Instruction::ANY_DUP: + { + auto index = static_cast(inst) - static_cast(Instruction::DUP1); + stack.dup(index); + break; + } + + case Instruction::ANY_SWAP: + { + auto index = static_cast(inst) - static_cast(Instruction::SWAP1) + 1; + stack.swap(index); + break; + } + + case Instruction::MLOAD: + { + auto addr = stack.pop(); + auto word = _memory.loadWord(addr); + stack.push(word); + break; + } + + case Instruction::MSTORE: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeWord(addr, word); + break; + } + + case Instruction::MSTORE8: + { + auto addr = stack.pop(); + auto word = stack.pop(); + _memory.storeByte(addr, word); + break; + } + + case Instruction::MSIZE: + { + auto word = _memory.getSize(); + stack.push(word); + break; + } + + case Instruction::SLOAD: + { + auto index = stack.pop(); + auto value = _ext.sload(index); + stack.push(value); + break; + } + + case Instruction::SSTORE: + { + auto index = stack.pop(); + auto value = stack.pop(); + _gasMeter.countSStore(_ext, index, value); + _ext.sstore(index, value); + break; + } + + case Instruction::JUMP: + case Instruction::JUMPI: + { + llvm::BasicBlock* targetBlock = nullptr; + auto target = stack.pop(); + if (auto constant = llvm::dyn_cast(target)) + { + auto&& c = constant->getValue(); + auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; + auto it = m_basicBlocks.find(targetIdx); + targetBlock = (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : getBadJumpBlock(); + } + + // TODO: Improve; check for constants + if (inst == Instruction::JUMP) + { + if (targetBlock) + { + m_builder.CreateBr(targetBlock); + } + else + { + _basicBlock.setJumpTarget(target); + m_builder.CreateBr(getJumpTableBlock()); + } + } + else // JUMPI + { + auto val = stack.pop(); + auto zero = Constant::get(0); + auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); + + if (targetBlock) + { + m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); + } + else + { + _basicBlock.setJumpTarget(target); + m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); + } + } + break; + } + + case Instruction::JUMPDEST: + { + // Nothing to do + break; + } + + case Instruction::PC: + { + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); + stack.push(value); + break; + } + + case Instruction::GAS: + { + _gasMeter.commitCostBlock(); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); + break; + } + + case Instruction::ADDRESS: + case Instruction::CALLER: + case Instruction::ORIGIN: + case Instruction::CALLVALUE: + case Instruction::GASPRICE: + case Instruction::COINBASE: + case Instruction::DIFFICULTY: + case Instruction::GASLIMIT: + case Instruction::NUMBER: + case Instruction::TIMESTAMP: + { + // Pushes an element of runtime data on stack + auto value = _runtimeManager.get(inst); + value = m_builder.CreateZExt(value, Type::Word); + stack.push(value); + break; + } + + case Instruction::CODESIZE: + // TODO: Use constant + stack.push(_runtimeManager.getCodeSize()); + break; + + case Instruction::CALLDATASIZE: + stack.push(_runtimeManager.getCallDataSize()); + break; + + case Instruction::BLOCKHASH: + { + auto number = stack.pop(); + auto hash = _ext.blockhash(number); + stack.push(hash); + break; + } + + case Instruction::BALANCE: + { + auto address = stack.pop(); + auto value = _ext.balance(address); + stack.push(value); + break; + } + + case Instruction::EXTCODESIZE: + { + auto addr = stack.pop(); + auto codeRef = _ext.extcode(addr); + stack.push(codeRef.size); + break; + } + + case Instruction::CALLDATACOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCallData(); + auto srcSize = _runtimeManager.getCallDataSize(); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CODECOPY: + { + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234 + auto srcSize = _runtimeManager.getCodeSize(); + + _memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::EXTCODECOPY: + { + auto addr = stack.pop(); + auto destMemIdx = stack.pop(); + auto srcIdx = stack.pop(); + auto reqBytes = stack.pop(); + + auto codeRef = _ext.extcode(addr); + + _memory.copyBytes(codeRef.ptr, codeRef.size, srcIdx, destMemIdx, reqBytes); + break; + } + + case Instruction::CALLDATALOAD: + { + auto index = stack.pop(); + auto value = _ext.calldataload(index); + stack.push(value); + break; + } + + case Instruction::CREATE: + { + auto endowment = stack.pop(); + auto initOff = stack.pop(); + auto initSize = stack.pop(); + _memory.require(initOff, initSize); + + _gasMeter.commitCostBlock(); + auto address = _ext.create(endowment, initOff, initSize); + stack.push(address); + break; + } + + case Instruction::CALL: + case Instruction::CALLCODE: + { + auto callGas256 = stack.pop(); + auto codeAddress = stack.pop(); + auto value = stack.pop(); + auto inOff = stack.pop(); + auto inSize = stack.pop(); + auto outOff = stack.pop(); + auto outSize = stack.pop(); + + _gasMeter.commitCostBlock(); + + // Require memory for in and out buffers + _memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one + _memory.require(inOff, inSize); + + auto receiveAddress = codeAddress; + if (inst == Instruction::CALLCODE) + receiveAddress = _runtimeManager.get(RuntimeData::Address); + + auto gas = _runtimeManager.getGas(); + _gasMeter.count(callGas256); + auto callGas = m_builder.CreateTrunc(callGas256, Type::Gas); + auto gasLeft = m_builder.CreateNSWSub(gas, callGas); + _runtimeManager.setGas(callGas); + auto ret = _ext.call(receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); + _gasMeter.giveBack(gasLeft); + stack.push(ret); + break; + } + + case Instruction::RETURN: + { + auto index = stack.pop(); + auto size = stack.pop(); + + _memory.require(index, size); + _runtimeManager.registerReturnData(index, size); + + m_builder.CreateRet(Constant::get(ReturnCode::Return)); + break; + } + + case Instruction::SUICIDE: + { + _runtimeManager.registerSuicide(stack.pop()); + m_builder.CreateRet(Constant::get(ReturnCode::Suicide)); + break; + } + + + case Instruction::STOP: + { + m_builder.CreateRet(Constant::get(ReturnCode::Stop)); + 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); + + // This will commit the current cost block + _gasMeter.countLogData(numBytes); + + std::array topics{{}}; + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + for (size_t i = 0; i < numTopics; ++i) + topics[i] = stack.pop(); + + _ext.log(beginIdx, numBytes, topics); + break; + } + + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation + } + } + + _gasMeter.commitCostBlock(); + + // Block may have no terminator if the next instruction is a jump destination. + if (!_basicBlock.llvm()->getTerminator()) + m_builder.CreateBr(_nextBasicBlock); +} + + + +void Compiler::removeDeadBlocks() +{ + // Remove dead basic blocks + auto sthErased = false; + do + { + sthErased = false; + for (auto it = m_basicBlocks.begin(); it != m_basicBlocks.end();) + { + auto llvmBB = it->second.llvm(); + if (llvm::pred_begin(llvmBB) == llvm::pred_end(llvmBB)) + { + llvmBB->eraseFromParent(); + m_basicBlocks.erase(it++); + sthErased = true; + } + else + ++it; + } + } + while (sthErased); + + if (m_jumpTableBlock && llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) + { + m_jumpTableBlock->llvm()->eraseFromParent(); + m_jumpTableBlock.reset(); + } + + if (m_badJumpBlock && llvm::pred_begin(m_badJumpBlock->llvm()) == llvm::pred_end(m_badJumpBlock->llvm())) + { + m_badJumpBlock->llvm()->eraseFromParent(); + m_badJumpBlock.reset(); + } +} + +void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) +{ + if (! m_options.dumpCFG) + return; + + // TODO: handle i/o failures + std::ofstream ofs(_dotfilePath); + dumpCFGtoStream(ofs); + ofs.close(); +} + +void Compiler::dumpCFGtoStream(std::ostream& _out) +{ + _out << "digraph BB {\n" + << " node [shape=record, fontname=Courier, fontsize=10];\n" + << " entry [share=record, label=\"entry block\"];\n"; + + std::vector blocks; + for (auto& pair : m_basicBlocks) + blocks.push_back(&pair.second); + if (m_jumpTableBlock) + blocks.push_back(m_jumpTableBlock.get()); + if (m_badJumpBlock) + blocks.push_back(m_badJumpBlock.get()); + + // std::map phiNodesPerBlock; + + // Output nodes + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + std::ostringstream oss; + bb->dump(oss, true); + + _out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; + } + + // Output edges + for (auto bb : blocks) + { + std::string blockName = bb->llvm()->getName(); + + auto end = llvm::pred_end(bb->llvm()); + for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) + { + _out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" + << ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") + << "];\n"; + } + } + + _out << "}\n"; +} + +void Compiler::dump() +{ + for (auto& entry : m_basicBlocks) + entry.second.dump(); + if (m_jumpTableBlock != nullptr) + m_jumpTableBlock->dump(); +} + +} +} +} + diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h new file mode 100644 index 000000000..c9795fb99 --- /dev/null +++ b/evmjit/libevmjit/Compiler.h @@ -0,0 +1,80 @@ +#pragma once + +#include "Common.h" +#include "BasicBlock.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class Compiler +{ +public: + + struct Options + { + /// Optimize stack operations between basic blocks + bool optimizeStack = true; + + /// Rewrite switch instructions to sequences of branches + bool rewriteSwitchToBranches = true; + + /// Dump CFG as a .dot file for graphviz + bool dumpCFG = false; + }; + + using ProgramCounter = uint64_t; + + Compiler(Options const& _options); + + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); + +private: + + void createBasicBlocks(code_iterator _begin, code_iterator _end); + + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + + llvm::BasicBlock* getJumpTableBlock(); + + llvm::BasicBlock* getBadJumpBlock(); + + void removeDeadBlocks(); + + /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. + void dumpCFGifRequired(std::string const& _dotfilePath); + + /// Dumps basic block graph in graphviz format to a stream. + void dumpCFGtoStream(std::ostream& _out); + + /// Dumps all basic blocks to stderr. Useful in a debugging session. + void dump(); + + /// Compiler options + Options const& m_options; + + /// Helper class for generating IR + llvm::IRBuilder<> m_builder; + + /// Maps a program counter pc to a basic block that starts at pc (if any). + std::map m_basicBlocks; + + /// Stop basic block - terminates execution with STOP code (0) + llvm::BasicBlock* m_stopBB = nullptr; + + /// Block with a jump table. + std::unique_ptr m_jumpTableBlock; + + /// Destination for invalid jumps + std::unique_ptr m_badJumpBlock; + + /// Main program function + llvm::Function* m_mainFunc = nullptr; +}; + +} +} +} diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp new file mode 100644 index 000000000..5c8ee8574 --- /dev/null +++ b/evmjit/libevmjit/CompilerHelper.cpp @@ -0,0 +1,51 @@ +#include "CompilerHelper.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +CompilerHelper::CompilerHelper(llvm::IRBuilder<>& _builder) : + m_builder(_builder) +{} + +llvm::Module* CompilerHelper::getModule() +{ + assert(m_builder.GetInsertBlock()); + assert(m_builder.GetInsertBlock()->getParent()); // BB must be in a function + return m_builder.GetInsertBlock()->getParent()->getParent(); +} + +llvm::Function* CompilerHelper::getMainFunction() +{ + // TODO: Rename or change semantics of getMainFunction() function + assert(m_builder.GetInsertBlock()); + auto mainFunc = m_builder.GetInsertBlock()->getParent(); + assert(mainFunc); + if (mainFunc == &mainFunc->getParent()->getFunctionList().front()) // Main function is the first one in module + return mainFunc; + return nullptr; +} + +llvm::CallInst* CompilerHelper::createCall(llvm::Function* _func, std::initializer_list const& _args) +{ + return getBuilder().CreateCall(_func, {_args.begin(), _args.size()}); +} + + +RuntimeHelper::RuntimeHelper(RuntimeManager& _runtimeManager): + CompilerHelper(_runtimeManager.getBuilder()), + m_runtimeManager(_runtimeManager) +{} + +} +} +} diff --git a/evmjit/libevmjit/CompilerHelper.h b/evmjit/libevmjit/CompilerHelper.h new file mode 100644 index 000000000..cd6d09a58 --- /dev/null +++ b/evmjit/libevmjit/CompilerHelper.h @@ -0,0 +1,79 @@ +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +/// Base class for compiler helpers like Memory, GasMeter, etc. +class CompilerHelper +{ +protected: + CompilerHelper(llvm::IRBuilder<>& _builder); + + CompilerHelper(const CompilerHelper&) = delete; + CompilerHelper& operator=(CompilerHelper) = delete; + + /// Reference to the IR module being compiled + llvm::Module* getModule(); + + /// Reference to the main module function + llvm::Function* getMainFunction(); + + /// Reference to parent compiler IR builder + llvm::IRBuilder<>& m_builder; + llvm::IRBuilder<>& getBuilder() { return m_builder; } + + llvm::CallInst* createCall(llvm::Function* _func, std::initializer_list const& _args); + + friend class RuntimeHelper; +}; + + +/// Compiler helper that depends on runtime data +class RuntimeHelper : public CompilerHelper +{ +protected: + RuntimeHelper(RuntimeManager& _runtimeManager); + + RuntimeManager& getRuntimeManager() { return m_runtimeManager; } + +private: + RuntimeManager& m_runtimeManager; +}; + + +/// Saves the insert point of the IR builder and restores it when destructed +struct InsertPointGuard +{ + InsertPointGuard(llvm::IRBuilder<>& _builder) : + m_builder(_builder), + m_insertBB(m_builder.GetInsertBlock()), + m_insertPt(m_builder.GetInsertPoint()) + {} + + InsertPointGuard(const InsertPointGuard&) = delete; + void operator=(InsertPointGuard) = delete; + + ~InsertPointGuard() + { + m_builder.SetInsertPoint(m_insertBB, m_insertPt); + } + +private: + llvm::IRBuilder<>& m_builder; + llvm::BasicBlock* m_insertBB; + llvm::BasicBlock::iterator m_insertPt; +}; + +} +} +} diff --git a/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp new file mode 100644 index 000000000..38f71560c --- /dev/null +++ b/evmjit/libevmjit/Endianness.cpp @@ -0,0 +1,39 @@ +#include "Endianness.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word) +{ + union tester + { + unsigned int x; + unsigned char isLE; + }; + + if (tester{1}.isLE) + { + // FIXME: Disabled because of problems with BYTE + //if (auto constant = llvm::dyn_cast(_word)) + // return _builder.getInt(constant->getValue().byteSwap()); + + // OPT: Cache func declaration? + auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); + return _builder.CreateCall(bswapFunc, _word); + } + return _word; +} + +} +} +} diff --git a/evmjit/libevmjit/Endianness.h b/evmjit/libevmjit/Endianness.h new file mode 100644 index 000000000..19fd8fc58 --- /dev/null +++ b/evmjit/libevmjit/Endianness.h @@ -0,0 +1,25 @@ +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Endianness +{ + static llvm::Value* toBE(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + static llvm::Value* toNative(llvm::IRBuilder<>& _builder, llvm::Value* _word) { return bswapIfLE(_builder, _word); } + +private: + static llvm::Value* bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _word); +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..684f6d39a --- /dev/null +++ b/evmjit/libevmjit/ExecStats.cpp @@ -0,0 +1,97 @@ +#include "ExecStats.h" + +#include +#include +#include + +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::stateChanged(ExecState _state) +{ + if (!CHECK(m_state != ExecState::Finished)) + return; + + auto now = clock::now(); + if (_state != ExecState::Started) + { + assert(time[(int)m_state] == ExecStats::duration::zero()); + time[(int)m_state] = now - m_tp; + } + m_state = _state; + m_tp = now; +} + +namespace +{ +struct StatsAgg +{ + using unit = std::chrono::microseconds; + ExecStats::duration tot = ExecStats::duration::zero(); + ExecStats::duration min = ExecStats::duration::max(); + ExecStats::duration max = ExecStats::duration::zero(); + size_t count = 0; + + void update(ExecStats::duration _d) + { + ++count; + tot += _d; + min = _d < min ? _d : min; + max = _d > max ? _d : max; + } + + void output(char const* _name, std::ostream& _os) + { + auto avg = tot / count; + _os << std::setfill(' ') + << std::setw(12) << std::left << _name + << std::setw(10) << std::right << std::chrono::duration_cast(tot).count() + << std::setw(10) << std::right << std::chrono::duration_cast(avg).count() + << std::setw(10) << std::right << std::chrono::duration_cast(min).count() + << std::setw(10) << std::right << std::chrono::duration_cast(max).count() + << std::endl; + } +}; + +char const* getExecStateName(ExecState _state) +{ + switch (_state) + { + case ExecState::Started: return "Start"; + case ExecState::CacheLoad: return "CacheLoad"; + case ExecState::CacheWrite: return "CacheWrite"; + case ExecState::Compilation: return "Compilation"; + case ExecState::CodeGen: return "CodeGen"; + case ExecState::Execution: return "Execution"; + case ExecState::Return: return "Return"; + case ExecState::Finished: return "Finish"; + } + return nullptr; +} +} + +StatsCollector::~StatsCollector() +{ + if (stats.empty()) + return; + + std::cout << " [us] total avg min max\n"; + for (int i = 0; i < (int)ExecState::Finished; ++i) + { + StatsAgg agg; + for (auto&& s : stats) + agg.update(s->time[i]); + + agg.output(getExecStateName(ExecState(i)), std::cout); + } +} + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h new file mode 100644 index 000000000..498e21341 --- /dev/null +++ b/evmjit/libevmjit/ExecStats.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include "ExecutionEngine.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats : public ExecutionEngineListener +{ +public: + using clock = std::chrono::high_resolution_clock; + using duration = clock::duration; + using time_point = clock::time_point; + + std::string id; + duration time[(int)ExecState::Finished] = {}; + + void stateChanged(ExecState _state) override; + +private: + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector(); +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp new file mode 100644 index 000000000..1d2ff91b1 --- /dev/null +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -0,0 +1,153 @@ +#include "ExecutionEngine.h" + +#include +#include // env options +#include + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "Utils.h" +#include "BuildInfo.gen.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +namespace +{ +using EntryFuncPtr = ReturnCode(*)(Runtime*); + +std::string codeHash(i256 const& _hash) +{ + static const auto size = sizeof(_hash); + static const auto hexChars = "0123456789abcdef"; + std::string str; + str.resize(size * 2); + auto outIt = str.rbegin(); // reverse for BE + auto& arr = *(std::array*)&_hash; + for (auto b : arr) + { + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; + } + return str; +} + +bool getEnvOption(char const* _name, bool _default) +{ + auto var = std::getenv(_name); + if (!var) + return _default; + return std::strtol(var, nullptr, 10) != 0; +} + +bool showInfo() +{ + auto show = getEnvOption("EVMJIT_INFO", false); + if (show) + { + std::cout << "The Ethereum EVM JIT " EVMJIT_VERSION_FULL " LLVM " LLVM_VERSION << std::endl; + } + return show; +} + +} + +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) +{ + static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); + static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto statsCollectingEnabled = getEnvOption("EVMJIT_STATS", false); + static auto infoShown = showInfo(); + (void) infoShown; + + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); + + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; + + static std::unique_ptr ee; + if (!ee) + { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); + llvm::EngineBuilder builder(module.get()); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setUseMCJIT(true); + builder.setOptLevel(llvm::CodeGenOpt::None); + + auto triple = llvm::Triple(llvm::sys::getProcessTriple()); + if (triple.getOS() == llvm::Triple::OSType::Win32) + triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format + module->setTargetTriple(triple.str()); + + ee.reset(builder.create()); + if (!CHECK(ee)) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); + } + + static StatsCollector statsCollector; + + auto mainFuncName = codeHash(_data->codeHash); + Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + + auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + if (!entryFuncPtr) + { + auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; + if (!module) + { + listener->stateChanged(ExecState::Compilation); + assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code? + module = Compiler({}).compile(_data->code, _data->code + _data->codeSize, mainFuncName); + } + if (debugDumpModule) + module->dump(); + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); + } + if (!CHECK(entryFuncPtr)) + return ReturnCode::LLVMLinkError; + + listener->stateChanged(ExecState::Execution); + auto returnCode = entryFuncPtr(&runtime); + listener->stateChanged(ExecState::Return); + + if (returnCode == ReturnCode::Return) + { + returnData = runtime.getReturnData(); // Save reference to return data + std::swap(m_memory, runtime.getMemory()); // Take ownership of memory + } + listener->stateChanged(ExecState::Finished); + + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(listener)); + + return returnCode; +} + +} +} +} diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h new file mode 100644 index 000000000..4c2965e58 --- /dev/null +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +enum class ExecState +{ + Started, + CacheLoad, + CacheWrite, + Compilation, + CodeGen, + Execution, + Return, + Finished +}; + +class ExecutionEngineListener +{ +public: + ExecutionEngineListener() = default; + ExecutionEngineListener(ExecutionEngineListener const&) = delete; + ExecutionEngineListener& operator=(ExecutionEngineListener) = delete; + virtual ~ExecutionEngineListener() {} + + virtual void executionStarted() {} + virtual void executionEnded() {} + + virtual void stateChanged(ExecState) {} +}; + +class ExecutionEngine +{ +public: + ExecutionEngine() = default; + ExecutionEngine(ExecutionEngine const&) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; + + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + + /// Reference to returned data (RETURN opcode used) + bytes_ref returnData; + +private: + /// After execution, if RETURN used, memory is moved there + /// to allow client copy the returned data + bytes m_memory; +}; + +} +} +} diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp new file mode 100644 index 000000000..38deef214 --- /dev/null +++ b/evmjit/libevmjit/Ext.cpp @@ -0,0 +1,192 @@ +#include "Ext.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Memory.h" +#include "Type.h" +#include "Endianness.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan): + RuntimeHelper(_runtimeManager), + m_memoryMan(_memoryMan) +{ + m_funcs = decltype(m_funcs)(); + m_argAllocas = decltype(m_argAllocas)(); + m_size = m_builder.CreateAlloca(Type::Size, nullptr, "env.size"); +} + + +using FuncDesc = std::tuple; + +llvm::FunctionType* getFunctionType(llvm::Type* _returnType, std::initializer_list const& _argsTypes) +{ + return llvm::FunctionType::get(_returnType, llvm::ArrayRef{_argsTypes.begin(), _argsTypes.size()}, false); +} + +std::array::value> const& getEnvFuncDescs() +{ + static std::array::value> descs{{ + FuncDesc{"env_sload", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_sstore", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_sha3", getFunctionType(Type::Void, {Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_balance", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_create", getFunctionType(Type::Void, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_call", getFunctionType(Type::Bool, {Type::EnvPtr, Type::GasPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, Type::BytePtr, Type::Size, Type::WordPtr})}, + FuncDesc{"env_log", getFunctionType(Type::Void, {Type::EnvPtr, Type::BytePtr, Type::Size, Type::WordPtr, Type::WordPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_blockhash", getFunctionType(Type::Void, {Type::EnvPtr, Type::WordPtr, Type::WordPtr})}, + FuncDesc{"env_extcode", getFunctionType(Type::BytePtr, {Type::EnvPtr, Type::WordPtr, Type::Size->getPointerTo()})}, + FuncDesc{"ext_calldataload", getFunctionType(Type::Void, {Type::RuntimeDataPtr, Type::WordPtr, Type::WordPtr})}, + }}; + + return descs; +} + +llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) +{ + auto&& desc = getEnvFuncDescs()[static_cast(_id)]; + return llvm::Function::Create(std::get<1>(desc), llvm::Function::ExternalLinkage, std::get<0>(desc), _module); +} + +llvm::Value* Ext::getArgAlloca() +{ + auto& a = m_argAllocas[m_argCounter]; + if (!a) + { + InsertPointGuard g{getBuilder()}; + auto allocaIt = getMainFunction()->front().begin(); + std::advance(allocaIt, m_argCounter); // Skip already created allocas + getBuilder().SetInsertPoint(allocaIt); + a = getBuilder().CreateAlloca(Type::Word, nullptr, {"a.", std::to_string(m_argCounter)}); + } + ++m_argCounter; + return a; +} + +llvm::Value* Ext::byPtr(llvm::Value* _value) +{ + auto a = getArgAlloca(); + getBuilder().CreateStore(_value, a); + return a; +} + +llvm::CallInst* Ext::createCall(EnvFunc _funcId, std::initializer_list const& _args) +{ + auto& func = m_funcs[static_cast(_funcId)]; + if (!func) + func = createFunc(_funcId, getModule()); + + m_argCounter = 0; + return getBuilder().CreateCall(func, {_args.begin(), _args.size()}); +} + +llvm::Value* Ext::sload(llvm::Value* _index) +{ + auto ret = getArgAlloca(); + createCall(EnvFunc::sload, {getRuntimeManager().getEnvPtr(), byPtr(_index), ret}); // Uses native endianness + return m_builder.CreateLoad(ret); +} + +void Ext::sstore(llvm::Value* _index, llvm::Value* _value) +{ + createCall(EnvFunc::sstore, {getRuntimeManager().getEnvPtr(), byPtr(_index), byPtr(_value)}); // Uses native endianness +} + +llvm::Value* Ext::calldataload(llvm::Value* _index) +{ + auto ret = getArgAlloca(); + createCall(EnvFunc::calldataload, {getRuntimeManager().getDataPtr(), byPtr(_index), ret}); + ret = m_builder.CreateLoad(ret); + return Endianness::toNative(m_builder, ret); +} + +llvm::Value* Ext::balance(llvm::Value* _address) +{ + auto address = Endianness::toBE(m_builder, _address); + auto ret = getArgAlloca(); + createCall(EnvFunc::balance, {getRuntimeManager().getEnvPtr(), byPtr(address), ret}); + return m_builder.CreateLoad(ret); +} + +llvm::Value* Ext::blockhash(llvm::Value* _number) +{ + auto hash = getArgAlloca(); + createCall(EnvFunc::blockhash, {getRuntimeManager().getEnvPtr(), byPtr(_number), hash}); + hash = m_builder.CreateLoad(hash); + return Endianness::toNative(getBuilder(), hash); +} + +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +{ + auto ret = getArgAlloca(); + auto begin = m_memoryMan.getBytePtr(_initOff); + auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); + createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(_endowment), begin, size, ret}); + llvm::Value* address = m_builder.CreateLoad(ret); + address = Endianness::toNative(m_builder, address); + return address; +} + +llvm::Value* Ext::call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +{ + auto receiveAddress = Endianness::toBE(m_builder, _receiveAddress); + auto inBeg = m_memoryMan.getBytePtr(_inOff); + auto inSize = m_builder.CreateTrunc(_inSize, Type::Size, "in.size"); + auto outBeg = m_memoryMan.getBytePtr(_outOff); + auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); + auto codeAddress = Endianness::toBE(m_builder, _codeAddress); + auto ret = createCall(EnvFunc::call, {getRuntimeManager().getEnvPtr(), getRuntimeManager().getGasPtr(), byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); + return m_builder.CreateZExt(ret, Type::Word, "ret"); +} + +llvm::Value* Ext::sha3(llvm::Value* _inOff, llvm::Value* _inSize) +{ + auto begin = m_memoryMan.getBytePtr(_inOff); + auto size = m_builder.CreateTrunc(_inSize, Type::Size, "size"); + auto ret = getArgAlloca(); + createCall(EnvFunc::sha3, {begin, size, ret}); + llvm::Value* hash = m_builder.CreateLoad(ret); + hash = Endianness::toNative(m_builder, hash); + return hash; +} + +MemoryRef Ext::extcode(llvm::Value* _addr) +{ + auto addr = Endianness::toBE(m_builder, _addr); + auto code = createCall(EnvFunc::extcode, {getRuntimeManager().getEnvPtr(), byPtr(addr), m_size}); + auto codeSize = m_builder.CreateLoad(m_size); + auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); + return {code, codeSize256}; +} + +void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics) +{ + auto begin = m_memoryMan.getBytePtr(_memIdx); + auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size"); + llvm::Value* args[] = {getRuntimeManager().getEnvPtr(), begin, size, getArgAlloca(), getArgAlloca(), getArgAlloca(), getArgAlloca()}; + + auto topicArgPtr = &args[3]; + for (auto&& topic : _topics) + { + if (topic) + m_builder.CreateStore(Endianness::toBE(m_builder, topic), *topicArgPtr); + else + *topicArgPtr = llvm::ConstantPointerNull::get(Type::WordPtr); + ++topicArgPtr; + } + + createCall(EnvFunc::log, {args[0], args[1], args[2], args[3], args[4], args[5], args[6]}); // TODO: use std::initializer_list<> +} + +} +} +} diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h new file mode 100644 index 000000000..1c0c0fc56 --- /dev/null +++ b/evmjit/libevmjit/Ext.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + class Memory; + +struct MemoryRef +{ + llvm::Value* ptr; + llvm::Value* size; +}; + +template +struct sizeOf +{ + static const size_t value = static_cast(_EnumT::_size); +}; + +enum class EnvFunc +{ + sload, + sstore, + sha3, + balance, + create, + call, + log, + blockhash, + extcode, + calldataload, // Helper function, not client Env interface + + _size +}; + +class Ext : public RuntimeHelper +{ +public: + Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan); + + llvm::Value* sload(llvm::Value* _index); + void sstore(llvm::Value* _index, llvm::Value* _value); + + llvm::Value* balance(llvm::Value* _address); + llvm::Value* calldataload(llvm::Value* _index); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* call(llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + llvm::Value* blockhash(llvm::Value* _number); + + llvm::Value* sha3(llvm::Value* _inOff, llvm::Value* _inSize); + MemoryRef extcode(llvm::Value* _addr); + + void log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array const& _topics); + +private: + Memory& m_memoryMan; + + llvm::Value* m_size; + llvm::Value* m_data = nullptr; + + std::array::value> m_funcs; + std::array m_argAllocas; + size_t m_argCounter = 0; + + llvm::CallInst* createCall(EnvFunc _funcId, std::initializer_list const& _args); + llvm::Value* getArgAlloca(); + llvm::Value* byPtr(llvm::Value* _value); +}; + + +} +} +} + diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp new file mode 100644 index 000000000..ca21714e0 --- /dev/null +++ b/evmjit/libevmjit/GasMeter.cpp @@ -0,0 +1,231 @@ +#include "GasMeter.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Ext.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +namespace // Helper functions +{ + +int64_t const c_stepGas = 1; +int64_t const c_balanceGas = 20; +int64_t const c_sha3Gas = 10; +int64_t const c_sha3WordGas = 10; +int64_t const c_sloadGas = 20; +int64_t const c_sstoreSetGas = 300; +int64_t const c_sstoreResetGas = 100; +int64_t const c_sstoreRefundGas = 100; +int64_t const c_createGas = 100; +int64_t const c_createDataGas = 5; +int64_t const c_callGas = 20; +int64_t const c_expGas = 1; +int64_t const c_expByteGas = 1; +int64_t const c_memoryGas = 1; +int64_t const c_txDataZeroGas = 1; +int64_t const c_txDataNonZeroGas = 5; +int64_t const c_txGas = 500; +int64_t const c_logGas = 32; +int64_t const c_logDataGas = 1; +int64_t const c_logTopicGas = 32; +int64_t const c_copyGas = 1; + +int64_t getStepCost(Instruction inst) +{ + switch (inst) + { + default: // Assumes instruction code is valid + return c_stepGas; + + case Instruction::STOP: + case Instruction::SUICIDE: + case Instruction::SSTORE: // Handle cost of SSTORE separately in GasMeter::countSStore() + return 0; + + case Instruction::EXP: return c_expGas; + + case Instruction::SLOAD: return c_sloadGas; + + case Instruction::SHA3: return c_sha3Gas; + + case Instruction::BALANCE: return c_balanceGas; + + case Instruction::CALL: + case Instruction::CALLCODE: return c_callGas; + + case Instruction::CREATE: return c_createGas; + + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + return c_logGas + numTopics * c_logTopicGas; + } + } +} + +} + +GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) : + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) +{ + auto module = getModule(); + + llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Gas}; + m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module); + InsertPointGuard guard(m_builder); + + auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); + auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); + auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); + + auto rt = &m_gasCheckFunc->getArgumentList().front(); + rt->setName("rt"); + auto cost = rt->getNextNode(); + cost->setName("cost"); + + m_builder.SetInsertPoint(checkBB); + auto gas = m_runtimeManager.getGas(); + gas = m_builder.CreateNSWSub(gas, cost, "gasUpdated"); + auto isOutOfGas = m_builder.CreateICmpSLT(gas, m_builder.getInt64(0), "isOutOfGas"); // gas < 0, with gas == 0 we can still do 0 cost instructions + m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); + + m_builder.SetInsertPoint(outOfGasBB); + m_runtimeManager.abort(); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(updateBB); + m_runtimeManager.setGas(gas); + m_builder.CreateRetVoid(); +} + +void GasMeter::count(Instruction _inst) +{ + if (!m_checkCall) + { + // Create gas check call with mocked block cost at begining of current cost-block + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); + } + + m_blockCost += getStepCost(_inst); +} + +void GasMeter::count(llvm::Value* _cost) +{ + if (_cost->getType() == Type::Word) + { + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_cost, gasMax256, "costTooHigh"); + auto cost64 = m_builder.CreateTrunc(_cost, Type::Gas); + _cost = m_builder.CreateSelect(tooHigh, Constant::gasMax, cost64, "cost"); + } + + assert(_cost->getType() == Type::Gas); + createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), _cost}); +} + +void GasMeter::countExp(llvm::Value* _exponent) +{ + // Additional cost is 1 per significant byte of exponent + // lz - leading zeros + // cost = ((256 - lz) + 7) / 8 + + // OPT: Can gas update be done in exp algorithm? + + auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); + count(sigBytes); +} + +void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) +{ + auto oldValue = _ext.sload(_index); + auto oldValueIsZero = m_builder.CreateICmpEQ(oldValue, Constant::get(0), "oldValueIsZero"); + auto newValueIsZero = m_builder.CreateICmpEQ(_newValue, Constant::get(0), "newValueIsZero"); + auto oldValueIsntZero = m_builder.CreateICmpNE(oldValue, Constant::get(0), "oldValueIsntZero"); + auto newValueIsntZero = m_builder.CreateICmpNE(_newValue, Constant::get(0), "newValueIsntZero"); + auto isInsert = m_builder.CreateAnd(oldValueIsZero, newValueIsntZero, "isInsert"); + auto isDelete = m_builder.CreateAnd(oldValueIsntZero, newValueIsZero, "isDelete"); + auto cost = m_builder.CreateSelect(isInsert, m_builder.getInt64(c_sstoreSetGas), m_builder.getInt64(c_sstoreResetGas), "cost"); + cost = m_builder.CreateSelect(isDelete, m_builder.getInt64(0), cost, "cost"); + count(cost); +} + +void GasMeter::countLogData(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // LOGn instruction is already counted + static_assert(c_logDataGas == 1, "Log data gas cost has changed. Update GasMeter."); + count(_dataLength); +} + +void GasMeter::countSha3Data(llvm::Value* _dataLength) +{ + assert(m_checkCall); + assert(m_blockCost > 0); // SHA3 instruction is already counted + + // TODO: This round ups to 32 happens in many places + static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); + auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::Gas); + auto words64 = m_builder.CreateUDiv(m_builder.CreateNUWAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); + count(cost64); +} + +void GasMeter::giveBack(llvm::Value* _gas) +{ + assert(_gas->getType() == Type::Gas); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); +} + +void GasMeter::commitCostBlock() +{ + // If any uncommited block + if (m_checkCall) + { + if (m_blockCost == 0) // Do not check 0 + { + m_checkCall->eraseFromParent(); // Remove the gas check call + m_checkCall = nullptr; + return; + } + + m_checkCall->setArgOperand(1, m_builder.getInt64(m_blockCost)); // Update block cost in gas check call + m_checkCall = nullptr; // End cost-block + m_blockCost = 0; + } + assert(m_blockCost == 0); +} + +void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) +{ + static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); + count(_additionalMemoryInWords); +} + +void GasMeter::countCopy(llvm::Value* _copyWords) +{ + static_assert(c_copyGas == 1, "Copy gas cost has changed. Update GasMeter."); + count(_copyWords); +} + +} +} +} + diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h new file mode 100644 index 000000000..4056cd64d --- /dev/null +++ b/evmjit/libevmjit/GasMeter.h @@ -0,0 +1,63 @@ +#pragma once + +#include "CompilerHelper.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class GasMeter : public CompilerHelper // TODO: Use RuntimeHelper +{ +public: + GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager); + + /// Count step cost of instruction + void count(Instruction _inst); + + /// Count additional cost + void count(llvm::Value* _cost); + + /// Calculate & count gas cost for SSTORE instruction + void countSStore(class Ext& _ext, llvm::Value* _index, llvm::Value* _newValue); + + /// Calculate & count additional gas cost for EXP instruction + void countExp(llvm::Value* _exponent); + + /// Count gas cost of LOG data + void countLogData(llvm::Value* _dataLength); + + /// Count gas cost of SHA3 data + void countSha3Data(llvm::Value* _dataLength); + + /// Finalize cost-block by checking gas needed for the block before the block + void commitCostBlock(); + + /// Give back an amount of gas not used by a call + void giveBack(llvm::Value* _gas); + + /// Generate code that checks the cost of additional memory used by program + void countMemory(llvm::Value* _additionalMemoryInWords); + + /// Count addional gas cost for memory copy + void countCopy(llvm::Value* _copyWords); + +private: + /// Cumulative gas cost of a block of instructions + /// @TODO Handle overflow + int64_t m_blockCost = 0; + + llvm::CallInst* m_checkCall = nullptr; + llvm::Function* m_gasCheckFunc = nullptr; + + RuntimeManager& m_runtimeManager; +}; + +} +} +} + diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp new file mode 100644 index 000000000..f70b020f8 --- /dev/null +++ b/evmjit/libevmjit/Instruction.cpp @@ -0,0 +1,42 @@ +#include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) +{ + auto pushInst = *_curr; + assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); + auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1; + llvm::APInt value(256, 0); + ++_curr; // Point the data + for (decltype(numBytes) i = 0; i < numBytes; ++i) + { + byte b = (_curr != _end) ? *_curr++ : 0; + value <<= 8; + value |= b; + } + --_curr; // Point the last real byte read + return value; +} + +void skipPushData(code_iterator& _curr, code_iterator _end) +{ + auto pushInst = *_curr; + assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); + auto numBytes = pushInst - static_cast(Instruction::PUSH1) + 1; + --_end; + for (decltype(numBytes) i = 0; i < numBytes && _curr < _end; ++i, ++_curr) {} +} + +} +} +} diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h new file mode 100644 index 000000000..6785213d6 --- /dev/null +++ b/evmjit/libevmjit/Instruction.h @@ -0,0 +1,239 @@ +#pragma once + +#include "Common.h" + +namespace llvm +{ + class APInt; +} + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +/// Virtual machine bytecode instruction. +enum class Instruction: uint8_t +{ + STOP = 0x00, ///< halts execution + ADD, ///< addition operation + MUL, ///< mulitplication operation + SUB, ///< subtraction operation + DIV, ///< integer division operation + SDIV, ///< signed integer division operation + MOD, ///< modulo remainder operation + SMOD, ///< signed modulo remainder operation + ADDMOD, ///< unsigned modular addition + MULMOD, ///< unsigned modular multiplication + EXP, ///< exponential operation + SIGNEXTEND, ///< extend length of signed integer + + LT = 0x10, ///< less-than comparision + GT, ///< greater-than comparision + SLT, ///< signed less-than comparision + SGT, ///< signed greater-than comparision + EQ, ///< equality comparision + ISZERO, ///< simple not operator + AND, ///< bitwise AND operation + OR, ///< bitwise OR operation + XOR, ///< bitwise XOR operation + NOT, ///< bitwise NOT opertation + BYTE, ///< retrieve single byte from word + + SHA3 = 0x20, ///< compute SHA3-256 hash + + ADDRESS = 0x30, ///< get address of currently executing account + BALANCE, ///< get balance of the given account + ORIGIN, ///< get execution origination address + CALLER, ///< get caller address + CALLVALUE, ///< get deposited value by the instruction/transaction responsible for this execution + CALLDATALOAD, ///< get input data of current environment + CALLDATASIZE, ///< get size of input data in current environment + CALLDATACOPY, ///< copy input data in current environment to memory + CODESIZE, ///< get size of code running in current environment + CODECOPY, ///< copy code running in current environment to memory + GASPRICE, ///< get price of gas in current environment + EXTCODESIZE, ///< get external code size (from another contract) + EXTCODECOPY, ///< copy external code (from another contract) + + BLOCKHASH = 0x40, ///< get hash of most recent complete block + COINBASE, ///< get the block's coinbase address + TIMESTAMP, ///< get the block's timestamp + NUMBER, ///< get the block's number + DIFFICULTY, ///< get the block's difficulty + GASLIMIT, ///< get the block's gas limit + + POP = 0x50, ///< remove item from stack + MLOAD, ///< load word from memory + MSTORE, ///< save word to memory + MSTORE8, ///< save byte to memory + SLOAD, ///< load word from storage + SSTORE, ///< save word to storage + JUMP, ///< alter the program counter + JUMPI, ///< conditionally alter the program counter + PC, ///< get the program counter + MSIZE, ///< get the size of active memory + GAS, ///< get the amount of available gas + JUMPDEST, ///< set a potential jump destination + + PUSH1 = 0x60, ///< place 1 byte item on stack + PUSH2, ///< place 2 byte item on stack + PUSH3, ///< place 3 byte item on stack + PUSH4, ///< place 4 byte item on stack + PUSH5, ///< place 5 byte item on stack + PUSH6, ///< place 6 byte item on stack + PUSH7, ///< place 7 byte item on stack + PUSH8, ///< place 8 byte item on stack + PUSH9, ///< place 9 byte item on stack + PUSH10, ///< place 10 byte item on stack + PUSH11, ///< place 11 byte item on stack + PUSH12, ///< place 12 byte item on stack + PUSH13, ///< place 13 byte item on stack + PUSH14, ///< place 14 byte item on stack + PUSH15, ///< place 15 byte item on stack + PUSH16, ///< place 16 byte item on stack + PUSH17, ///< place 17 byte item on stack + PUSH18, ///< place 18 byte item on stack + PUSH19, ///< place 19 byte item on stack + PUSH20, ///< place 20 byte item on stack + PUSH21, ///< place 21 byte item on stack + PUSH22, ///< place 22 byte item on stack + PUSH23, ///< place 23 byte item on stack + PUSH24, ///< place 24 byte item on stack + PUSH25, ///< place 25 byte item on stack + PUSH26, ///< place 26 byte item on stack + PUSH27, ///< place 27 byte item on stack + PUSH28, ///< place 28 byte item on stack + PUSH29, ///< place 29 byte item on stack + PUSH30, ///< place 30 byte item on stack + PUSH31, ///< place 31 byte item on stack + PUSH32, ///< place 32 byte item on stack + + DUP1 = 0x80, ///< copies the highest item in the stack to the top of the stack + DUP2, ///< copies the second highest item in the stack to the top of the stack + DUP3, ///< copies the third highest item in the stack to the top of the stack + DUP4, ///< copies the 4th highest item in the stack to the top of the stack + DUP5, ///< copies the 5th highest item in the stack to the top of the stack + DUP6, ///< copies the 6th highest item in the stack to the top of the stack + DUP7, ///< copies the 7th highest item in the stack to the top of the stack + DUP8, ///< copies the 8th highest item in the stack to the top of the stack + DUP9, ///< copies the 9th highest item in the stack to the top of the stack + DUP10, ///< copies the 10th highest item in the stack to the top of the stack + DUP11, ///< copies the 11th highest item in the stack to the top of the stack + DUP12, ///< copies the 12th highest item in the stack to the top of the stack + DUP13, ///< copies the 13th highest item in the stack to the top of the stack + DUP14, ///< copies the 14th highest item in the stack to the top of the stack + DUP15, ///< copies the 15th highest item in the stack to the top of the stack + DUP16, ///< copies the 16th highest item in the stack to the top of the stack + + SWAP1 = 0x90, ///< swaps the highest and second highest value on the stack + SWAP2, ///< swaps the highest and third highest value on the stack + SWAP3, ///< swaps the highest and 4th highest value on the stack + SWAP4, ///< swaps the highest and 5th highest value on the stack + SWAP5, ///< swaps the highest and 6th highest value on the stack + SWAP6, ///< swaps the highest and 7th highest value on the stack + SWAP7, ///< swaps the highest and 8th highest value on the stack + SWAP8, ///< swaps the highest and 9th highest value on the stack + SWAP9, ///< swaps the highest and 10th highest value on the stack + SWAP10, ///< swaps the highest and 11th highest value on the stack + SWAP11, ///< swaps the highest and 12th highest value on the stack + SWAP12, ///< swaps the highest and 13th highest value on the stack + SWAP13, ///< swaps the highest and 14th highest value on the stack + SWAP14, ///< swaps the highest and 15th highest value on the stack + SWAP15, ///< swaps the highest and 16th highest value on the stack + SWAP16, ///< swaps the highest and 17th highest value on the stack + + LOG0 = 0xa0, ///< Makes a log entry; no topics. + LOG1, ///< Makes a log entry; 1 topic. + LOG2, ///< Makes a log entry; 2 topics. + LOG3, ///< Makes a log entry; 3 topics. + LOG4, ///< Makes a log entry; 4 topics. + + CREATE = 0xf0, ///< create a new account with associated code + CALL, ///< message-call into an account + CALLCODE, ///< message-call with another account's code only + RETURN, ///< halt execution returning output data + SUICIDE = 0xff ///< halt execution and register account for later deletion +}; + +/// Reads PUSH data from pointed fragment of bytecode and constructs number out of it +/// Reading out of bytecode means reading 0 +/// @param _curr is updated and points the last real byte read +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end); + +/// Skips PUSH data in pointed fragment of bytecode. +/// @param _curr is updated and points the last real byte skipped +void skipPushData(code_iterator& _curr, code_iterator _end); + +#define ANY_PUSH PUSH1: \ + case Instruction::PUSH2: \ + case Instruction::PUSH3: \ + case Instruction::PUSH4: \ + case Instruction::PUSH5: \ + case Instruction::PUSH6: \ + case Instruction::PUSH7: \ + case Instruction::PUSH8: \ + case Instruction::PUSH9: \ + case Instruction::PUSH10: \ + case Instruction::PUSH11: \ + case Instruction::PUSH12: \ + case Instruction::PUSH13: \ + case Instruction::PUSH14: \ + case Instruction::PUSH15: \ + case Instruction::PUSH16: \ + case Instruction::PUSH17: \ + case Instruction::PUSH18: \ + case Instruction::PUSH19: \ + case Instruction::PUSH20: \ + case Instruction::PUSH21: \ + case Instruction::PUSH22: \ + case Instruction::PUSH23: \ + case Instruction::PUSH24: \ + case Instruction::PUSH25: \ + case Instruction::PUSH26: \ + case Instruction::PUSH27: \ + case Instruction::PUSH28: \ + case Instruction::PUSH29: \ + case Instruction::PUSH30: \ + case Instruction::PUSH31: \ + case Instruction::PUSH32 + +#define ANY_DUP DUP1: \ + case Instruction::DUP2: \ + case Instruction::DUP3: \ + case Instruction::DUP4: \ + case Instruction::DUP5: \ + case Instruction::DUP6: \ + case Instruction::DUP7: \ + case Instruction::DUP8: \ + case Instruction::DUP9: \ + case Instruction::DUP10: \ + case Instruction::DUP11: \ + case Instruction::DUP12: \ + case Instruction::DUP13: \ + case Instruction::DUP14: \ + case Instruction::DUP15: \ + case Instruction::DUP16 + +#define ANY_SWAP SWAP1: \ + case Instruction::SWAP2: \ + case Instruction::SWAP3: \ + case Instruction::SWAP4: \ + case Instruction::SWAP5: \ + case Instruction::SWAP6: \ + case Instruction::SWAP7: \ + case Instruction::SWAP8: \ + case Instruction::SWAP9: \ + case Instruction::SWAP10: \ + case Instruction::SWAP11: \ + case Instruction::SWAP12: \ + case Instruction::SWAP13: \ + case Instruction::SWAP14: \ + case Instruction::SWAP15: \ + case Instruction::SWAP16 + +} +} +} diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp new file mode 100644 index 000000000..647c5f26a --- /dev/null +++ b/evmjit/libevmjit/Memory.cpp @@ -0,0 +1,260 @@ +#include "Memory.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Type.h" +#include "Runtime.h" +#include "GasMeter.h" +#include "Endianness.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): + RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed + m_gasMeter(_gasMeter) +{} + +llvm::Function* Memory::getRequireFunc() +{ + auto& func = m_require; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto offset = rt->getNextNode(); + offset->setName("offset"); + auto size = offset->getNextNode(); + size->setName("size"); + + llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + auto resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", getModule()); + llvm::AttrBuilder attrBuilder; + attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); + resize->setAttributes(llvm::AttributeSet::get(resize->getContext(), 1, attrBuilder)); + + auto preBB = llvm::BasicBlock::Create(func->getContext(), "Pre", func); + auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func); + auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func); + auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + // BB "Pre": Ignore checks with size 0 + m_builder.SetInsertPoint(preBB); + auto sizeIsZero = m_builder.CreateICmpEQ(size, Constant::get(0)); + m_builder.CreateCondBr(sizeIsZero, returnBB, checkBB); + + // BB "Check" + m_builder.SetInsertPoint(checkBB); + auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::Word); + auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res"); + auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq"); + auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1"); + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + auto currSize = m_builder.CreateLoad(sizePtr, "currSize"); + auto tooSmall = m_builder.CreateICmpULE(currSize, sizeRequired, "tooSmall"); + auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded"); + m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights? + + // BB "Resize" + m_builder.SetInsertPoint(resizeBB); + // Check gas first + uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res"); + auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0); + auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2"); + auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow"); + wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired); + wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq"); + sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq"); + auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k + auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords"); + m_gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData"); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + m_builder.CreateStore(newData, dataPtr); + m_builder.CreateBr(returnBB); + + // BB "Return" + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&) +{ + auto isWord = _valueType == Type::Word; + + llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType}; + llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word}; + auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; + auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false); + auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); + + InsertPointGuard guard(m_builder); // Restores insert point at function exit + + m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); + auto rt = func->arg_begin(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; + this->require(index, Constant::get(valueSize)); + auto ptr = getBytePtr(index); + if (isWord) + ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); + if (_isStore) + { + llvm::Value* value = index->getNextNode(); + value->setName("value"); + if (isWord) + value = Endianness::toBE(m_builder, value); + m_builder.CreateStore(value, ptr); + m_builder.CreateRetVoid(); + } + else + { + llvm::Value* ret = m_builder.CreateLoad(ptr); + ret = Endianness::toNative(m_builder, ret); + m_builder.CreateRet(ret); + } + + return func; +} + +llvm::Function* Memory::getLoadWordFunc() +{ + auto& func = m_loadWord; + if (!func) + func = createFunc(false, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreWordFunc() +{ + auto& func = m_storeWord; + if (!func) + func = createFunc(true, Type::Word, m_gasMeter); + return func; +} + +llvm::Function* Memory::getStoreByteFunc() +{ + auto& func = m_storeByte; + if (!func) + func = createFunc(true, Type::Byte, m_gasMeter); + return func; +} + + +llvm::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); +} + +llvm::Value* Memory::getData() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto dataPtr = m_builder.CreateStructGEP(rtPtr, 3); + return m_builder.CreateLoad(dataPtr, "data"); +} + +llvm::Value* Memory::getSize() +{ + auto rtPtr = getRuntimeManager().getRuntimePtr(); + auto sizePtr = m_builder.CreateStructGEP(rtPtr, 4); + return m_builder.CreateLoad(sizePtr, "size"); +} + +llvm::Value* Memory::getBytePtr(llvm::Value* _index) +{ + auto idx = m_builder.CreateTrunc(_index, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 + return m_builder.CreateGEP(getData(), idx, "ptr"); +} + +void Memory::require(llvm::Value* _offset, llvm::Value* _size) +{ + if (auto constant = llvm::dyn_cast(_size)) + { + if (!constant->getValue()) + return; + } + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); +} + +void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, + llvm::Value* _destMemIdx, llvm::Value* _reqBytes) +{ + require(_destMemIdx, _reqBytes); + + // Additional copy cost + // TODO: This round ups to 32 happens in many places + auto reqBytes = m_builder.CreateTrunc(_reqBytes, Type::Gas); + auto copyWords = m_builder.CreateUDiv(m_builder.CreateNUWAdd(reqBytes, m_builder.getInt64(31)), m_builder.getInt64(32)); + m_gasMeter.countCopy(copyWords); + + // Algorithm: + // isOutsideData = idx256 >= size256 + // idx64 = trunc idx256 + // size64 = trunc size256 + // dataLeftSize = size64 - idx64 // safe if not isOutsideData + // reqBytes64 = trunc _reqBytes // require() handles large values + // bytesToCopy0 = select(reqBytes64 > dataLeftSize, dataSizeLeft, reqBytes64) // min + // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) + + auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes); + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, m_builder.getInt64(0), bytesToCopyInner); + + auto src = m_builder.CreateGEP(_srcPtr, idx64, "src"); + auto dstIdx = m_builder.CreateTrunc(_destMemIdx, Type::Size, "dstIdx"); // Never allow memory index be a type bigger than i64 + auto dst = m_builder.CreateGEP(getData(), dstIdx, "dst"); + m_builder.CreateMemCpy(dst, src, bytesToCopy, 0); +} + +} +} +} + + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT byte* mem_resize(Runtime* _rt, i256* _size) // TODO: Use uint64 as size OR use realloc in LLVM IR + { + auto size = _size->a; // Trunc to 64-bit + auto& memory = _rt->getMemory(); + memory.resize(size); + return memory.data(); + } +} diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h new file mode 100644 index 000000000..e8edce735 --- /dev/null +++ b/evmjit/libevmjit/Memory.h @@ -0,0 +1,49 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class GasMeter; + +class Memory : public RuntimeHelper +{ +public: + Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter); + + llvm::Value* loadWord(llvm::Value* _addr); + void storeWord(llvm::Value* _addr, llvm::Value* _word); + void storeByte(llvm::Value* _addr, llvm::Value* _byte); + llvm::Value* getData(); + llvm::Value* getSize(); + llvm::Value* getBytePtr(llvm::Value* _index); + void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex, + llvm::Value* _destMemIdx, llvm::Value* _byteCount); + + /// 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); + +private: + GasMeter& m_gasMeter; + + llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); + + llvm::Function* getRequireFunc(); + llvm::Function* getLoadWordFunc(); + llvm::Function* getStoreWordFunc(); + llvm::Function* getStoreByteFunc(); + + llvm::Function* m_require = nullptr; + llvm::Function* m_loadWord = nullptr; + llvm::Function* m_storeWord = nullptr; + llvm::Function* m_storeByte = nullptr; +}; + +} +} +} + diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp new file mode 100644 index 000000000..69937368c --- /dev/null +++ b/evmjit/libevmjit/Runtime.cpp @@ -0,0 +1,34 @@ +#include "Runtime.h" + +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Runtime::Runtime(RuntimeData* _data, Env* _env) : + m_data(*_data), + m_env(*_env) +{} + +bytes_ref Runtime::getReturnData() const +{ + auto data = m_data.callData; + auto size = static_cast(m_data.callDataSize); + + if (data < m_memory.data() || data >= m_memory.data() + m_memory.size() || size == 0) + { + assert(size == 0); // data can be an invalid pointer only if size is 0 + m_data.callData = nullptr; + return {}; + } + + return bytes_ref{data, size}; +} + +} +} +} diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h new file mode 100644 index 000000000..82be4a0c8 --- /dev/null +++ b/evmjit/libevmjit/Runtime.h @@ -0,0 +1,40 @@ +#pragma once + +#include "RuntimeData.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +using StackImpl = std::vector; +using MemoryImpl = bytes; + +class Runtime +{ +public: + Runtime(RuntimeData* _data, Env* _env); + + Runtime(const Runtime&) = delete; + Runtime& operator=(const Runtime&) = delete; + + StackImpl& getStack() { return m_stack; } + MemoryImpl& getMemory() { return m_memory; } + + bytes_ref getReturnData() const; + +private: + RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. + Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. + void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract. + byte* m_memoryData = nullptr; + i256 m_memorySize; + StackImpl m_stack; + MemoryImpl m_memory; +}; + +} +} +} diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h new file mode 100644 index 000000000..cc081cc58 --- /dev/null +++ b/evmjit/libevmjit/RuntimeData.h @@ -0,0 +1,60 @@ +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct RuntimeData +{ + enum Index + { + Gas, + GasPrice, + CallData, + CallDataSize, + Address, + Caller, + Origin, + CallValue, + CoinBase, + Difficulty, + GasLimit, + Number, + Timestamp, + Code, + CodeSize, + + SuicideDestAddress = Address, ///< Suicide balance destination address + ReturnData = CallData, ///< Return data pointer (set only in case of RETURN) + ReturnDataSize = CallDataSize, ///< Return data size (set only in case of RETURN) + }; + + int64_t gas = 0; + int64_t gasPrice = 0; + byte const* callData = nullptr; + uint64_t callDataSize = 0; + i256 address; + i256 caller; + i256 origin; + i256 callValue; + i256 coinBase; + i256 difficulty; + i256 gasLimit; + uint64_t number = 0; + int64_t timestamp = 0; + byte const* code = nullptr; + uint64_t codeSize = 0; + i256 codeHash; +}; + +/// VM Environment (ExtVM) opaque type +struct Env; + +} +} +} diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp new file mode 100644 index 000000000..0b5762fa2 --- /dev/null +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -0,0 +1,242 @@ +#include "RuntimeManager.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::StructType* RuntimeManager::getRuntimeDataType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + Type::Size, // gas + Type::Size, // gasPrice + Type::BytePtr, // callData + Type::Size, // callDataSize + Type::Word, // address + Type::Word, // caller + Type::Word, // origin + Type::Word, // callValue + Type::Word, // coinBase + Type::Word, // difficulty + Type::Word, // gasLimit + Type::Size, // blockNumber + Type::Size, // blockTimestamp + Type::BytePtr, // code + Type::Size, // codeSize + }; + type = llvm::StructType::create(elems, "RuntimeData"); + } + return type; +} + +llvm::StructType* RuntimeManager::getRuntimeType() +{ + static llvm::StructType* type = nullptr; + if (!type) + { + llvm::Type* elems[] = + { + Type::RuntimeDataPtr, // data + Type::EnvPtr, // Env* + Type::BytePtr, // jmpbuf + Type::BytePtr, // memory data + Type::Word, // memory size + }; + type = llvm::StructType::create(elems, "Runtime"); + } + return type; +} + +namespace +{ +llvm::Twine getName(RuntimeData::Index _index) +{ + switch (_index) + { + default: return "data"; + case RuntimeData::Address: return "address"; + case RuntimeData::Caller: return "caller"; + case RuntimeData::Origin: return "origin"; + case RuntimeData::CallValue: return "callvalue"; + case RuntimeData::GasPrice: return "gasprice"; + case RuntimeData::CoinBase: return "coinbase"; + case RuntimeData::Difficulty: return "difficulty"; + case RuntimeData::GasLimit: return "gaslimit"; + case RuntimeData::CallData: return "callData"; + case RuntimeData::Code: return "code"; + case RuntimeData::CodeSize: return "code"; + case RuntimeData::CallDataSize: return "callDataSize"; + case RuntimeData::Gas: return "gas"; + case RuntimeData::Number: return "number"; + case RuntimeData::Timestamp: return "timestamp"; + } +} +} + +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_jmpBuf(_jmpBuf), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) +{ + m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + + // save jmpBuf to be used in helper functions + auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2); + m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt"); + + // Unpack data + auto rtPtr = getRuntimePtr(); + m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + assert(m_dataPtr->getType() == Type::RuntimeDataPtr); + m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); + assert(m_envPtr->getType() == Type::EnvPtr); +} + +llvm::Value* RuntimeManager::getRuntimePtr() +{ + // Expect first argument of a function to be a pointer to Runtime + auto func = m_builder.GetInsertBlock()->getParent(); + auto rtPtr = &func->getArgumentList().front(); + assert(rtPtr->getType() == Type::RuntimePtr); + return rtPtr; +} + +llvm::Value* RuntimeManager::getDataPtr() +{ + if (getMainFunction()) + return m_dataPtr; + + auto rtPtr = getRuntimePtr(); + auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + assert(dataPtr->getType() == getRuntimeDataType()->getPointerTo()); + return dataPtr; +} + +llvm::Value* RuntimeManager::getEnvPtr() +{ + assert(getMainFunction()); // Available only in main function + return m_envPtr; +} + +llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) +{ + auto ptr = getBuilder().CreateStructGEP(getDataPtr(), _index); + assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType()); + return ptr; +} + +llvm::Value* RuntimeManager::get(RuntimeData::Index _index) +{ + return getBuilder().CreateLoad(getPtr(_index), getName(_index)); +} + +void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value) +{ + auto ptr = getPtr(_index); + assert(ptr->getType() == _value->getType()->getPointerTo()); + getBuilder().CreateStore(_value, ptr); +} + +void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size) +{ + auto memPtr = getBuilder().CreateStructGEP(getRuntimePtr(), 3); + auto mem = getBuilder().CreateLoad(memPtr, "memory"); + auto idx = m_builder.CreateTrunc(_offset, Type::Size, "idx"); // Never allow memory index be a type bigger than i64 // TODO: Report bug & fix to LLVM + auto returnDataPtr = getBuilder().CreateGEP(mem, idx); + set(RuntimeData::ReturnData, returnDataPtr); + + auto size64 = getBuilder().CreateTrunc(_size, Type::Size); + set(RuntimeData::ReturnDataSize, size64); +} + +void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) +{ + set(RuntimeData::SuicideDestAddress, _balanceAddress); +} + +void RuntimeManager::abort(llvm::Value* _jmpBuf) +{ + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); +} + +llvm::Value* RuntimeManager::get(Instruction _inst) +{ + switch (_inst) + { + default: assert(false); return nullptr; + case Instruction::ADDRESS: return get(RuntimeData::Address); + case Instruction::CALLER: return get(RuntimeData::Caller); + case Instruction::ORIGIN: return get(RuntimeData::Origin); + case Instruction::CALLVALUE: return get(RuntimeData::CallValue); + case Instruction::GASPRICE: return get(RuntimeData::GasPrice); + case Instruction::COINBASE: return get(RuntimeData::CoinBase); + case Instruction::DIFFICULTY: return get(RuntimeData::Difficulty); + case Instruction::GASLIMIT: return get(RuntimeData::GasLimit); + case Instruction::NUMBER: return get(RuntimeData::Number); + case Instruction::TIMESTAMP: return get(RuntimeData::Timestamp); + } +} + +llvm::Value* RuntimeManager::getCallData() +{ + return get(RuntimeData::CallData); +} + +llvm::Value* RuntimeManager::getCode() +{ + // OPT Check what is faster + //return get(RuntimeData::Code); + return m_builder.CreateGlobalStringPtr({reinterpret_cast(m_codeBegin), static_cast(m_codeEnd - m_codeBegin)}, "code"); +} + +llvm::Value* RuntimeManager::getCodeSize() +{ + return Constant::get(m_codeEnd - m_codeBegin); +} + +llvm::Value* RuntimeManager::getCallDataSize() +{ + auto value = get(RuntimeData::CallDataSize); + assert(value->getType() == Type::Size); + return getBuilder().CreateZExt(value, Type::Word); +} + +llvm::Value* RuntimeManager::getJmpBufExt() +{ + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); +} + +llvm::Value* RuntimeManager::getGas() +{ + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; +} + +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); +} + +void RuntimeManager::setGas(llvm::Value* _gas) +{ + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); +} + +} +} +} diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h new file mode 100644 index 000000000..30c69ec88 --- /dev/null +++ b/evmjit/libevmjit/RuntimeManager.h @@ -0,0 +1,60 @@ +#pragma once + +#include "CompilerHelper.h" +#include "Type.h" +#include "RuntimeData.h" +#include "Instruction.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class RuntimeManager: public CompilerHelper +{ +public: + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); + + llvm::Value* getRuntimePtr(); + llvm::Value* getDataPtr(); + llvm::Value* getEnvPtr(); + + llvm::Value* get(RuntimeData::Index _index); + llvm::Value* get(Instruction _inst); + llvm::Value* getGas(); + llvm::Value* getGasPtr(); + llvm::Value* getCallData(); + llvm::Value* getCode(); + llvm::Value* getCodeSize(); + llvm::Value* getCallDataSize(); + llvm::Value* getJmpBuf() { return m_jmpBuf; } + void setGas(llvm::Value* _gas); + + void registerReturnData(llvm::Value* _index, llvm::Value* _size); + void registerSuicide(llvm::Value* _balanceAddress); + + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } + + static llvm::StructType* getRuntimeType(); + static llvm::StructType* getRuntimeDataType(); + +private: + llvm::Value* getPtr(RuntimeData::Index _index); + void set(RuntimeData::Index _index, llvm::Value* _value); + llvm::Value* getJmpBufExt(); + + llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; + llvm::Value* m_dataPtr = nullptr; + llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; +}; + +} +} +} diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp new file mode 100644 index 000000000..81a954991 --- /dev/null +++ b/evmjit/libevmjit/Stack.cpp @@ -0,0 +1,200 @@ +#include "Stack.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Runtime.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): + CompilerHelper(_builder), + m_runtimeManager(_runtimeManager) +{ + m_arg = m_builder.CreateAlloca(Type::Word, nullptr, "stack.arg"); + + using namespace llvm; + using Linkage = GlobalValue::LinkageTypes; + + auto module = getModule(); + + llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; + m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); + + llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; + m_set = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_set", module); +} + +llvm::Function* Stack::getPopFunc() +{ + auto& func = m_pop; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto ok = createCall(extPopFunc, {rt, index}); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRetVoid(); + } + return func; +} + +llvm::Function* Stack::getGetFunc() +{ + auto& func = m_get; + if (!func) + { + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + auto jmpBuf = index->getNextNode(); + jmpBuf->setName("jmpBuf"); + + InsertPointGuard guard{m_builder}; + auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func); + auto underflowBB = llvm::BasicBlock::Create(m_builder.getContext(), "Underflow", func); + auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); + + m_builder.SetInsertPoint(entryBB); + auto valuePtr = createCall(extGetFunc, {rt, index}); + auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.abort(jmpBuf); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + +llvm::Value* Stack::get(size_t _index) +{ + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); + return m_builder.CreateLoad(valuePtr); +} + +void Stack::set(size_t _index, llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall3(m_set, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); +} + +void Stack::pop(size_t _count) +{ + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); +} + +void Stack::push(llvm::Value* _value) +{ + m_builder.CreateStore(_value, m_arg); + m_builder.CreateCall2(m_push, m_runtimeManager.getRuntimePtr(), m_arg); +} + + +size_t Stack::maxStackSize = 0; + +} +} +} + +extern "C" +{ + using namespace dev::eth::jit; + + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) + { + auto& stack = _rt->getStack(); + if (stack.size() < _count) + return false; + + stack.erase(stack.end() - _count, stack.end()); + return true; + } + + EXPORT void stack_push(Runtime* _rt, i256 const* _word) + { + auto& stack = _rt->getStack(); + stack.push_back(*_word); + + if (stack.size() > Stack::maxStackSize) + Stack::maxStackSize = stack.size(); + } + + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) + { + auto& stack = _rt->getStack(); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; + } + + EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) + { + auto& stack = _rt->getStack(); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; + + *(stack.rbegin() + _index) = *_word; + } + + EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) + { + // It asumes all indexes are less than 2^64 + + auto index = _index->a; + if (_index->b || _index->c || _index->d) // if bigger that 2^64 + index = std::numeric_limits::max(); // set max to fill with 0 leter + + auto data = _rtData->callData; + auto size = _rtData->callDataSize; + for (auto i = 0; i < 32; ++i) + { + if (index < size) + { + o_value[i] = data[index]; + ++index; // increment only if in range + } + else + o_value[i] = 0; + } + } + +} // extern "C" + diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h new file mode 100644 index 000000000..4b6fa374f --- /dev/null +++ b/evmjit/libevmjit/Stack.h @@ -0,0 +1,44 @@ +#pragma once + +#include "CompilerHelper.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ +class RuntimeManager; + +class Stack : public CompilerHelper +{ +public: + Stack(llvm::IRBuilder<>& builder, RuntimeManager& runtimeManager); + + llvm::Value* get(size_t _index); + void set(size_t _index, llvm::Value* _value); + void pop(size_t _count); + void push(llvm::Value* _value); + + static size_t maxStackSize; + +private: + llvm::Function* getPopFunc(); + llvm::Function* getGetFunc(); + + RuntimeManager& m_runtimeManager; + + llvm::Function* m_pop = nullptr; + llvm::Function* m_push; + llvm::Function* m_get = nullptr; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp new file mode 100644 index 000000000..8e2bc13fc --- /dev/null +++ b/evmjit/libevmjit/Type.cpp @@ -0,0 +1,70 @@ +#include "Type.h" +#include "RuntimeManager.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +llvm::IntegerType* Type::Word; +llvm::PointerType* Type::WordPtr; +llvm::IntegerType* Type::lowPrecision; +llvm::IntegerType* Type::Bool; +llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; +llvm::PointerType* Type::GasPtr; +llvm::IntegerType* Type::Byte; +llvm::PointerType* Type::BytePtr; +llvm::Type* Type::Void; +llvm::IntegerType* Type::MainReturn; +llvm::PointerType* Type::EnvPtr; +llvm::PointerType* Type::RuntimeDataPtr; +llvm::PointerType* Type::RuntimePtr; +llvm::ConstantInt* Constant::gasMax; + +void Type::init(llvm::LLVMContext& _context) +{ + if (!Word) // Do init only once + { + Word = llvm::Type::getIntNTy(_context, 256); + WordPtr = Word->getPointerTo(); + lowPrecision = llvm::Type::getInt64Ty(_context); + // TODO: Size should be architecture-dependent + Bool = llvm::Type::getInt1Ty(_context); + Size = llvm::Type::getInt64Ty(_context); + Gas = Size; + GasPtr = Gas->getPointerTo(); + Byte = llvm::Type::getInt8Ty(_context); + BytePtr = Byte->getPointerTo(); + Void = llvm::Type::getVoidTy(_context); + MainReturn = llvm::Type::getInt32Ty(_context); + + EnvPtr = llvm::StructType::create(_context, "Env")->getPointerTo(); + RuntimeDataPtr = RuntimeManager::getRuntimeDataType()->getPointerTo(); + RuntimePtr = RuntimeManager::getRuntimeType()->getPointerTo(); + + Constant::gasMax = llvm::ConstantInt::getSigned(Type::Gas, std::numeric_limits::max()); + } +} + +llvm::ConstantInt* Constant::get(int64_t _n) +{ + return llvm::ConstantInt::getSigned(Type::Word, _n); +} + +llvm::ConstantInt* Constant::get(llvm::APInt const& _n) +{ + return llvm::ConstantInt::get(Type::Word->getContext(), _n); +} + +llvm::ConstantInt* Constant::get(ReturnCode _returnCode) +{ + return llvm::ConstantInt::get(Type::MainReturn, static_cast(_returnCode)); +} + +} +} +} + diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h new file mode 100644 index 000000000..b8a4a09eb --- /dev/null +++ b/evmjit/libevmjit/Type.h @@ -0,0 +1,60 @@ +#pragma once + +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct Type +{ + static llvm::IntegerType* Word; + static llvm::PointerType* WordPtr; + + /// Type for doing low precision arithmetics where 256-bit precision is not supported by native target + /// @TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required + static llvm::IntegerType* lowPrecision; + + static llvm::IntegerType* Bool; + static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; + + static llvm::IntegerType* Byte; + static llvm::PointerType* BytePtr; + + static llvm::Type* Void; + + /// Main function return type + static llvm::IntegerType* MainReturn; + + static llvm::PointerType* EnvPtr; + static llvm::PointerType* RuntimeDataPtr; + static llvm::PointerType* RuntimePtr; + + static void init(llvm::LLVMContext& _context); +}; + +struct Constant +{ + static llvm::ConstantInt* gasMax; + + /// Returns word-size constant + static llvm::ConstantInt* get(int64_t _n); + static llvm::ConstantInt* get(llvm::APInt const& _n); + + static llvm::ConstantInt* get(ReturnCode _returnCode); +}; + +} +} +} + diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp new file mode 100644 index 000000000..bf3bf93b3 --- /dev/null +++ b/evmjit/libevmjit/Utils.cpp @@ -0,0 +1,13 @@ +#include "Utils.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + + +} +} +} diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h new file mode 100644 index 000000000..aad975f5b --- /dev/null +++ b/evmjit/libevmjit/Utils.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "Common.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +struct JIT: public NoteChannel { static const char* name() { return "JIT"; } }; + +//#define clog(CHANNEL) std::cerr +#define clog(CHANNEL) std::ostream(nullptr) + +// The same as assert, but expression is always evaluated and result returned +#define CHECK(expr) (assert(expr), expr) + +} +} +} diff --git a/evmjit/libevmjit/interface.cpp b/evmjit/libevmjit/interface.cpp new file mode 100644 index 000000000..645f3d150 --- /dev/null +++ b/evmjit/libevmjit/interface.cpp @@ -0,0 +1,40 @@ +#include "ExecutionEngine.h" + +extern "C" +{ + +using namespace dev::eth::jit; + +#ifdef _MSC_VER +#define _ALLOW_KEYWORD_MACROS +#define noexcept throw() +#endif + +EXPORT void* evmjit_create() noexcept +{ + // TODO: Make sure ExecutionEngine constructor does not throw + return new(std::nothrow) ExecutionEngine; +} + +EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept +{ + delete _engine; +} + +EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept +{ + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + + try + { + auto returnCode = _engine->run(_data, _env); + return static_cast(returnCode); + } + catch(...) + { + return static_cast(ReturnCode::UnexpectedException); + } +} + +} diff --git a/evmjit/libevmjit/interface.h b/evmjit/libevmjit/interface.h new file mode 100644 index 000000000..4f4d56610 --- /dev/null +++ b/evmjit/libevmjit/interface.h @@ -0,0 +1,13 @@ + +#ifdef __cplusplus +extern "C" { +#endif + +void* evmjit_create(); +int evmjit_run(void* _jit, void* _data, void* _env); +void evmjit_destroy(void* _jit); + + +#ifdef __cplusplus +} +#endif diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_end.h b/evmjit/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..023c8021e --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,5 @@ +#if defined(_MSC_VER) + #pragma warning(pop) +#else + #pragma GCC diagnostic pop +#endif diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..bf34ade99 --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,8 @@ +#if defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 4267 4244 4800) +#else + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-parameter" + #pragma GCC diagnostic ignored "-Wconversion" +#endif From a52fc7bdd746143c2b21201692437600a905cd9c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 22:08:30 +0100 Subject: [PATCH 41/59] Icon updates. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c4731642c..6cd9c7adf 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ By Gav Wood et al, 2013, 2014, 2015. | Linux | OSX | Windows ----------|---------|-----|-------- -develop | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) -master | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](http://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) -evmjit | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](http://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](http://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A +develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20develop%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20develop%20branch/builds/-1) +master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20C%2B%2B%20master%20branch)](https://build.ethdev.com/builders/Windows%20C%2B%2B%20master%20branch/builds/-1) +evmjit | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/Linux%20C%2B%2B%20develop%20evmjit/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20C%2B%2B%20develop%20evmjit)](https://build.ethdev.com/builders/OSX%20C%2B%2B%20develop%20evmjit/builds/-1) | N/A [![Stories in Ready](https://badge.waffle.io/ethereum/cpp-ethereum.png?label=ready&title=Ready)](http://waffle.io/ethereum/cpp-ethereum) From 87e956729cd889ece16a4a65592641a5025ebf73 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 17 Feb 2015 16:21:38 +0100 Subject: [PATCH 42/59] Inline member initialisation renamed VariableDefinition class to VariableDeclarationStatement added tests --- libsolidity/AST.cpp | 22 ++++++++---- libsolidity/AST.h | 25 +++++++------ libsolidity/ASTForward.h | 2 +- libsolidity/ASTJsonConverter.cpp | 4 +-- libsolidity/ASTJsonConverter.h | 4 +-- libsolidity/ASTPrinter.cpp | 4 +-- libsolidity/ASTPrinter.h | 4 +-- libsolidity/ASTVisitor.h | 8 ++--- libsolidity/AST_accept.h | 12 +++---- libsolidity/Compiler.cpp | 16 +++++++-- libsolidity/Compiler.h | 3 +- libsolidity/ExpressionCompiler.cpp | 30 ++++++++++++++-- libsolidity/ExpressionCompiler.h | 13 ++++++- libsolidity/NameAndTypeResolver.cpp | 6 ++-- libsolidity/NameAndTypeResolver.h | 2 +- libsolidity/Parser.cpp | 47 ++++++++++++------------ libsolidity/Parser.h | 9 ++--- libsolidity/Types.cpp | 2 +- test/SolidityEndToEndTest.cpp | 55 +++++++++++++++++++++++++++++ 19 files changed, 194 insertions(+), 74 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 761427db4..a18785ae1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -77,6 +77,9 @@ void ContractDefinition::checkTypeRequirements() for (ASTPointer const& function: getDefinedFunctions()) function->checkTypeRequirements(); + for (ASTPointer const& variable: m_stateVariables) + variable->checkTypeRequirements(); + // check for hash collisions in function signatures set> hashes; for (auto const& it: getInterfaceFunctionList()) @@ -294,6 +297,12 @@ bool VariableDeclaration::isLValue() const return !isExternalFunctionParameter(); } +void VariableDeclaration::checkTypeRequirements() +{ + if (m_value) + m_value->checkTypeRequirements(); +} + bool VariableDeclaration::isExternalFunctionParameter() const { auto const* function = dynamic_cast(getScope()); @@ -390,26 +399,26 @@ void Return::checkTypeRequirements() m_expression->expectType(*m_returnParameters->getParameters().front()->getType()); } -void VariableDefinition::checkTypeRequirements() +void VariableDeclarationStatement::checkTypeRequirements() { // Variables can be declared without type (with "var"), in which case the first assignment // sets the type. // Note that assignments before the first declaration are legal because of the special scoping // rules inherited from JavaScript. - if (m_value) + if (m_variable->getValue()) { if (m_variable->getType()) - m_value->expectType(*m_variable->getType()); + m_variable->getValue()->expectType(*m_variable->getType()); else { // no type declared and no previous assignment, infer the type - m_value->checkTypeRequirements(); - TypePointer type = m_value->getType(); + m_variable->getValue()->checkTypeRequirements(); + TypePointer type = m_variable->getValue()->getType(); if (type->getCategory() == Type::Category::IntegerConstant) { auto intType = dynamic_pointer_cast(type)->getIntegerType(); if (!intType) - BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString())); + BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString())); type = intType; } else if (type->getCategory() == Type::Category::Void) @@ -418,7 +427,6 @@ void VariableDefinition::checkTypeRequirements() } } } - void Assignment::checkTypeRequirements() { m_leftHandSide->checkTypeRequirements(); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 64dac594d..c7fd068d9 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -432,14 +432,17 @@ class VariableDeclaration: public Declaration { public: VariableDeclaration(Location const& _location, ASTPointer const& _type, - ASTPointer const& _name, Visibility _visibility, - bool _isStateVar = false, bool _isIndexed = false): - Declaration(_location, _name, _visibility), m_typeName(_type), - m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} + ASTPointer const& _name, ASTPointer _value, + Visibility _visibility, + bool _isStateVar = false, bool _isIndexed = false): + Declaration(_location, _name, _visibility), + m_typeName(_type), m_value(_value), + m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; TypeName const* getTypeName() const { return m_typeName.get(); } + ASTPointer const& getValue() const { return m_value; } /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// declared and there is no assignment to the variable that fixes the type. @@ -447,6 +450,9 @@ public: void setType(std::shared_ptr const& _type) { m_type = _type; } virtual bool isLValue() const override; + + /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. + void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } bool isExternalFunctionParameter() const; bool isStateVariable() const { return m_isStateVariable; } @@ -457,6 +463,7 @@ protected: private: ASTPointer m_typeName; ///< can be empty ("var") + ASTPointer m_value; ///< the assigned value, can be missing bool m_isStateVariable; ///< Whether or not this is a contract state variable bool m_isIndexed; ///< Whether this is an indexed variable (used by events). @@ -833,22 +840,20 @@ private: * also be "var") but the actual assignment can be missing. * Examples: var a = 2; uint256 a; */ -class VariableDefinition: public Statement +class VariableDeclarationStatement: public Statement { public: - VariableDefinition(Location const& _location, ASTPointer _variable, - ASTPointer _value): - Statement(_location), m_variable(_variable), m_value(_value) {} + VariableDeclarationStatement(Location const& _location, ASTPointer _variable): + Statement(_location), m_variable(_variable) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; virtual void checkTypeRequirements() override; VariableDeclaration const& getDeclaration() const { return *m_variable; } - Expression const* getExpression() const { return m_value.get(); } + Expression const* getExpression() const { return m_variable->getValue().get(); } private: ASTPointer m_variable; - ASTPointer m_value; ///< the assigned value, can be missing }; /** diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 0b6817e45..3a151b63e 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -63,7 +63,7 @@ class ForStatement; class Continue; class Break; class Return; -class VariableDefinition; +class VariableDeclarationStatement; class ExpressionStatement; class Expression; class Assignment; diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index 04feafe2f..c30e4ca2b 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -198,7 +198,7 @@ bool ASTJsonConverter::visit(Return const&) return true; } -bool ASTJsonConverter::visit(VariableDefinition const&) +bool ASTJsonConverter::visit(VariableDeclarationStatement const&) { addJsonNode("VariableDefinition", {}, true); return true; @@ -394,7 +394,7 @@ void ASTJsonConverter::endVisit(Return const&) goUp(); } -void ASTJsonConverter::endVisit(VariableDefinition const&) +void ASTJsonConverter::endVisit(VariableDeclarationStatement const&) { goUp(); } diff --git a/libsolidity/ASTJsonConverter.h b/libsolidity/ASTJsonConverter.h index 466801e9c..30a92e66c 100644 --- a/libsolidity/ASTJsonConverter.h +++ b/libsolidity/ASTJsonConverter.h @@ -64,7 +64,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -98,7 +98,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index d380b0029..aead6abd8 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -225,7 +225,7 @@ bool ASTPrinter::visit(Return const& _node) return goDeeper(); } -bool ASTPrinter::visit(VariableDefinition const& _node) +bool ASTPrinter::visit(VariableDeclarationStatement const& _node) { writeLine("VariableDefinition"); printSourcePart(_node); @@ -469,7 +469,7 @@ void ASTPrinter::endVisit(Return const&) m_indentation--; } -void ASTPrinter::endVisit(VariableDefinition const&) +void ASTPrinter::endVisit(VariableDeclarationStatement const&) { m_indentation--; } diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index d9072aacc..7a0ef5a65 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -68,7 +68,7 @@ public: bool visit(Continue const& _node) override; bool visit(Break const& _node) override; bool visit(Return const& _node) override; - bool visit(VariableDefinition const& _node) override; + bool visit(VariableDeclarationStatement const& _node) override; bool visit(ExpressionStatement const& _node) override; bool visit(Expression const& _node) override; bool visit(Assignment const& _node) override; @@ -109,7 +109,7 @@ public: void endVisit(Continue const&) override; void endVisit(Break const&) override; void endVisit(Return const&) override; - void endVisit(VariableDefinition const&) override; + void endVisit(VariableDeclarationStatement const&) override; void endVisit(ExpressionStatement const&) override; void endVisit(Expression const&) override; void endVisit(Assignment const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index a7fa6b1cf..2ecfbe4b1 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -69,7 +69,7 @@ public: virtual bool visit(Continue&) { return true; } virtual bool visit(Break&) { return true; } virtual bool visit(Return&) { return true; } - virtual bool visit(VariableDefinition&) { return true; } + virtual bool visit(VariableDeclarationStatement&) { return true; } virtual bool visit(ExpressionStatement&) { return true; } virtual bool visit(Expression&) { return true; } virtual bool visit(Assignment&) { return true; } @@ -112,7 +112,7 @@ public: virtual void endVisit(Continue&) { } virtual void endVisit(Break&) { } virtual void endVisit(Return&) { } - virtual void endVisit(VariableDefinition&) { } + virtual void endVisit(VariableDeclarationStatement&) { } virtual void endVisit(ExpressionStatement&) { } virtual void endVisit(Expression&) { } virtual void endVisit(Assignment&) { } @@ -159,7 +159,7 @@ public: virtual bool visit(Continue const&) { return true; } virtual bool visit(Break const&) { return true; } virtual bool visit(Return const&) { return true; } - virtual bool visit(VariableDefinition const&) { return true; } + virtual bool visit(VariableDeclarationStatement const&) { return true; } virtual bool visit(ExpressionStatement const&) { return true; } virtual bool visit(Expression const&) { return true; } virtual bool visit(Assignment const&) { return true; } @@ -202,7 +202,7 @@ public: virtual void endVisit(Continue const&) { } virtual void endVisit(Break const&) { } virtual void endVisit(Return const&) { } - virtual void endVisit(VariableDefinition const&) { } + virtual void endVisit(VariableDeclarationStatement const&) { } virtual void endVisit(ExpressionStatement const&) { } virtual void endVisit(Expression const&) { } virtual void endVisit(Assignment const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index b71e103df..217a565f0 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -475,24 +475,24 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTVisitor& _visitor) +void VariableDeclarationStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); + if (m_variable->getValue()) + m_variable->getValue()->accept(_visitor); } _visitor.endVisit(*this); } -void VariableDefinition::accept(ASTConstVisitor& _visitor) const +void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) { m_variable->accept(_visitor); - if (m_value) - m_value->accept(_visitor); + if (m_variable->getValue()) + m_variable->getValue()->accept(_visitor); } _visitor.endVisit(*this); } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 14acc0113..f552210f4 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -73,7 +73,7 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp for (ASTPointer const& base: contract->getBaseContracts()) { ContractDefinition const* baseContract = dynamic_cast( - base->getName()->getReferencedDeclaration()); + base->getName()->getReferencedDeclaration()); solAssert(baseContract, ""); if (baseArguments.count(baseContract) == 0) baseArguments[baseContract] = &base->getArguments(); @@ -85,12 +85,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp { ContractDefinition const* base = bases[bases.size() - i]; solAssert(base, ""); + initializeStateVariables(*base); FunctionDefinition const* baseConstructor = base->getConstructor(); if (!baseConstructor) continue; solAssert(baseArguments[base], ""); appendBaseConstructorCall(*baseConstructor, *baseArguments[base]); } + initializeStateVariables(_contract); if (_contract.getConstructor()) appendConstructorCall(*_contract.getConstructor()); @@ -247,6 +249,16 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) m_context.addStateVariable(*variable); } +void Compiler::initializeStateVariables(ContractDefinition const& _contract) +{ + for(ASTPointer const& variable: _contract.getStateVariables()) + if (variable->getValue()) + { + compileExpression(*(variable->getValue()), (variable->getValue())->getType()); + ExpressionCompiler::appendStateVariableInitialization(m_context, *variable); + } +} + bool Compiler::visit(VariableDeclaration const& _variableDeclaration) { solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration."); @@ -429,7 +441,7 @@ bool Compiler::visit(Return const& _return) return false; } -bool Compiler::visit(VariableDefinition const& _variableDefinition) +bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition) { if (Expression const* expression = _variableDefinition.getExpression()) { diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 1aeaee88f..0838512ee 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -59,6 +59,7 @@ private: void appendReturnValuePacker(TypePointers const& _typeParameters); void registerStateVariables(ContractDefinition const& _contract); + void initializeStateVariables(ContractDefinition const& _contract); virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(FunctionDefinition const& _function) override; @@ -68,7 +69,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; - virtual bool visit(VariableDefinition const& _variableDefinition) override; + virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a8bc53e0f..74dfb2b5e 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -56,6 +56,19 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, compiler.appendStateVariableAccessor(_varDecl); } +void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) +{ + ExpressionCompiler compiler(_context, _optimize); + compiler.appendStateVariableInitialization(_varDecl); +} + +void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) +{ + m_currentLValue.fromStateVariable(_varDecl); + m_currentLValue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); + m_currentLValue.reset(); +} + bool ExpressionCompiler::visit(Assignment const& _assignment) { _assignment.getRightHandSide().accept(*this); @@ -77,7 +90,6 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) } m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); m_currentLValue.reset(); - return false; } @@ -1018,12 +1030,24 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D m_dataType = _identifier.getType(); solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); } + m_size = unsigned(m_dataType->getStorageSize()); + } else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); } +void ExpressionCompiler::LValue::fromStateVariable(VariableDeclaration const& _declaration) +{ + solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); + *m_context << m_context->getStorageLocationOfVariable(_declaration); + m_type = LValueType::Storage; + m_dataType = _declaration.getType(); + solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), + "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); + m_size = unsigned(m_dataType->getStorageSize()); +} + void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const { switch (m_type) @@ -1117,7 +1141,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co } else { - solAssert(_sourceType.getCategory() == m_dataType->getCategory(), ""); + solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "Wrong type conversation for assignment."); if (m_dataType->getCategory() == Type::Category::ByteArray) { CompilerUtils(*m_context).copyByteArrayToStorage( diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 471d81865..3567a9148 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -59,6 +59,9 @@ public: /// Appends code for a State Variable accessor function static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + /// Appends code for a State Variable Initialization function + static void appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); + private: explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} @@ -111,6 +114,9 @@ private: /// Appends code for a State Variable accessor function void appendStateVariableAccessor(VariableDeclaration const& _varDecl); + /// Appends code for a State Variable initialization + void appendStateVariableInitialization(VariableDeclaration const& _varDecl); + /** * Helper class to store and retrieve lvalues to and from various locations. * All types except STACK store a reference in a slot on the stack, STACK just @@ -126,8 +132,13 @@ private: std::shared_ptr const& _dataType, unsigned _baseStackOffset = 0); /// Set type according to the declaration and retrieve the reference. - /// @a _expression is the current expression + /// @a _identifier is the current identifier void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); + + /// Set type according to the declaration and retrieve the reference. + /// @a _declaration is the variable declaration + void fromStateVariable(VariableDeclaration const& _declaration); + void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } bool isValid() const { return m_type != LValueType::None; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index e19b0bf9e..15e1ac6f5 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -267,12 +267,12 @@ void DeclarationRegistrationHelper::endVisit(ModifierDefinition&) closeCurrentScope(); } -void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefinition) +void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement) { // Register the local variables with the function // This does not fit here perfectly, but it saves us another AST visit. - solAssert(m_currentFunction, "Variable definition without function."); - m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); + solAssert(m_currentFunction, "Variable declaration without function."); + m_currentFunction->addLocalVariable(_variableDeclarationStatement.getDeclaration()); } bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index d9ac98ce5..63b8ab637 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -105,7 +105,7 @@ private: void endVisit(FunctionDefinition& _function) override; bool visit(ModifierDefinition& _modifier) override; void endVisit(ModifierDefinition& _modifier) override; - void endVisit(VariableDefinition& _variableDefinition) override; + void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override; bool visit(VariableDeclaration& _declaration) override; bool visit(EventDefinition& _event) override; void endVisit(EventDefinition& _event) override; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 72334c6cc..9940fb8d9 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -148,6 +148,7 @@ ASTPointer Parser::parseContractDefinition() { VarDeclParserOptions options; options.isStateVariable = true; + options.allowInitialValue = true; stateVariables.push_back(parseVariableDeclaration(options)); expectToken(Token::Semicolon); } @@ -324,9 +325,19 @@ ASTPointer Parser::parseVariableDeclaration(VarDeclParserOp } else identifier = expectIdentifierToken(); - return nodeFactory.createNode(type, identifier, - visibility, _options.isStateVariable, - isIndexed); + ASTPointer value; + if (_options.allowInitialValue) + { + if (m_scanner->getCurrentToken() == Token::Assign) + { + m_scanner->next(); + value = parseExpression(); + nodeFactory.setEndPositionFromNode(value); + } + } + return nodeFactory.createNode(type, identifier, value, + visibility, _options.isStateVariable, + isIndexed); } ASTPointer Parser::parseModifierDefinition() @@ -519,7 +530,7 @@ ASTPointer Parser::parseStatement() } // fall-through default: - statement = parseVarDefOrExprStmt(); + statement = parseVarDeclOrExprStmt(); } expectToken(Token::Semicolon); return statement; @@ -568,7 +579,7 @@ ASTPointer Parser::parseForStatement() // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? if (m_scanner->getCurrentToken() != Token::Semicolon) - initExpression = parseVarDefOrExprStmt(); + initExpression = parseVarDeclOrExprStmt(); expectToken(Token::Semicolon); if (m_scanner->getCurrentToken() != Token::Semicolon) @@ -587,30 +598,22 @@ ASTPointer Parser::parseForStatement() body); } -ASTPointer Parser::parseVarDefOrExprStmt() +ASTPointer Parser::parseVarDeclOrExprStmt() { - if (peekVariableDefinition()) - return parseVariableDefinition(); + if (peekVariableDeclarationStatement()) + return parseVariableDeclarationStatement(); else return parseExpressionStatement(); } -ASTPointer Parser::parseVariableDefinition() +ASTPointer Parser::parseVariableDeclarationStatement() { ASTNodeFactory nodeFactory(*this); VarDeclParserOptions options; options.allowVar = true; + options.allowInitialValue = true; ASTPointer variable = parseVariableDeclaration(options); - ASTPointer value; - if (m_scanner->getCurrentToken() == Token::Assign) - { - m_scanner->next(); - value = parseExpression(); - nodeFactory.setEndPositionFromNode(value); - } - else - nodeFactory.setEndPositionFromNode(variable); - return nodeFactory.createNode(variable, value); + return nodeFactory.createNode(variable); } ASTPointer Parser::parseExpressionStatement() @@ -822,11 +825,11 @@ pair>, vector>> Parser::pars } -bool Parser::peekVariableDefinition() +bool Parser::peekVariableDeclarationStatement() { - // distinguish between variable definition (and potentially assignment) and expression statement + // distinguish between variable declaration (and potentially assignment) and expression statement // (which include assignments to other expressions and pre-declared variables) - // We have a variable definition if we get a keyword that specifies a type name, or + // We have a variable declaration if we get a keyword that specifies a type name, or // in the case of a user-defined type, we have two identifiers following each other. return (m_scanner->getCurrentToken() == Token::Mapping || m_scanner->getCurrentToken() == Token::Var || diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 1bb4ea977..4034aec85 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -51,6 +51,7 @@ private: bool isStateVariable = false; bool allowIndexed = false; bool allowEmptyName = false; + bool allowInitialValue = false; }; ///@{ @@ -76,8 +77,8 @@ private: ASTPointer parseIfStatement(); ASTPointer parseWhileStatement(); ASTPointer parseForStatement(); - ASTPointer parseVarDefOrExprStmt(); - ASTPointer parseVariableDefinition(); + ASTPointer parseVarDeclOrExprStmt(); + ASTPointer parseVariableDeclarationStatement(); ASTPointer parseExpressionStatement(); ASTPointer parseExpression(); ASTPointer parseBinaryExpression(int _minPrecedence = 4); @@ -91,8 +92,8 @@ private: ///@{ ///@name Helper functions - /// Peeks ahead in the scanner to determine if a variable definition is going to follow - bool peekVariableDefinition(); + /// Peeks ahead in the scanner to determine if a variable declaration statement is going to follow + bool peekVariableDeclarationStatement(); /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index a9c480176..55dedd921 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -653,7 +653,7 @@ MemberList const& StructType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - vector> members; + MemberList::MemberMap members; for (ASTPointer const& variable: m_struct.getMembers()) members.push_back(make_pair(variable->getName(), variable->getType())); m_members.reset(new MemberList(members)); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 8c87db2d8..1f80b1017 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2570,6 +2570,61 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints) BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); } +BOOST_AUTO_TEST_CASE(inline_member_init) +{ + char const* sourceCode = R"( + contract test { + function test(){ + m_b = 6; + m_c = 8; + } + uint m_a = 5; + uint m_b; + uint m_c = 7; + function get() returns (uint a, uint b, uint c){ + a = m_a; + b = m_b; + c = m_c; + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(5, 6, 8)); +} + +BOOST_AUTO_TEST_CASE(inline_member_init_inheritence) +{ + char const* sourceCode = R"( + contract Base { + function Base(){} + uint m_base = 5; + function getBMember() returns (uint i) { return m_base; } + } + contract Derived is Base { + function Derived(){} + uint m_derived = 6; + function getDMember() returns (uint i) { return m_derived; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5)); + BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6)); +} + +BOOST_AUTO_TEST_CASE(inline_member_init_inheritence_without_constructor) +{ + char const* sourceCode = R"( + contract Base { + uint m_base = 5; + function getBMember() returns (uint i) { return m_base; } + } + contract Derived is Base { + uint m_derived = 6; + function getDMember() returns (uint i) { return m_derived; } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5)); + BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6)); +} + BOOST_AUTO_TEST_CASE(external_function) { char const* sourceCode = R"( From 0a334cd7db9d84d3fb9efe9f64f1f0aac0fcbc64 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 11:57:42 +0100 Subject: [PATCH 43/59] cosmetic changes --- libsolidity/Compiler.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 17 ++++++----------- libsolidity/ExpressionCompiler.h | 2 +- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index f552210f4..bdc29fab9 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -251,7 +251,7 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract) void Compiler::initializeStateVariables(ContractDefinition const& _contract) { - for(ASTPointer const& variable: _contract.getStateVariables()) + for (ASTPointer const& variable: _contract.getStateVariables()) if (variable->getValue()) { compileExpression(*(variable->getValue()), (variable->getValue())->getType()); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 74dfb2b5e..c2a10ab45 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -64,7 +64,7 @@ void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _con void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { - m_currentLValue.fromStateVariable(_varDecl); + m_currentLValue.fromVariableDeclaration(_varDecl); m_currentLValue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); m_currentLValue.reset(); } @@ -1024,22 +1024,17 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) - { - *m_context << m_context->getStorageLocationOfVariable(_declaration); - m_type = LValueType::Storage; - m_dataType = _identifier.getType(); - solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), - "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); - } + //{ + fromVariableDeclaration(_declaration); + //} else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); } -void ExpressionCompiler::LValue::fromStateVariable(VariableDeclaration const& _declaration) +void ExpressionCompiler::LValue::fromVariableDeclaration(Declaration const& _declaration) { - solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); + //solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); *m_context << m_context->getStorageLocationOfVariable(_declaration); m_type = LValueType::Storage; m_dataType = _declaration.getType(); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 3567a9148..a29abc7f1 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -137,7 +137,7 @@ private: /// Set type according to the declaration and retrieve the reference. /// @a _declaration is the variable declaration - void fromStateVariable(VariableDeclaration const& _declaration); + void fromVariableDeclaration(const Declaration &_declaration); void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } From d66c448d8215abf0b21d122074536eb9916263c2 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 12:27:39 +0100 Subject: [PATCH 44/59] corrected accept for variableDeclaration changes after code review --- libsolidity/AST.h | 2 +- libsolidity/ASTPrinter.cpp | 2 +- libsolidity/AST_accept.h | 17 ++++++++--------- libsolidity/Compiler.cpp | 3 --- libsolidity/ExpressionCompiler.cpp | 13 +++++++------ 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index c7fd068d9..064457d3b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -451,7 +451,7 @@ public: virtual bool isLValue() const override; - /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. + /// Calls checkTypeRequirments for all state variables. void checkTypeRequirements(); bool isLocalVariable() const { return !!dynamic_cast(getScope()); } bool isExternalFunctionParameter() const; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index aead6abd8..209bb73e6 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -227,7 +227,7 @@ bool ASTPrinter::visit(Return const& _node) bool ASTPrinter::visit(VariableDeclarationStatement const& _node) { - writeLine("VariableDefinition"); + writeLine("VariableDeclarationStatement"); printSourcePart(_node); return goDeeper(); } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 217a565f0..b1577ecd3 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -196,17 +196,24 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const void VariableDeclaration::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } _visitor.endVisit(*this); } void VariableDeclaration::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) + { if (m_typeName) m_typeName->accept(_visitor); - _visitor.endVisit(*this); + if (m_value) + m_value->accept(_visitor); + } } void ModifierDefinition::accept(ASTVisitor& _visitor) @@ -478,22 +485,14 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const void VariableDeclarationStatement::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_variable->getValue()) - m_variable->getValue()->accept(_visitor); - } _visitor.endVisit(*this); } void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) - { m_variable->accept(_visitor); - if (m_variable->getValue()) - m_variable->getValue()->accept(_visitor); - } _visitor.endVisit(*this); } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index bdc29fab9..23014da6c 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -253,10 +253,7 @@ void Compiler::initializeStateVariables(ContractDefinition const& _contract) { for (ASTPointer const& variable: _contract.getStateVariables()) if (variable->getValue()) - { - compileExpression(*(variable->getValue()), (variable->getValue())->getType()); ExpressionCompiler::appendStateVariableInitialization(m_context, *variable); - } } bool Compiler::visit(VariableDeclaration const& _variableDeclaration) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index c2a10ab45..653bf8298 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -58,15 +58,19 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context, void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize) { + compileExpression(_context, *(_varDecl.getValue()), _optimize); + if (_varDecl.getValue()->getType()) + appendTypeConversion(_context, *(_varDecl.getValue())->getType(), *(_varDecl.getValue())->getType()); + ExpressionCompiler compiler(_context, _optimize); compiler.appendStateVariableInitialization(_varDecl); } void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { - m_currentLValue.fromVariableDeclaration(_varDecl); - m_currentLValue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); - m_currentLValue.reset(); + LValue lvalue = LValue(m_context); + lvalue.fromVariableDeclaration(_varDecl); + lvalue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); } bool ExpressionCompiler::visit(Assignment const& _assignment) @@ -1024,9 +1028,7 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) - //{ fromVariableDeclaration(_declaration); - //} else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Identifier type not supported or identifier not found.")); @@ -1034,7 +1036,6 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D void ExpressionCompiler::LValue::fromVariableDeclaration(Declaration const& _declaration) { - //solAssert(m_context->isStateVariable(&_declaration), "Not a state variable."); *m_context << m_context->getStorageLocationOfVariable(_declaration); m_type = LValueType::Storage; m_dataType = _declaration.getType(); From 29290402b433ddd495388d0c3878aeaaf17650b9 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 20:09:46 +0100 Subject: [PATCH 45/59] renamed fromIdentifier to fromStateVariable --- libsolidity/ExpressionCompiler.cpp | 29 +++++++++++++---------------- libsolidity/ExpressionCompiler.h | 8 ++------ 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 653bf8298..e76a8a795 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -69,7 +69,7 @@ void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _con void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { LValue lvalue = LValue(m_context); - lvalue.fromVariableDeclaration(_varDecl); + lvalue.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); lvalue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); } @@ -588,7 +588,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag(); else if (dynamic_cast(declaration)) { - m_currentLValue.fromIdentifier(_identifier, *declaration); + m_currentLValue.fromDeclaration(*declaration, _identifier.getLocation()); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); } else if (dynamic_cast(declaration)) @@ -1018,32 +1018,29 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType m_size = unsigned(m_dataType->getSizeOnStack()); } -void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration) +void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, Location const& _location) { if (m_context->isLocalVariable(&_declaration)) { m_type = LValueType::Stack; - m_dataType = _identifier.getType(); + m_dataType = _declaration.getType(); m_size = m_dataType->getSizeOnStack(); m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration); } else if (m_context->isStateVariable(&_declaration)) - fromVariableDeclaration(_declaration); + { + *m_context << m_context->getStorageLocationOfVariable(_declaration); + m_type = LValueType::Storage; + m_dataType = _declaration.getType(); + solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), + "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); + m_size = unsigned(m_dataType->getStorageSize()); + } else - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Identifier type not supported or identifier not found.")); } -void ExpressionCompiler::LValue::fromVariableDeclaration(Declaration const& _declaration) -{ - *m_context << m_context->getStorageLocationOfVariable(_declaration); - m_type = LValueType::Storage; - m_dataType = _declaration.getType(); - solAssert(m_dataType->getStorageSize() <= numeric_limits::max(), - "The storage size of " + m_dataType->toString() + " should fit in an unsigned"); - m_size = unsigned(m_dataType->getStorageSize()); -} - void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const { switch (m_type) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index a29abc7f1..889c58b19 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -132,12 +132,8 @@ private: std::shared_ptr const& _dataType, unsigned _baseStackOffset = 0); /// Set type according to the declaration and retrieve the reference. - /// @a _identifier is the current identifier - void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); - - /// Set type according to the declaration and retrieve the reference. - /// @a _declaration is the variable declaration - void fromVariableDeclaration(const Declaration &_declaration); + /// @a _location is the current location + void fromDeclaration(Declaration const& _declaration, Location const& _location); void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } From 744ea7ac72b3f2d540f575141d779b5e83d6bed9 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 20 Feb 2015 23:04:32 +0100 Subject: [PATCH 46/59] renamed local vaiable in fromDeclaration added missing endvisit --- libsolidity/AST_accept.h | 1 + libsolidity/ExpressionCompiler.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index b1577ecd3..5bd6993db 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -214,6 +214,7 @@ void VariableDeclaration::accept(ASTConstVisitor& _visitor) const if (m_value) m_value->accept(_visitor); } + _visitor.endVisit(*this); } void ModifierDefinition::accept(ASTVisitor& _visitor) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index e76a8a795..461dfef14 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -68,9 +68,9 @@ void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _con void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl) { - LValue lvalue = LValue(m_context); - lvalue.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); - lvalue.storeValue(*_varDecl.getType(), _varDecl.getLocation()); + LValue var = LValue(m_context); + var.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation()); + var.storeValue(*_varDecl.getType(), _varDecl.getLocation()); } bool ExpressionCompiler::visit(Assignment const& _assignment) From 1fce862e1bfda41055d2ce9e0cd6d2ece3e58fa9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 21 Feb 2015 00:12:20 +0100 Subject: [PATCH 47/59] Improvement to AZ - confirmation disabler. Fix network crash. --- alethzero/Main.ui | 12 ++++++++++++ alethzero/MainWin.cpp | 9 ++++++++- alethzero/MainWin.h | 1 + alethzero/OurWebThreeStubServer.cpp | 6 ++++++ eth/main.cpp | 4 +++- libjsqrc/ethereumjs/dist/ethereum.js | 2 +- libjsqrc/ethereumjs/dist/ethereum.js.map | 2 +- libjsqrc/ethereumjs/dist/ethereum.min.js | 2 +- libjsqrc/ethereumjs/lib/httpsync.js | 2 +- libp2p/Host.cpp | 3 +++ mix/qml/js/ProjectModel.js | 2 +- standard.js | 1 + 12 files changed, 39 insertions(+), 7 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b7c4f6c96..9025aa846 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -163,6 +163,7 @@ &Special + @@ -1652,6 +1653,17 @@ font-size: 14pt New &Transaction... + + + true + + + true + + + &NatSpec Enabled + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 00fb29e2d..f842937ca 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -201,6 +201,11 @@ Main::~Main() g_logPost = simpleDebugOut; } +bool Main::confirm() const +{ + return ui->natSpec->isChecked(); +} + void Main::on_newIdentity_triggered() { KeyPair kp = KeyPair::create(); @@ -651,6 +656,7 @@ void Main::writeSettings() s.setValue("localNetworking", ui->localNetworking->isChecked()); s.setValue("forceMining", ui->forceMining->isChecked()); s.setValue("paranoia", ui->paranoia->isChecked()); + s.setValue("natSpec", ui->natSpec->isChecked()); s.setValue("showAll", ui->showAll->isChecked()); s.setValue("showAllAccounts", ui->showAllAccounts->isChecked()); s.setValue("clientName", ui->clientName->text()); @@ -662,7 +668,7 @@ void Main::writeSettings() s.setValue("jitvm", ui->jitvm->isChecked()); bytes d = m_webThree->saveNetwork(); - if (d.size()) + if (!d.empty()) m_networkConfig = QByteArray((char*)d.data(), (int)d.size()); s.setValue("peers", m_networkConfig); s.setValue("nameReg", ui->nameReg->text()); @@ -720,6 +726,7 @@ void Main::readSettings(bool _skipGeometry) ui->forceMining->setChecked(s.value("forceMining", false).toBool()); on_forceMining_triggered(); ui->paranoia->setChecked(s.value("paranoia", false).toBool()); + ui->natSpec->setChecked(s.value("natSpec", true).toBool()); ui->showAll->setChecked(s.value("showAll", false).toBool()); ui->showAllAccounts->setChecked(s.value("showAllAccounts", false).toBool()); ui->clientName->setText(s.value("clientName", "").toString()); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 6c4a97301..52b98d293 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -72,6 +72,7 @@ public: dev::eth::Client* ethereum() const { return m_webThree->ethereum(); } std::shared_ptr whisper() const { return m_webThree->whisper(); } + bool confirm() const; NatSpecFace* natSpec() { return &m_natSpecDB; } QVariant evalRaw(QString const& _js); diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 5b5ce420a..78b192515 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -46,6 +46,12 @@ string OurWebThreeStubServer::shh_newIdentity() bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const { + if (!m_main->confirm()) + { + cnote << "Skipping confirmation step for: " << _title << "\n" << _text; + return true; + } + int button; QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); return button == QMessageBox::Ok; diff --git a/eth/main.cpp b/eth/main.cpp index fbf47a69c..5051580a5 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -898,7 +898,9 @@ int main(int argc, char** argv) while (!g_exit) this_thread::sleep_for(chrono::milliseconds(1000)); - writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", web3.saveNetwork()); + auto netData = web3.saveNetwork(); + if (!netData.empty()) + writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData); return 0; } diff --git a/libjsqrc/ethereumjs/dist/ethereum.js b/libjsqrc/ethereumjs/dist/ethereum.js index 73b6e56ee..1662ddf91 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js +++ b/libjsqrc/ethereumjs/dist/ethereum.js @@ -1052,7 +1052,7 @@ if ("build" !== 'build') {/* var HttpSyncProvider = function (host) { this.handlers = []; - this.host = host || 'http://localhost:8080'; + this.host = host || 'http://127.0.0.1:8080'; }; HttpSyncProvider.prototype.send = function (payload) { diff --git a/libjsqrc/ethereumjs/dist/ethereum.js.map b/libjsqrc/ethereumjs/dist/ethereum.js.map index 5bf0e8f1b..d9f613c6a 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.js.map +++ b/libjsqrc/ethereumjs/dist/ethereum.js.map @@ -35,7 +35,7 @@ "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file event.js\n * @authors:\n * Marek Kotewicz \n * @date 2014\n */\n\nvar abi = require('./abi');\nvar utils = require('./utils');\n\n/// filter inputs array && returns only indexed (or not) inputs\n/// @param inputs array\n/// @param bool if result should be an array of indexed params on not\n/// @returns array of (not?) indexed params\nvar filterInputs = function (inputs, indexed) {\n return inputs.filter(function (current) {\n return current.indexed === indexed;\n });\n};\n\nvar inputWithName = function (inputs, name) {\n var index = utils.findIndex(inputs, function (input) {\n return input.name === name;\n });\n \n if (index === -1) {\n console.error('indexed param with name ' + name + ' not found');\n return undefined;\n }\n return inputs[index];\n};\n\nvar indexedParamsToTopics = function (event, indexed) {\n // sort keys?\n return Object.keys(indexed).map(function (key) {\n var inputs = [inputWithName(filterInputs(event.inputs, true), key)];\n\n var value = indexed[key];\n if (value instanceof Array) {\n return value.map(function (v) {\n return abi.formatInput(inputs, [v]);\n }); \n }\n return abi.formatInput(inputs, [value]);\n });\n};\n\nvar inputParser = function (address, signature, event) {\n \n // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'\n return function (indexed, options) {\n var o = options || {};\n o.address = address;\n o.topic = [];\n o.topic.push(signature);\n if (indexed) {\n o.topic = o.topic.concat(indexedParamsToTopics(event, indexed));\n }\n return o;\n };\n};\n\nvar getArgumentsObject = function (inputs, indexed, notIndexed) {\n var indexedCopy = indexed.slice();\n var notIndexedCopy = notIndexed.slice();\n return inputs.reduce(function (acc, current) {\n var value;\n if (current.indexed)\n value = indexed.splice(0, 1)[0];\n else\n value = notIndexed.splice(0, 1)[0];\n\n acc[current.name] = value;\n return acc;\n }, {}); \n};\n \nvar outputParser = function (event) {\n \n return function (output) {\n var result = {\n event: utils.extractDisplayName(event.name),\n number: output.number,\n args: {}\n };\n\n output.topics = output.topic; // fallback for go-ethereum\n if (!output.topic) {\n return result;\n }\n \n var indexedOutputs = filterInputs(event.inputs, true);\n var indexedData = \"0x\" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join(\"\");\n var indexedRes = abi.formatOutput(indexedOutputs, indexedData);\n\n var notIndexedOutputs = filterInputs(event.inputs, false);\n var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);\n\n result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);\n\n return result;\n };\n};\n\nvar getMatchingEvent = function (events, payload) {\n for (var i = 0; i < events.length; i++) {\n var signature = abi.eventSignatureFromAscii(events[i].name); \n if (signature === payload.topic[0]) {\n return events[i];\n }\n }\n return undefined;\n};\n\n\nmodule.exports = {\n inputParser: inputParser,\n outputParser: outputParser,\n getMatchingEvent: getMatchingEvent\n};\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\n/// Should be called to check if filter implementation is valid\n/// @returns true if it is, otherwise false\nvar implementationIsValid = function (i) {\n return !!i && \n typeof i.newFilter === 'function' && \n typeof i.getMessages === 'function' && \n typeof i.uninstallFilter === 'function' &&\n typeof i.startPolling === 'function' &&\n typeof i.stopPolling === 'function';\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n if (typeof options === 'string') {\n return options;\n } \n\n options = options || {};\n\n if (options.topics) {\n console.warn('\"topics\" is deprecated, is \"topic\" instead');\n }\n\n // evaluate lazy properties\n return {\n to: options.to,\n topic: options.topic,\n earliest: options.earliest,\n latest: options.latest,\n max: options.max,\n skip: options.skip,\n address: options.address\n };\n};\n\n/// Should be used when we want to watch something\n/// it's using inner polling mechanism and is notified about changes\n/// @param options are filter options\n/// @param implementation, an abstract polling implementation\n/// @param formatter (optional), callback function which formats output before 'real' callback \nvar filter = function(options, implementation, formatter) {\n if (!implementationIsValid(implementation)) {\n console.error('filter implemenation is invalid');\n return;\n }\n\n options = getOptions(options);\n var callbacks = [];\n var filterId = implementation.newFilter(options);\n var onMessages = function (messages) {\n messages.forEach(function (message) {\n message = formatter ? formatter(message) : message;\n callbacks.forEach(function (callback) {\n callback(message);\n });\n });\n };\n\n implementation.startPolling(filterId, onMessages, implementation.uninstallFilter);\n\n var changed = function (callback) {\n callbacks.push(callback);\n };\n\n var messages = function () {\n return implementation.getMessages(filterId);\n };\n \n var uninstall = function (callback) {\n implementation.stopPolling(filterId);\n implementation.uninstallFilter(filterId);\n callbacks = [];\n };\n\n return {\n changed: changed,\n arrived: changed,\n happened: changed,\n messages: messages,\n logs: messages,\n uninstall: uninstall\n };\n};\n\nmodule.exports = filter;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file formatters.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nif (\"build\" !== 'build') {/*\n var BigNumber = require('bignumber.js'); // jshint ignore:line\n*/}\n\nvar utils = require('./utils');\nvar c = require('./const');\n\n/// @param string string to be padded\n/// @param number of characters that result string should have\n/// @param sign, by default 0\n/// @returns right aligned string\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/// Formats input value to byte representation of int\n/// If value is negative, return it's two's complement\n/// If the value is floating point, round it down\n/// @returns right-aligned byte representation of int\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n if (value instanceof BigNumber || typeof value === 'number') {\n if (typeof value === 'number')\n value = new BigNumber(value);\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n value = value.round();\n\n if (value.lessThan(0)) \n value = new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(value).plus(1);\n value = value.toString(16);\n }\n else if (value.indexOf('0x') === 0)\n value = value.substr(2);\n else if (typeof value === 'string')\n value = formatInputInt(new BigNumber(value));\n else\n value = (+value).toString(16);\n return padLeft(value, padding);\n};\n\n/// Formats input value to byte representation of string\n/// @returns left-algined byte representation of string\nvar formatInputString = function (value) {\n return utils.fromAscii(value, c.ETH_PADDING).substr(2);\n};\n\n/// Formats input value to byte representation of bool\n/// @returns right-aligned byte representation bool\nvar formatInputBool = function (value) {\n return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n};\n\n/// Formats input value to byte representation of real\n/// Values are multiplied by 2^m and encoded as integers\n/// @returns byte representation of real\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); \n};\n\n\n/// Check if input value is negative\n/// @param value is hex format\n/// @returns true if it is negative, otherwise false\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/// Formats input right-aligned input bytes to int\n/// @returns right-aligned input bytes formatted to int\nvar formatOutputInt = function (value) {\n value = value || \"0\";\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/// Formats big right-aligned input bytes to uint\n/// @returns right-aligned input bytes formatted to uint\nvar formatOutputUInt = function (value) {\n value = value || \"0\";\n return new BigNumber(value, 16);\n};\n\n/// @returns input bytes formatted to real\nvar formatOutputReal = function (value) {\n return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns input bytes formatted to ureal\nvar formatOutputUReal = function (value) {\n return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/// @returns right-aligned input bytes formatted to hex\nvar formatOutputHash = function (value) {\n return \"0x\" + value;\n};\n\n/// @returns right-aligned input bytes formatted to bool\nvar formatOutputBool = function (value) {\n return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/// @returns left-aligned input bytes formatted to ascii string\nvar formatOutputString = function (value) {\n return utils.toAscii(value);\n};\n\n/// @returns right-aligned input bytes formatted to address\nvar formatOutputAddress = function (value) {\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputString: formatInputString,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputHash: formatOutputHash,\n formatOutputBool: formatOutputBool,\n formatOutputString: formatOutputString,\n formatOutputAddress: formatOutputAddress\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://localhost:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n\n var result = request.responseText;\n // check request.status\n if(request.status !== 200)\n return;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\n\n", + "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nif (\"build\" !== 'build') {/*\n var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\n*/}\n\nvar HttpSyncProvider = function (host) {\n this.handlers = [];\n this.host = host || 'http://127.0.0.1:8080';\n};\n\nHttpSyncProvider.prototype.send = function (payload) {\n //var data = formatJsonRpcObject(payload);\n\n var request = new XMLHttpRequest();\n request.open('POST', this.host, false);\n request.send(JSON.stringify(payload));\n\n var result = request.responseText;\n // check request.status\n if(request.status !== 200)\n return;\n return JSON.parse(result);\n};\n\nmodule.exports = HttpSyncProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar messageId = 1;\n\n/// Should be called to valid json create payload object\n/// @param method of jsonrpc call, required\n/// @param params, an array of method params, optional\n/// @returns valid jsonrpc payload object\nvar toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: messageId++\n }; \n};\n\n/// Should be called to check if jsonrpc response is valid\n/// @returns true if response is valid, otherwise false \nvar isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/// Should be called to create batch payload object\n/// @param messages, an array of objects with method (required) and params (optional) fields\nvar toBatchPayload = function (messages) {\n return messages.map(function (message) {\n return toPayload(message.method, message.params);\n }); \n};\n\nmodule.exports = {\n toPayload: toPayload,\n isValidResponse: isValidResponse,\n toBatchPayload: toBatchPayload\n};\n\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qtsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nvar QtSyncProvider = function () {\n};\n\nQtSyncProvider.prototype.send = function (payload) {\n var result = navigator.qt.callMethod(JSON.stringify(payload));\n return JSON.parse(result);\n};\n\nmodule.exports = QtSyncProvider;\n\n", "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file requestmanager.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Gav Wood \n * @date 2014\n */\n\nvar jsonrpc = require('./jsonrpc');\nvar c = require('./const');\n\n/**\n * It's responsible for passing messages to providers\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 1 second\n */\nvar requestManager = function() {\n var polls = [];\n var provider;\n\n var send = function (data) {\n var payload = jsonrpc.toPayload(data.method, data.params);\n \n if (!provider) {\n console.error('provider is not set');\n return null;\n }\n\n var result = provider.send(payload);\n\n if (!jsonrpc.isValidResponse(result)) {\n console.log(result);\n return null;\n }\n \n return result.result;\n };\n\n var setProvider = function (p) {\n provider = p;\n };\n\n var startPolling = function (data, pollId, callback, uninstall) {\n polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});\n };\n\n var stopPolling = function (pollId) {\n for (var i = polls.length; i--;) {\n var poll = polls[i];\n if (poll.id === pollId) {\n polls.splice(i, 1);\n }\n }\n };\n\n var reset = function () {\n polls.forEach(function (poll) {\n poll.uninstall(poll.id); \n });\n polls = [];\n };\n\n var poll = function () {\n polls.forEach(function (data) {\n var result = send(data.data);\n if (!(result instanceof Array) || result.length === 0) {\n return;\n }\n data.callback(result);\n });\n setTimeout(poll, c.ETH_POLLING_TIMEOUT);\n };\n \n poll();\n\n return {\n send: send,\n setProvider: setProvider,\n startPolling: startPolling,\n stopPolling: stopPolling,\n reset: reset\n };\n};\n\nmodule.exports = requestManager;\n\n", diff --git a/libjsqrc/ethereumjs/dist/ethereum.min.js b/libjsqrc/ethereumjs/dist/ethereum.min.js index cbf98f363..92748f48a 100644 --- a/libjsqrc/ethereumjs/dist/ethereum.min.js +++ b/libjsqrc/ethereumjs/dist/ethereum.min.js @@ -1 +1 @@ -require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(n.topics=n.topic,!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file +require=function t(n,e,r){function o(i,u){if(!e[i]){if(!n[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=e[i]={exports:{}};n[i][0].call(c.exports,function(t){var e=n[i][1][t];return o(e?e:t)},c,c.exports,t,n,e,r)}return e[i].exports}for(var a="function"==typeof require&&require,i=0;iv;v++)g.push(h(n.slice(0,r))),n=n.slice(r);e.push(g)}else o.prefixedType("string")(t[s].type)?(c=c.slice(r),e.push(h(n.slice(0,r))),n=n.slice(r)):(e.push(h(n.slice(0,r))),n=n.slice(r))}),e},d=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(){var n=Array.prototype.slice.call(arguments);return l(t.inputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},g=function(t){var n={};return t.forEach(function(t){var e=r.extractDisplayName(t.name),o=r.extractTypeName(t.name),a=function(n){return h(t.outputs,n)};void 0===n[e]&&(n[e]=a),n[e][o]=a}),n},v=function(t){return e.sha3(e.fromAscii(t)).slice(0,2+2*a.ETH_SIGNATURE_LENGTH)},y=function(t){return e.sha3(e.fromAscii(t))};n.exports={inputParser:d,outputParser:g,formatInput:l,formatOutput:h,signatureFromAscii:v,eventSignatureFromAscii:y}},{"./const":2,"./formatters":8,"./types":14,"./utils":15,"./web3":17}],2:[function(t,n){var e=["wei","Kwei","Mwei","Gwei","szabo","finney","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];n.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:e,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:BigNumber.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3}},{}],3:[function(t,n){var e=t("./web3"),r=t("./abi"),o=t("./utils"),a=t("./event"),i=(t("./filter"),function(t){e._currentContractAbi=t.abi,e._currentContractAddress=t.address,e._currentContractMethodName=t.method,e._currentContractMethodParams=t.params}),u=function(t){t.call=function(n){return t._isTransact=!1,t._options=n,t},t.transact=function(n){return t._isTransact=!0,t._options=n,t},t._options={},["gas","gasPrice","value","from"].forEach(function(n){t[n]=function(e){return t._options[n]=e,t}})},f=function(t,n,a){var u=r.inputParser(n),f=r.outputParser(n);o.filterFunctions(n).forEach(function(s){var c=o.extractDisplayName(s.name),l=o.extractTypeName(s.name),p=function(){var o=Array.prototype.slice.call(arguments),p=r.signatureFromAscii(s.name),m=u[c][l].apply(null,o),h=t._options||{};h.to=a,h.data=p+m;var d=t._isTransact===!0||t._isTransact!==!1&&!s.constant,g=h.collapse!==!1;if(t._options={},t._isTransact=null,d)return i({abi:n,address:a,method:s.name,params:o}),void e.eth.transact(h);var v=e.eth.call(h),y=f[c][l](v);return g&&(1===y.length?y=y[0]:0===y.length&&(y=null)),y};void 0===t[c]&&(t[c]=p),t[c][l]=p})},s=function(t,n,e){t.address=e,t._onWatchEventResult=function(t){var e=event.getMatchingEvent(o.filterEvents(n)),r=a.outputParser(e);return r(t)},Object.defineProperty(t,"topic",{get:function(){return o.filterEvents(n).map(function(t){return r.eventSignatureFromAscii(t.name)})}})},c=function(t,n,i){o.filterEvents(n).forEach(function(n){var u=function(){var t=Array.prototype.slice.call(arguments),o=r.eventSignatureFromAscii(n.name),u=a.inputParser(i,o,n),f=u.apply(null,t),s=function(t){var e=a.outputParser(n);return e(t)};return e.eth.watch(f,void 0,void 0,s)};u._isEvent=!0;var f=o.extractDisplayName(n.name),s=o.extractTypeName(n.name);void 0===t[f]&&(t[f]=u),t[f][s]=u})},l=function(t,n){n.forEach(function(t){if(-1===t.name.indexOf("(")){var n=t.name,e=t.inputs.map(function(t){return t.type}).join();t.name=n+"("+e+")"}});var e={};return u(e),f(e,n,t),s(e,n,t),c(e,n,t),e};n.exports=l},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(t,n){var e=function(){return[{name:"put",call:"db_put"},{name:"get",call:"db_get"},{name:"putString",call:"db_putString"},{name:"getString",call:"db_getString"}]};n.exports={methods:e}},{}],5:[function(t,n){var e=function(){var t=function(t){return"string"==typeof t[0]?"eth_blockByHash":"eth_blockByNumber"},n=function(t){return"string"==typeof t[0]?"eth_transactionByHash":"eth_transactionByNumber"},e=function(t){return"string"==typeof t[0]?"eth_uncleByHash":"eth_uncleByNumber"},r=function(t){return"string"==typeof t[0]?"eth_transactionCountByHash":"eth_transactionCountByNumber"},o=function(t){return"string"==typeof t[0]?"eth_uncleCountByHash":"eth_uncleCountByNumber"};return[{name:"balanceAt",call:"eth_balanceAt"},{name:"stateAt",call:"eth_stateAt"},{name:"storageAt",call:"eth_storageAt"},{name:"countAt",call:"eth_countAt"},{name:"codeAt",call:"eth_codeAt"},{name:"transact",call:"eth_transact"},{name:"call",call:"eth_call"},{name:"block",call:t},{name:"transaction",call:n},{name:"uncle",call:e},{name:"compilers",call:"eth_compilers"},{name:"flush",call:"eth_flush"},{name:"lll",call:"eth_lll"},{name:"solidity",call:"eth_solidity"},{name:"serpent",call:"eth_serpent"},{name:"logs",call:"eth_logs"},{name:"transactionCount",call:r},{name:"uncleCount",call:o}]},r=function(){return[{name:"coinbase",getter:"eth_coinbase",setter:"eth_setCoinbase"},{name:"listening",getter:"eth_listening",setter:"eth_setListening"},{name:"mining",getter:"eth_mining",setter:"eth_setMining"},{name:"gasPrice",getter:"eth_gasPrice"},{name:"accounts",getter:"eth_accounts"},{name:"peerCount",getter:"eth_peerCount"},{name:"defaultBlock",getter:"eth_defaultBlock",setter:"eth_setDefaultBlock"},{name:"number",getter:"eth_number"}]};n.exports={methods:e,properties:r}},{}],6:[function(t,n){var e=t("./abi"),r=t("./utils"),o=function(t,n){return t.filter(function(t){return t.indexed===n})},a=function(t,n){var e=r.findIndex(t,function(t){return t.name===n});return-1===e?void console.error("indexed param with name "+n+" not found"):t[e]},i=function(t,n){return Object.keys(n).map(function(r){var i=[a(o(t.inputs,!0),r)],u=n[r];return u instanceof Array?u.map(function(t){return e.formatInput(i,[t])}):e.formatInput(i,[u])})},u=function(t,n,e){return function(r,o){var a=o||{};return a.address=t,a.topic=[],a.topic.push(n),r&&(a.topic=a.topic.concat(i(e,r))),a}},f=function(t,n,e){n.slice(),e.slice();return t.reduce(function(t,r){var o;return o=r.indexed?n.splice(0,1)[0]:e.splice(0,1)[0],t[r.name]=o,t},{})},s=function(t){return function(n){var a={event:r.extractDisplayName(t.name),number:n.number,args:{}};if(n.topics=n.topic,!n.topic)return a;var i=o(t.inputs,!0),u="0x"+n.topic.slice(1,n.topic.length).map(function(t){return t.slice(2)}).join(""),s=e.formatOutput(i,u),c=o(t.inputs,!1),l=e.formatOutput(c,n.data);return a.args=f(t.inputs,s,l),a}},c=function(t,n){for(var r=0;re;e+=2){var o=parseInt(t.substr(e,2),16);if(0===o)break;n+=String.fromCharCode(o)}return n},a=function(t){for(var n="",e=0;e3e3&&r2?t.substring(2):"0",new BigNumber(t,16).toString(10)},fromDecimal:function(t){return"0x"+new BigNumber(t).toString(16)},toEth:u.toEth,eth:{contractFromAbi:function(t){return function(n){n=n||"0xc6d9d2cd449a754c494264e1809c50e34d64562b";var e=g.eth.contract(n,t);return e.address=n,e}},watch:function(t,n,e,r){return t._isEvent?t(n,e):i(t,h,r)}},db:{},shh:{watch:function(t){return i(t,d)}},setProvider:function(t){g.manager.setProvider(t)},reset:function(){g.manager.reset()}};c(g,s()),c(g.eth,e.methods()),l(g.eth,e.properties()),c(g.db,r.methods()),c(g.shh,o.methods()),c(h,a.eth()),c(d,a.shh()),n.exports=g},{"./db":4,"./eth":5,"./filter":7,"./requestmanager":12,"./shh":13,"./utils":15,"./watches":16}],web3:[function(t,n){var e=t("./lib/web3");e.providers.HttpSyncProvider=t("./lib/httpsync"),e.providers.QtSyncProvider=t("./lib/qtsync"),e.eth.contract=t("./lib/contract"),e.abi=t("./lib/abi"),n.exports=e},{"./lib/abi":1,"./lib/contract":3,"./lib/httpsync":9,"./lib/qtsync":11,"./lib/web3":17}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/lib/httpsync.js b/libjsqrc/ethereumjs/lib/httpsync.js index 90f3ee454..b90fa746e 100644 --- a/libjsqrc/ethereumjs/lib/httpsync.js +++ b/libjsqrc/ethereumjs/lib/httpsync.js @@ -27,7 +27,7 @@ if (process.env.NODE_ENV !== 'build') { var HttpSyncProvider = function (host) { this.handlers = []; - this.host = host || 'http://localhost:8080'; + this.host = host || 'http://127.0.0.1:8080'; }; HttpSyncProvider.prototype.send = function (payload) { diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f117df37a..fd5d2c4d8 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -630,6 +630,9 @@ void Host::disconnectLatePeers() bytes Host::saveNetwork() const { + if (!m_nodeTable) + return bytes(); + std::list peers; { RecursiveGuard l(x_sessions); diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 5a7bf4332..9ca9bae39 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -282,7 +282,7 @@ function deployProject(force) { var date = new Date(); var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); - var jsonRpcUrl = "http://localhost:8080"; + var jsonRpcUrl = "http://127.0.0.1:8080"; console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); deploymentStarted(); diff --git a/standard.js b/standard.js index 0f9cf6fa4..f51828cbe 100644 --- a/standard.js +++ b/standard.js @@ -10,6 +10,7 @@ var addrNameReg = initService("namereg"); var addrGavsino = initServiceVal("gavmble", "1000000000000000000"); var addrCoinReg = initService("coins"); var addrGavCoin = initService("coin"); + var addrRegistrar = initService("registrar"); var abiNameReg = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getName","outputs":[{"name":"o_name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":true,"inputs":[{"name":"_name","type":"string32"}],"name":"getAddress","outputs":[{"name":"o_owner","type":"address"}]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]}]; From 1f0791b4bcb100373145bb6e3d85208c00d19721 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 21 Feb 2015 00:48:31 +0100 Subject: [PATCH 48/59] Validation queuing. --- alethzero/MainWin.cpp | 1 + alethzero/OurWebThreeStubServer.cpp | 59 +++++++++++++++++------ alethzero/OurWebThreeStubServer.h | 20 ++++++-- libweb3jsonrpc/WebThreeStubServerBase.cpp | 34 ++++++------- libweb3jsonrpc/WebThreeStubServerBase.h | 2 +- 5 files changed, 75 insertions(+), 41 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index f842937ca..c40e8f6a0 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1167,6 +1167,7 @@ void Main::timerEvent(QTimerEvent*) interval = 0; refreshNetwork(); refreshWhispers(); + poll(); } else interval += 100; diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 78b192515..da588ba3e 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -33,9 +33,11 @@ using namespace dev; using namespace dev::eth; OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, - vector const& _accounts, Main* main): - WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main) -{} + vector const& _accounts, Main* _main): + WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(_main) +{ + connect(_main, SIGNAL(poll()), this, SLOT(doValidations())); +} string OurWebThreeStubServer::shh_newIdentity() { @@ -44,7 +46,7 @@ string OurWebThreeStubServer::shh_newIdentity() return toJS(kp.pub()); } -bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const +bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) { if (!m_main->confirm()) { @@ -52,23 +54,30 @@ bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string return true; } - int button; - QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); - return button == QMessageBox::Ok; + QMessageBox userInput; + userInput.setText(QString::fromStdString(_title)); + userInput.setInformativeText(QString::fromStdString(_text)); + userInput.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + userInput.button(QMessageBox::Ok)->setText("Allow"); + userInput.button(QMessageBox::Cancel)->setText("Reject"); + userInput.setDefaultButton(QMessageBox::Cancel); + return userInput.exec() == QMessageBox::Ok; + //QMetaObject::invokeMethod(m_main, "authenticate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, button), Q_ARG(QString, QString::fromStdString(_title)), Q_ARG(QString, QString::fromStdString(_text))); + //return button == QMessageBox::Ok; } -bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) const +bool OurWebThreeStubServer::showCreationNotice(TransactionSkeleton const& _t, bool _toProxy) { - return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); + return showAuthenticationPopup("Contract Creation Transaction", string("ÐApp is attemping to create a contract; ") + (_toProxy ? "(this transaction is not executed directly, but forwarded to another ÐApp) " : "") + "to be endowed with " + formatBalance(_t.value) + ", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) const +bool OurWebThreeStubServer::showSendNotice(TransactionSkeleton const& _t, bool _toProxy) { return showAuthenticationPopup("Fund Transfer Transaction", "ÐApp is attempting to send " + formatBalance(_t.value) + " to a recipient " + m_main->pretty(_t.to).toStdString() + (_toProxy ? " (this transaction is not executed directly, but forwarded to another ÐApp)" : "") + -", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); +", with additional network fees of up to " + formatBalance(_t.gas * _t.gasPrice) + ".\n\nMaximum total cost is " + formatBalance(_t.value + _t.gas * _t.gasPrice) + "."); } -bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) const +bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, bool _toProxy) { return showAuthenticationPopup("DANGEROUS! Unknown Contract Transaction!", "ÐApp is attempting to call into an unknown contract at address " + @@ -84,11 +93,29 @@ bool OurWebThreeStubServer::showUnknownCallNotice(TransactionSkeleton const& _t, "REJECT UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!"); } -bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) +void OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _toProxy) +{ + Guard l(x_queued); + m_queued.push(make_pair(_t, _toProxy)); +} + +void OurWebThreeStubServer::doValidations() +{ + Guard l(x_queued); + while (!m_queued.empty()) + { + auto q = m_queued.front(); + m_queued.pop(); + if (validateTransaction(q.first, q.second)) + WebThreeStubServerBase::authenticate(q.first, q.second); + } +} + +bool OurWebThreeStubServer::validateTransaction(TransactionSkeleton const& _t, bool _toProxy) { if (_t.creation) { - // recipient has no code - nothing special about this transaction, show basic value transfer info + // show notice concerning the creation code. TODO: this needs entering into natspec. return showCreationNotice(_t, _toProxy); } @@ -116,8 +143,8 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t, bool _to (_t.value > 0 ? "In addition, ÐApp is attempting to send " + formatBalance(_t.value) + " to said recipient, with additional network fees of up to " + - formatBalance(_t.gas * _t.gasPrice) + " = " + - formatBalance(_t.value + _t.gas * _t.gasPrice) + "." + formatBalance(_t.gas * _t.gasPrice) + " = " + + formatBalance(_t.value + _t.gas * _t.gasPrice) + "." : "Additional network fees are at most" + formatBalance(_t.gas * _t.gasPrice) + ".") diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index 1ab5f813c..95cf70438 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -19,7 +19,9 @@ * @date 2014 */ +#include #include +#include #include #include #include @@ -35,16 +37,24 @@ public: std::vector const& _accounts, Main* main); virtual std::string shh_newIdentity() override; - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); signals: void onNewId(QString _s); +public slots: + void doValidations(); + private: - bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const; - bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; - bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; - bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy) const; + bool showAuthenticationPopup(std::string const& _title, std::string const& _text); + bool showCreationNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + bool showSendNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + bool showUnknownCallNotice(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + + bool validateTransaction(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + + std::queue> m_queued; + dev::Mutex x_queued; dev::WebThreeDirect* m_web3; Main* m_main; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 3fa22a928..6ab701899 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -701,35 +701,31 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) { std::string ret; TransactionSkeleton t = toTransaction(_json); + if (t.creation) + ret = right160(sha3(rlpList(t.from, client()->countAt(t.from))));; if (!t.from) t.from = m_accounts->getDefaultTransactAccount(); if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) t.gas = min(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); - if (!m_accounts->isRealAccount(t.from)) - { - if (m_accounts->isProxyAccount(t.from)) - if (authenticate(t, true)) - m_accounts->queueTransaction(t); - return ret; - } - if (authenticate(t, false)) - { - if (t.to) - // TODO: from qethereum, insert validification hook here. - client()->transact(m_accounts->secretKey(t.from), t.value, t.to, t.data, t.gas, t.gasPrice); - else - ret = toJS(client()->transact(m_accounts->secretKey(t.from), t.value, t.data, t.gas, t.gasPrice)); - client()->flushTransactions(); - } + + if (m_accounts->isRealAccount(t.from)) + authenticate(t, false); + else if (m_accounts->isProxyAccount(t.from)) + authenticate(t, true); + return ret; } -bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool) +void WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t, bool _toProxy) { - cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; - return true; + if (_toProxy) + m_accounts->queueTransaction(_t); + else if (_t.to) + client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.to, _t.data, _t.gas, _t.gasPrice); + else + client()->transact(m_accounts->secretKey(_t.from), _t.value, _t.data, _t.gas, _t.gasPrice); } Json::Value WebThreeStubServerBase::eth_transactionByHash(std::string const& _hash, int _i) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ed2f09d99..9535c33a0 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -136,7 +136,7 @@ public: std::map const& ids() const { return m_ids; } protected: - virtual bool authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); + virtual void authenticate(dev::eth::TransactionSkeleton const& _t, bool _toProxy); protected: virtual dev::eth::Interface* client() = 0; From a0f0812fcbc56b69c4298bc4818070b8b9e63d81 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 21 Feb 2015 00:48:43 -0500 Subject: [PATCH 49/59] fix #1055 --- libp2p/Host.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f117df37a..f4882b47d 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -665,17 +665,20 @@ bytes Host::saveNetwork() const } } - auto state = m_nodeTable->snapshot(); - state.sort(); - for (auto const& s: state) + if (!!m_nodeTable) { - network.appendList(3); - if (s.endpoint.tcp.address().is_v4()) - network << s.endpoint.tcp.address().to_v4().to_bytes(); - else - network << s.endpoint.tcp.address().to_v6().to_bytes(); - network << s.endpoint.tcp.port() << s.id; - count++; + auto state = m_nodeTable->snapshot(); + state.sort(); + for (auto const& s: state) + { + network.appendList(3); + if (s.endpoint.tcp.address().is_v4()) + network << s.endpoint.tcp.address().to_v4().to_bytes(); + else + network << s.endpoint.tcp.address().to_v6().to_bytes(); + network << s.endpoint.tcp.port() << s.id; + count++; + } } RLPStream ret(3); From f971a7147da7159b3b83d237e3bb16d54d0e2e22 Mon Sep 17 00:00:00 2001 From: caktux Date: Sat, 21 Feb 2015 00:57:29 -0500 Subject: [PATCH 50/59] fix dependency server for windows --- extdep/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extdep/CMakeLists.txt b/extdep/CMakeLists.txt index 99f76800c..e9711754f 100644 --- a/extdep/CMakeLists.txt +++ b/extdep/CMakeLists.txt @@ -7,7 +7,7 @@ include(eth_download.cmake) # all dependencies will be installed into this directory, separated by platform string(TOLOWER ${CMAKE_SYSTEM_NAME} _system_name) set(ETH_DEPENDENCY_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/install/${_system_name}") -set(ETH_DEPENDENCY_SERVER "http://build.ethdev.com/builds/${_system_name}-precompiled") +set(ETH_DEPENDENCY_SERVER "https://build.ethdev.com/builds/${_system_name}-precompiled") file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/lib) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/include) file(MAKE_DIRECTORY ${ETH_DEPENDENCY_INSTALL_DIR}/bin) From 900f7053246d32efdddd8595645ac4325e4de68d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 20 Feb 2015 18:15:34 +0100 Subject: [PATCH 51/59] Adding Libraries as source units --- libsolidity/CompilerStack.cpp | 8 +++++--- libsolidity/CompilerStack.h | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index ca9c75bcd..a5cd91986 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -58,14 +58,15 @@ CompilerStack::CompilerStack(bool _addStandardSources): m_addStandardSources(_addStandardSources), m_parseSuccessful(false) { if (m_addStandardSources) - addSources(StandardSources); + addSources(StandardSources, true); // add them as libraries } -bool CompilerStack::addSource(string const& _name, string const& _content) +bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) { bool existed = m_sources.count(_name) != 0; reset(true); m_sources[_name].scanner = make_shared(CharStream(expanded(_content)), _name); + m_sources[_name].isLibrary = _isLibrary; return existed; } @@ -328,7 +329,8 @@ void CompilerStack::resolveImports() }; for (auto const& sourcePair: m_sources) - toposort(&sourcePair.second); + if (!sourcePair.second.isLibrary) + toposort(&sourcePair.second); swap(m_sourceOrder, sourceOrder); } diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index cb4770cd3..c9642745a 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -64,8 +64,8 @@ public: /// Adds a source object (e.g. file) to the parser. After this, parse has to be called again. /// @returns true if a source object by the name already existed and was replaced. - void addSources(std::map const& _nameContents) { for (auto const& i: _nameContents) addSource(i.first, i.second); } - bool addSource(std::string const& _name, std::string const& _content); + void addSources(std::map const& _nameContents, bool _isLibrary = false) { for (auto const& i: _nameContents) addSource(i.first, i.second, _isLibrary); } + bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false); void setSource(std::string const& _sourceCode); /// Parses all source units that were added void parse(); @@ -125,7 +125,8 @@ private: std::shared_ptr scanner; std::shared_ptr ast; std::string interface; - void reset() { scanner.reset(); ast.reset(); interface.clear(); } + bool isLibrary; + void reset() { scanner.reset(); ast.reset(); interface.clear(); isLibrary = false;} }; struct Contract From ca8f786d563e2fc8060ccabdb75aa714f30bd5bc Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 21 Feb 2015 16:25:28 +0100 Subject: [PATCH 52/59] Removing temporary contracts - They are now added as importable libraries --- libsolidity/CompilerStack.cpp | 55 ++--------------------------------- libsolidity/CompilerStack.h | 4 --- 2 files changed, 2 insertions(+), 57 deletions(-) diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp index a5cd91986..69dbced00 100644 --- a/libsolidity/CompilerStack.cpp +++ b/libsolidity/CompilerStack.cpp @@ -65,7 +65,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool { bool existed = m_sources.count(_name) != 0; reset(true); - m_sources[_name].scanner = make_shared(CharStream(expanded(_content)), _name); + m_sources[_name].scanner = make_shared(CharStream(_content), _name); m_sources[_name].isLibrary = _isLibrary; return existed; } @@ -73,7 +73,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool void CompilerStack::setSource(string const& _sourceCode) { reset(); - addSource("", expanded(_sourceCode)); + addSource("", _sourceCode); } void CompilerStack::parse() @@ -127,57 +127,6 @@ vector CompilerStack::getContractNames() const return contractNames; } -////// BEGIN: TEMPORARY ONLY -/// -/// NOTE: THIS INVALIDATES SOURCE POINTERS AND CAN CRASH THE COMPILER -/// -/// remove once import works properly and we have genesis contracts - -string CompilerStack::expanded(string const& _sourceCode) -{ - const map c_standardSources = map{ - { "Config", "contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}" }, - { "Coin", "contract Coin{function isApprovedFor(address _target,address _proxy)constant returns(bool _r){}function isApproved(address _proxy)constant returns(bool _r){}function sendCoinFrom(address _from,uint256 _val,address _to){}function coinBalanceOf(address _a)constant returns(uint256 _r){}function sendCoin(uint256 _val,address _to){}function coinBalance()constant returns(uint256 _r){}function approve(address _a){}}"}, - { "CoinReg", "contract CoinReg{function count()constant returns(uint256 r){}function info(uint256 i)constant returns(address addr,string3 name,uint256 denom){}function register(string3 name,uint256 denom){}function unregister(){}}" }, - { "coin", "#require CoinReg\ncontract coin {function coin(string3 name, uint denom) {CoinReg(Config().lookup(3)).register(name, denom);}}" }, - { "service", "#require Config\ncontract service{function service(uint _n){Config().register(_n, this);}}" }, - { "owned", "contract owned{function owned(){owner = msg.sender;}modifier onlyowner(){if(msg.sender==owner)_}address owner;}" }, - { "mortal", "#require owned\ncontract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}" }, - { "NameReg", "contract NameReg{function register(string32 name){}function addressOf(string32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(string32 name){}}" }, - { "named", "#require Config NameReg\ncontract named {function named(string32 name) {NameReg(Config().lookup(1)).register(name);}}" }, - { "std", "#require owned mortal Config NameReg named" }, - }; - - string sub; - set got; - function localExpanded; - localExpanded = [&](string const& s) -> string - { - string ret = s; - for (size_t p = 0; p != string::npos;) - if ((p = ret.find("#require ")) != string::npos) - { - string n = ret.substr(p + 9, ret.find_first_of('\n', p + 9) - p - 9); - ret.replace(p, n.size() + 9, ""); - vector rs; - boost::split(rs, n, boost::is_any_of(" \t,"), boost::token_compress_on); - for (auto const& r: rs) - if (!got.count(r)) - { - if (c_standardSources.count(r)) - sub.append("\n" + localExpanded(c_standardSources.at(r)) + "\n"); - got.insert(r); - } - } - // TODO: remove once we have genesis contracts. - else if ((p = ret.find("Config()")) != string::npos) - ret.replace(p, 8, "Config(0xc6d9d2cd449a754c494264e1809c50e34d64562b)"); - return ret; - }; - return sub + localExpanded(_sourceCode); -} - -////// END: TEMPORARY ONLY void CompilerStack::compile(bool _optimize) { diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index c9642745a..87946a6b9 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -144,10 +144,6 @@ private: Contract(); }; - /// Expand source code with preprocessor-like includes. - /// @todo Replace with better framework. - std::string expanded(std::string const& _sourceCode); - void reset(bool _keepSources = false); void resolveImports(); From 11566fd3a03e39c3593d48c9f191de4cd95a5b43 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 21 Feb 2015 18:55:55 +0100 Subject: [PATCH 53/59] Adding default value to isLibrary --- libsolidity/CompilerStack.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 87946a6b9..8f77ef68a 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -125,7 +125,7 @@ private: std::shared_ptr scanner; std::shared_ptr ast; std::string interface; - bool isLibrary; + bool isLibrary = false; void reset() { scanner.reset(); ast.reset(); interface.clear(); isLibrary = false;} }; From b6773a30841c307f0afb2f2abbba28f2f76728bf Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 22 Feb 2015 02:00:19 +0100 Subject: [PATCH 54/59] fixed microhttpd deployment --- alethzero/CMakeLists.txt | 2 +- cmake/EthExecutableHelper.cmake | 11 ++++++++++- cmake/FindMHD.cmake | 10 ++++++++-- third/CMakeLists.txt | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 008721518..9cb1a0ff7 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -58,5 +58,5 @@ if (NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")) endif() # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE}) +eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE}) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index c6e0210de..0c2f72946 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -56,7 +56,7 @@ macro(eth_install_executable EXECUTABLE) set (extra_macro_args ${ARGN}) set (options) set (one_value_args QMLDIR) - set (multi_value_args) + set (multi_value_args DLLS) cmake_parse_arguments (ETH_INSTALL_EXECUTABLE "${options}" "${one_value_args}" "${multi_value_args}" "${extra_macro_args}") if (ETH_INSTALL_EXECUTABLE_QMLDIR) @@ -99,6 +99,15 @@ macro(eth_install_executable EXECUTABLE) COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM ) + + #copy additional dlls + foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS}) + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS -E copy ${dll} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" + ) + endforeach(dll) + install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin COMPONENT ${EXECUTABLE} diff --git a/cmake/FindMHD.cmake b/cmake/FindMHD.cmake index 84875bc47..5cb8a98d6 100755 --- a/cmake/FindMHD.cmake +++ b/cmake/FindMHD.cmake @@ -29,13 +29,19 @@ set(MHD_LIBRARIES ${MHD_LIBRARY}) # boost is using the same "hack" as us with "optimized" and "debug" # official MHD project actually uses _d suffix if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + #TODO: place dlls into CMAKE_CFG_INTDIR subfolders + string(REPLACE ".lib" ".dll" MHD_DLL_RELEASE ${MHD_LIBRARY}) + string(REPLACE "/lib/" "/bin/" MHD_DLL_RELEASE ${MHD_DLL_RELEASE}) + find_library( MHD_LIBRARY_DEBUG NAMES microhttpd_d microhttpd-10_d libmicrohttpd_d libmicrohttpd-dll_d DOC "mhd debug library" ) - - set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) + # always use release for now + #string(REPLACE ".lib" ".dll" MHD_DLL_DEBUG ${MHD_LIBRARY_DEBUG}) + #set(MHD_LIBRARIES optimized ${MHD_LIBRARIES} debug ${MHD_LIBRARY_DEBUG}) endif() diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index bde47988b..989677626 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -51,5 +51,5 @@ target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} jsqrc) # eth_install_executable is defined in cmake/EthExecutableHelper.cmake -eth_install_executable(${EXECUTABLE}) +eth_install_executable(${EXECUTABLE} DLLS ${MHD_DLL_RELEASE}) From 7db97414cab65425e441410906a7f11f2ff4d34d Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 22 Feb 2015 10:11:21 +0100 Subject: [PATCH 55/59] copy dll for eth, check if qt is linked before running windeployqt --- cmake/EthExecutableHelper.cmake | 23 ++++++++++++++--------- eth/CMakeLists.txt | 4 ++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/cmake/EthExecutableHelper.cmake b/cmake/EthExecutableHelper.cmake index 0c2f72946..0c529881f 100644 --- a/cmake/EthExecutableHelper.cmake +++ b/cmake/EthExecutableHelper.cmake @@ -90,15 +90,20 @@ macro(eth_install_executable EXECUTABLE) " COMPONENT RUNTIME ) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" - WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} - ) - #workaround for https://bugreports.qt.io/browse/QTBUG-42083 - add_custom_command(TARGET ${EXECUTABLE} POST_BUILD - COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM - ) + + get_target_property(TARGET_LIBS ${EXECUTABLE} INTERFACE_LINK_LIBRARIES) + string(REGEX MATCH "Qt5::Core" HAVE_QT ${TARGET_LIBS}) + if ("${HAVE_QT}" STREQUAL "Qt5::Core") + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD + COMMAND cmd /C "set PATH=${Qt5Core_DIR}/../../../bin;%PATH% && ${WINDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.exe ${eth_qml_dir}" + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + ) + #workaround for https://bugreports.qt.io/browse/QTBUG-42083 + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD + COMMAND cmd /C "(echo [Paths] & echo.Prefix=.)" > "qt.conf" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} VERBATIM + ) + endif() #copy additional dlls foreach(dll ${ETH_INSTALL_EXECUTABLE_DLLS}) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index ed65862a4..bc458a50f 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -28,5 +28,9 @@ endif() target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} secp256k1) +if (WIN32) + add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") +endif() + install( TARGETS ${EXECUTABLE} DESTINATION bin ) From d417618dce14a58101a31471e025d18460b12daf Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 22 Feb 2015 18:38:32 +0100 Subject: [PATCH 56/59] Stack height checks and fix. --- libsolidity/Compiler.cpp | 40 +++++++++++++++++++++++++++++++---- libsolidity/Compiler.h | 2 +- libsolidity/CompilerContext.h | 2 +- libsolidity/Types.cpp | 11 ++++++++-- test/SolidityEndToEndTest.cpp | 1 - 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 23014da6c..e691394cb 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -34,6 +34,20 @@ using namespace std; namespace dev { namespace solidity { +/** + * Simple helper class to ensure that the stack height is the same at certain places in the code. + */ +class StackHeightChecker +{ +public: + StackHeightChecker(CompilerContext const& _context): + m_context(_context), stackHeight(m_context.getStackHeight()) {} + void check() { solAssert(m_context.getStackHeight() == stackHeight, "I sense a disturbance in the stack."); } +private: + CompilerContext const& m_context; + unsigned stackHeight; +}; + void Compiler::compileContract(ContractDefinition const& _contract, map const& _contracts) { @@ -340,6 +354,8 @@ bool Compiler::visit(FunctionDefinition const& _function) bool Compiler::visit(IfStatement const& _ifStatement) { + StackHeightChecker checker(m_context); + compileExpression(_ifStatement.getCondition()); eth::AssemblyItem trueTag = m_context.appendConditionalJump(); if (_ifStatement.getFalseStatement()) @@ -348,11 +364,15 @@ bool Compiler::visit(IfStatement const& _ifStatement) m_context << trueTag; _ifStatement.getTrueStatement().accept(*this); m_context << endTag; + + checker.check(); return false; } bool Compiler::visit(WhileStatement const& _whileStatement) { + StackHeightChecker checker(m_context); + eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); m_continueTags.push_back(loopStart); @@ -370,11 +390,15 @@ bool Compiler::visit(WhileStatement const& _whileStatement) m_continueTags.pop_back(); m_breakTags.pop_back(); + + checker.check(); return false; } bool Compiler::visit(ForStatement const& _forStatement) { + StackHeightChecker checker(m_context); + eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag(); m_continueTags.push_back(loopStart); @@ -404,6 +428,8 @@ bool Compiler::visit(ForStatement const& _forStatement) m_continueTags.pop_back(); m_breakTags.pop_back(); + + checker.check(); return false; } @@ -438,29 +464,35 @@ bool Compiler::visit(Return const& _return) return false; } -bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition) +bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement) { - if (Expression const* expression = _variableDefinition.getExpression()) + StackHeightChecker checker(m_context); + if (Expression const* expression = _variableDeclarationStatement.getExpression()) { - compileExpression(*expression, _variableDefinition.getDeclaration().getType()); - CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration()); + compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType()); + CompilerUtils(m_context).moveToStackVariable(_variableDeclarationStatement.getDeclaration()); } + checker.check(); return false; } bool Compiler::visit(ExpressionStatement const& _expressionStatement) { + StackHeightChecker checker(m_context); Expression const& expression = _expressionStatement.getExpression(); compileExpression(expression); CompilerUtils(m_context).popStackElement(*expression.getType()); + checker.check(); return false; } bool Compiler::visit(PlaceholderStatement const&) { + StackHeightChecker checker(m_context); ++m_modifierDepth; appendModifierOrFunctionCode(); --m_modifierDepth; + checker.check(); return true; } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 0838512ee..28ab34adb 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -69,7 +69,7 @@ private: virtual bool visit(Continue const& _continue) override; virtual bool visit(Break const& _break) override; virtual bool visit(Return const& _return) override; - virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override; + virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(PlaceholderStatement const&) override; diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index f202d7f4e..da2e7f4fe 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -48,7 +48,7 @@ public: bytes const& getCompiledContract(ContractDefinition const& _contract) const; void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } - unsigned getStackHeight() { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } + unsigned getStackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; } bool isLocalVariable(Declaration const* _declaration) const; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 55dedd921..ce51336df 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -833,10 +833,17 @@ string FunctionType::toString() const unsigned FunctionType::getSizeOnStack() const { + Location location = m_location; + if (m_location == Location::SetGas || m_location == Location::SetValue) + { + solAssert(m_returnParameterTypes.size() == 1, ""); + location = dynamic_cast(*m_returnParameterTypes.front()).m_location; + } + unsigned size = 0; - if (m_location == Location::External) + if (location == Location::External) size = 2; - else if (m_location == Location::Internal || m_location == Location::Bare) + else if (location == Location::Internal || location == Location::Bare) size = 1; if (m_gasSet) size++; diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 1f80b1017..20bc81599 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -1669,7 +1669,6 @@ BOOST_AUTO_TEST_CASE(value_insane) function test() { h = new helper(); } function sendAmount(uint amount) returns (uint256 bal) { var x1 = h.getBalance.value; - uint someStackElement = 20; var x2 = x1(amount).gas; var x3 = x2(1000).value; return x3(amount + 3)();// overwrite value From fba448415115cffd0cacfa054ba30fdd4daf8bba Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 22 Feb 2015 19:37:54 +0100 Subject: [PATCH 57/59] Replaced "inheritable" by "internal". --- libsolidity/AST.h | 6 +++--- libsolidity/Parser.cpp | 4 ++-- libsolidity/Token.h | 4 ++-- test/SolidityNameAndTypeResolution.cpp | 12 ++++++------ test/SolidityParser.cpp | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 064457d3b..138abf36e 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -133,7 +133,7 @@ class Declaration: public ASTNode { public: /// Visibility ordered from restricted to unrestricted. - enum class Visibility { Default, Private, Inheritable, Public, External }; + enum class Visibility { Default, Private, Internal, Public, External }; Declaration(Location const& _location, ASTPointer const& _name, Visibility _visibility = Visibility::Default): @@ -144,7 +144,7 @@ public: Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } bool isPublic() const { return getVisibility() >= Visibility::Public; } bool isVisibleInContract() const { return getVisibility() != Visibility::External; } - bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Inheritable; } + bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Internal; } /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. @@ -459,7 +459,7 @@ public: bool isIndexed() const { return m_isIndexed; } protected: - Visibility getDefaultVisibility() const override { return Visibility::Inheritable; } + Visibility getDefaultVisibility() const override { return Visibility::Internal; } private: ASTPointer m_typeName; ///< can be empty ("var") diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 9940fb8d9..9fe1af22e 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -187,8 +187,8 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) Declaration::Visibility visibility(Declaration::Visibility::Default); if (_token == Token::Public) visibility = Declaration::Visibility::Public; - else if (_token == Token::Inheritable) - visibility = Declaration::Visibility::Inheritable; + else if (_token == Token::Internal) + visibility = Declaration::Visibility::Internal; else if (_token == Token::Private) visibility = Declaration::Visibility::Private; else if (_token == Token::External) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 4aa000475..5e4a6317f 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -162,7 +162,7 @@ namespace solidity K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Inheritable, "inheritable", 0) \ + K(Internal, "internal", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ @@ -380,7 +380,7 @@ public: static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } - static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Inheritable; } + static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } // Returns a string corresponding to the JS token string diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index da6c2a88a..df970a6ed 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -470,7 +470,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_indirect) BOOST_AUTO_TEST_CASE(illegal_override_visibility) { char const* text = R"( - contract B { function f() inheritable {} } + contract B { function f() internal {} } contract C is B { function f() public {} } )"; BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); @@ -706,7 +706,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) " uint64(2);\n" " }\n" "uint256 private foo;\n" - "uint256 inheritable bar;\n" + "uint256 internal bar;\n" "}\n"; ASTPointer source; @@ -717,7 +717,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) function = retrieveFunctionBySignature(contract, "foo()"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist"); function = retrieveFunctionBySignature(contract, "bar()"); - BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an inheritable variable should not exist"); + BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist"); } BOOST_AUTO_TEST_CASE(fallback_function) @@ -832,11 +832,11 @@ BOOST_AUTO_TEST_CASE(access_to_default_function_visibility) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } -BOOST_AUTO_TEST_CASE(access_to_inheritable_function) +BOOST_AUTO_TEST_CASE(access_to_internal_function) { char const* text = R"( contract c { - function f() inheritable {} + function f() internal {} } contract d { function g() { c(0).f(); } @@ -856,7 +856,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } -BOOST_AUTO_TEST_CASE(access_to_inheritable_state_variable) +BOOST_AUTO_TEST_CASE(access_to_internal_state_variable) { char const* text = R"( contract c { diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index ddb582447..69bbc6e0a 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -651,13 +651,13 @@ BOOST_AUTO_TEST_CASE(visibility_specifiers) char const* text = R"( contract c { uint private a; - uint inheritable b; + uint internal b; uint public c; uint d; function f() {} function f_priv() private {} function f_public() public {} - function f_inheritable() inheritable {} + function f_internal() internal {} })"; BOOST_CHECK_NO_THROW(parseText(text)); } @@ -666,7 +666,7 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers) { char const* text = R"( contract c { - uint private inheritable a; + uint private internal a; })"; BOOST_CHECK_THROW(parseText(text), ParserError); } From 4a269eb47312e79f0eb99b6dd7a5f52be3af2444 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 23 Feb 2015 08:29:56 +0100 Subject: [PATCH 58/59] fix too-small-address-length bug in transaction --- libdevcore/RLP.h | 4 +++- libethereum/Transaction.cpp | 2 +- test/TestHelper.cpp | 4 ++-- test/transaction.cpp | 7 ++++++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index 34a0fc65f..a538fac21 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -242,7 +242,9 @@ public: AllowNonCanon = 1, ThrowOnFail = 4, FailIfTooBig = 8, + FailIfTooSmall = 16, Strict = ThrowOnFail | FailIfTooBig, + VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, LaisezFaire = AllowNonCanon }; @@ -269,7 +271,7 @@ public: template _N toHash(int _flags = Strict) const { - if (!isData() || (length() > _N::size && (_flags & FailIfTooBig))) + if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall))) if (_flags & ThrowOnFail) BOOST_THROW_EXCEPTION(BadCast()); else diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 345e379af..5b3557641 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -40,7 +40,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig) m_gasPrice = rlp[field = 1].toInt(); m_gas = rlp[field = 2].toInt(); m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; - m_receiveAddress = rlp[field = 3].toHash
(); + m_receiveAddress = rlp[field = 3].toHash
(RLP::VeryStrict); m_value = rlp[field = 4].toInt(); m_data = rlp[field = 5].toBytes(); byte v = rlp[field = 6].toInt() - 27; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index ff6939a5f..71d381030 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -475,11 +475,11 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun } catch (Exception const& _e) { - BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + BOOST_ERROR("Failed filling test with Exception: " << diagnostic_information(_e)); } catch (std::exception const& _e) { - BOOST_ERROR("Failed test with Exception: " << _e.what()); + BOOST_ERROR("Failed filling test with Exception: " << _e.what()); } break; } diff --git a/test/transaction.cpp b/test/transaction.cpp index 7bd8ac20c..6ebe62754 100644 --- a/test/transaction.cpp +++ b/test/transaction.cpp @@ -51,7 +51,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) catch(...) { BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); - return; + continue; } BOOST_REQUIRE(o.count("transaction") > 0); @@ -108,6 +108,11 @@ BOOST_AUTO_TEST_CASE(TransactionTest) dev::test::executeTests("ttTransactionTest", "/TransactionTests", dev::test::doTransactionTests); } +BOOST_AUTO_TEST_CASE(ttWrongRLPTransaction) +{ + dev::test::executeTests("ttWrongRLPTransaction", "/TransactionTests", dev::test::doTransactionTests); +} + BOOST_AUTO_TEST_CASE(tt10mbDataField) { dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests); From a9cc2ffa87cb8b550fdc51bfaf74ead78030e016 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 23 Feb 2015 08:56:15 +0100 Subject: [PATCH 59/59] address can only be empty or 20 bytes, nothing in between --- libethereum/Transaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 5b3557641..96689326d 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -40,7 +40,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig) m_gasPrice = rlp[field = 1].toInt(); m_gas = rlp[field = 2].toInt(); m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; - m_receiveAddress = rlp[field = 3].toHash
(RLP::VeryStrict); + m_receiveAddress = rlp[field = 3].isEmpty() ? Address() : rlp[field = 3].toHash
(RLP::VeryStrict); m_value = rlp[field = 4].toInt(); m_data = rlp[field = 5].toBytes(); byte v = rlp[field = 6].toInt() - 27;