From 11d34902bd7a33eca88324074bcb51a89c73a5ee Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 27 Dec 2014 21:45:16 +0000 Subject: [PATCH 001/201] 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 002/201] 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 003/201] 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 004/201] 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 005/201] 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 006/201] 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 007/201] 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 6f174b50afe3f9853cb96e33ed192aa1e5f2cda3 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 21 Jan 2015 16:10:06 +0100 Subject: [PATCH 008/201] new file block.cpp --- test/block.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/block.cpp diff --git a/test/block.cpp b/test/block.cpp new file mode 100644 index 000000000..974acbf6d --- /dev/null +++ b/test/block.cpp @@ -0,0 +1,21 @@ +/* + 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 state.cpp + * @author Christoph Jentzsch + * @date 2014 + * block test functions. + */ From 808b646de39c6774da3e254f0a28e1144a231db1 Mon Sep 17 00:00:00 2001 From: caktux Date: Thu, 22 Jan 2015 23:39:20 -0500 Subject: [PATCH 009/201] 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 998b0f7043d4d712fa4cadd6f088363502f34c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 15:23:49 +0100 Subject: [PATCH 010/201] Create README.md --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..30ed2f489 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# 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. + + From 8cb2a56764220439033c62875b69c5d657cb395e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 15:35:34 +0100 Subject: [PATCH 011/201] Create LICENSE.md --- LICENSE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..630157f98 --- /dev/null +++ b/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. From 1b449d357e36c73bcde5394282c343a92ef5024c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 16:20:22 +0100 Subject: [PATCH 012/201] Fallback to interpreter VM in case of JIT requirements unmet --- libevmjit-cpp/JitVM.cpp | 28 ++++++++++++++++------------ libevmjit-cpp/JitVM.h | 4 +--- libevmjit/Common.h | 24 ++++++++++++++---------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 613b5031c..e3bb09099 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -1,6 +1,7 @@ #include "JitVM.h" #include +#include #include #include "Utils.h" @@ -9,22 +10,25 @@ namespace dev namespace eth { -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; - if (m_gas > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that - - if (_ext.gasPrice > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.number > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.timestamp > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); + auto rejected = false; + 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); diff --git a/libevmjit-cpp/JitVM.h b/libevmjit-cpp/JitVM.h index 90855127e..58caa3648 100644 --- a/libevmjit-cpp/JitVM.h +++ b/libevmjit-cpp/JitVM.h @@ -12,15 +12,13 @@ class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - enum Kind: bool { Interpreter, JIT }; - static std::unique_ptr create(Kind, u256 _gas = 0); - 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/libevmjit/Common.h b/libevmjit/Common.h index 7383b9f93..e485148fb 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -25,20 +25,24 @@ struct NoteChannel {}; // FIXME: Use some log library? enum class ReturnCode { - Stop = 0, - Return = 1, + // Success codes + Stop = 0, + Return = 1, Suicide = 2, - OutOfGas = -1, - BadJumpDestination = -2, - StackTooSmall = -3, - BadInstruction = -4, + // 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 - LLVMConfigError = -5, - LLVMCompileError = -6, - LLVMLinkError = -7, + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, - UnexpectedException = -8, + UnexpectedException = -111, }; /// Representation of 256-bit value binary compatible with LLVM i256 From de649202a096a63fc8927540b703fdb18231cc11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 16:20:22 +0100 Subject: [PATCH 013/201] Fallback to interpreter VM in case of JIT requirements unmet --- evmjit/libevmjit-cpp/JitVM.cpp | 28 ++++++++++++++++------------ evmjit/libevmjit-cpp/JitVM.h | 4 +--- evmjit/libevmjit/Common.h | 24 ++++++++++++++---------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 613b5031c..e3bb09099 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -1,6 +1,7 @@ #include "JitVM.h" #include +#include #include #include "Utils.h" @@ -9,22 +10,25 @@ namespace dev namespace eth { -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const&, uint64_t) +bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; - if (m_gas > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); // Do not accept requests with gas > 2^63 (int64 max) // TODO: Return "not accepted" exception to allow interpreted handle that - - if (_ext.gasPrice > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.number > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); - - if (_ext.currentBlock.timestamp > std::numeric_limits::max()) - BOOST_THROW_EXCEPTION(OutOfGas()); + auto rejected = false; + 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); diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 90855127e..58caa3648 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -12,15 +12,13 @@ class JitVM: public VMFace { virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - enum Kind: bool { Interpreter, JIT }; - static std::unique_ptr create(Kind, u256 _gas = 0); - 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/Common.h b/evmjit/libevmjit/Common.h index 7383b9f93..e485148fb 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -25,20 +25,24 @@ struct NoteChannel {}; // FIXME: Use some log library? enum class ReturnCode { - Stop = 0, - Return = 1, + // Success codes + Stop = 0, + Return = 1, Suicide = 2, - OutOfGas = -1, - BadJumpDestination = -2, - StackTooSmall = -3, - BadInstruction = -4, + // 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 - LLVMConfigError = -5, - LLVMCompileError = -6, - LLVMLinkError = -7, + // Internal error codes + LLVMConfigError = -101, + LLVMCompileError = -102, + LLVMLinkError = -103, - UnexpectedException = -8, + UnexpectedException = -111, }; /// Representation of 256-bit value binary compatible with LLVM i256 From 5e29eef349b39c9cf95ada5c22d1e31094480e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 17:34:31 +0100 Subject: [PATCH 014/201] Replacing code references (usually vector&) with code_iterator pair. Code is now extracted from RuntimeData what removes copy in C interface. --- libevmjit-cpp/JitVM.cpp | 2 +- libevmjit/BasicBlock.cpp | 2 +- libevmjit/BasicBlock.h | 10 +++++----- libevmjit/Common.h | 1 + libevmjit/Compiler.cpp | 27 ++++++++++++++------------- libevmjit/Compiler.h | 8 +++++--- libevmjit/ExecutionEngine.cpp | 15 +++++++++------ libevmjit/ExecutionEngine.h | 2 +- libevmjit/Instruction.cpp | 4 ++-- libevmjit/Instruction.h | 4 ++-- libevmjit/interface.cpp | 11 +++++------ 11 files changed, 46 insertions(+), 40 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index e3bb09099..f92b114df 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -47,7 +47,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) m_data.codeSize = _ext.code.size(); auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(_ext.code, &m_data, env); + auto exitCode = m_engine.run(&m_data, env); switch (exitCode) { case ReturnCode::Suicide: diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 5868c0f43..c3668c61e 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -20,7 +20,7 @@ namespace jit const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : m_begin(_begin), m_end(_end), // TODO: Add begin index to name diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index cda4f89bd..26d6914d2 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -53,7 +53,7 @@ public: /// Basic block name prefix. The rest is instruction index. static const char* NamePrefix; - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(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; @@ -61,8 +61,8 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - bytes::const_iterator begin() { return m_begin; } - bytes::const_iterator end() { return m_end; } + code_iterator begin() { return m_begin; } + code_iterator end() { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +84,8 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - bytes::const_iterator const m_begin; - bytes::const_iterator const m_end; + code_iterator const m_begin = {}; + code_iterator const m_end = {}; llvm::BasicBlock* const m_llvmBB; diff --git a/libevmjit/Common.h b/libevmjit/Common.h index e485148fb..9c9dfd8a2 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -20,6 +20,7 @@ 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? diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1ce63d8ec..b6c3f10c0 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -39,10 +39,10 @@ Compiler::Compiler(Options const& _options): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytes const& _bytecode) +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 = [](bytes::const_iterator _curr, bytes::const_iterator _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); @@ -52,11 +52,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) return _curr + offset; }; - auto begin = _bytecode.begin(); + auto begin = _codeBegin; // begin of current block bool nextJumpDest = false; - for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) { - next = skipPushDataAndGetNext(curr, _bytecode.end()); + next = skipPushDataAndGetNext(curr, _codeEnd); bool isEnd = false; switch (Instruction(*curr)) @@ -77,13 +77,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) break; } - assert(next <= _bytecode.end()); - if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) isEnd = true; if (isEnd) { - auto beginIdx = begin - _bytecode.begin(); + auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; @@ -124,7 +124,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock() return m_badJumpBlock->llvm(); } -std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) +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())); @@ -138,7 +138,8 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(_bytecode); + m_codeBegin = _begin; + createBasicBlocks(_begin, _end); // Init runtime structures. RuntimeManager runtimeManager(m_builder); @@ -156,7 +157,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: @@ -223,7 +224,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str } -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, +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 @@ -622,7 +623,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::PC: { - auto value = Constant::get(it - _bytecode.begin()); + auto value = Constant::get(it - m_codeBegin); stack.push(value); break; } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 720a48cf9..3c9bb9c68 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -33,13 +33,13 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); private: - void createBasicBlocks(bytes const& _bytecode); + void createBasicBlocks(code_iterator _begin, code_iterator _end); - void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); llvm::BasicBlock* getJumpTableBlock(); @@ -76,6 +76,8 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; + + code_iterator m_codeBegin = {}; }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ee92a6ba9..e23a625e3 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -52,15 +52,15 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(bytes const& _code) +std::string codeHash(code_iterator _begin, code_iterator _end) { uint32_t hash = 0; - for (auto b : _code) + std::for_each(_begin, _end, [&hash](decltype(*_begin) b) { hash += b; hash += (hash << 10); hash ^= (hash >> 6); - } + }); hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); @@ -69,13 +69,16 @@ std::string codeHash(bytes const& _code) } -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); - auto mainFuncName = codeHash(_code); + auto codeBegin = _data->code; + auto codeEnd = codeBegin + _data->codeSize; + assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? + auto mainFuncName = codeHash(codeBegin, codeEnd); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls @@ -89,7 +92,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en if (objectCache) module = Cache::getObject(mainFuncName); if (!module) - module = Compiler({}).compile(_code, mainFuncName); + module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); if (debugDumpModule) module->dump(); if (!ee) diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index e8d1e1c05..c95bbfb62 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -16,7 +16,7 @@ public: ExecutionEngine(ExecutionEngine const&) = delete; void operator=(ExecutionEngine) = delete; - EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); /// Reference to returned data (RETURN opcode used) bytes_ref returnData; diff --git a/libevmjit/Instruction.cpp b/libevmjit/Instruction.cpp index fdc40d043..909121607 100644 --- a/libevmjit/Instruction.cpp +++ b/libevmjit/Instruction.cpp @@ -9,7 +9,7 @@ namespace eth namespace jit { -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); @@ -26,7 +26,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en return value; } -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +void skipPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 158490dee..6785213d6 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -161,11 +161,11 @@ enum class Instruction: uint8_t /// 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(bytes::const_iterator& _curr, bytes::const_iterator _end); +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(bytes::const_iterator& _curr, bytes::const_iterator _end); +void skipPushData(code_iterator& _curr, code_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ diff --git a/libevmjit/interface.cpp b/libevmjit/interface.cpp index 6b0992dd4..645f3d150 100644 --- a/libevmjit/interface.cpp +++ b/libevmjit/interface.cpp @@ -12,6 +12,7 @@ using namespace dev::eth::jit; EXPORT void* evmjit_create() noexcept { + // TODO: Make sure ExecutionEngine constructor does not throw return new(std::nothrow) ExecutionEngine; } @@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept { + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + try { - auto codePtr = _data->code; - auto codeSize = _data->codeSize; - bytes bytecode; - bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - - auto returnCode = _engine->run(bytecode, _data, _env); + auto returnCode = _engine->run(_data, _env); return static_cast(returnCode); } catch(...) From 932ce6650ca47868f8a5266ab02981897808a5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 17:34:31 +0100 Subject: [PATCH 015/201] Replacing code references (usually vector&) with code_iterator pair. Code is now extracted from RuntimeData what removes copy in C interface. --- evmjit/libevmjit-cpp/JitVM.cpp | 2 +- evmjit/libevmjit/BasicBlock.cpp | 2 +- evmjit/libevmjit/BasicBlock.h | 10 +++++----- evmjit/libevmjit/Common.h | 1 + evmjit/libevmjit/Compiler.cpp | 27 ++++++++++++++------------- evmjit/libevmjit/Compiler.h | 8 +++++--- evmjit/libevmjit/ExecutionEngine.cpp | 15 +++++++++------ evmjit/libevmjit/ExecutionEngine.h | 2 +- evmjit/libevmjit/Instruction.cpp | 4 ++-- evmjit/libevmjit/Instruction.h | 4 ++-- evmjit/libevmjit/interface.cpp | 11 +++++------ 11 files changed, 46 insertions(+), 40 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index e3bb09099..f92b114df 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -47,7 +47,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) m_data.codeSize = _ext.code.size(); auto env = reinterpret_cast(&_ext); - auto exitCode = m_engine.run(_ext.code, &m_data, env); + auto exitCode = m_engine.run(&m_data, env); switch (exitCode) { case ReturnCode::Suicide: diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index 5868c0f43..c3668c61e 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -20,7 +20,7 @@ namespace jit const char* BasicBlock::NamePrefix = "Instr."; -BasicBlock::BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : m_begin(_begin), m_end(_end), // TODO: Add begin index to name diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index cda4f89bd..26d6914d2 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -53,7 +53,7 @@ public: /// Basic block name prefix. The rest is instruction index. static const char* NamePrefix; - explicit BasicBlock(bytes::const_iterator _begin, bytes::const_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + explicit BasicBlock(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; @@ -61,8 +61,8 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - bytes::const_iterator begin() { return m_begin; } - bytes::const_iterator end() { return m_end; } + code_iterator begin() { return m_begin; } + code_iterator end() { return m_end; } bool isJumpDest() const { return m_isJumpDest; } @@ -84,8 +84,8 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - bytes::const_iterator const m_begin; - bytes::const_iterator const m_end; + code_iterator const m_begin = {}; + code_iterator const m_end = {}; llvm::BasicBlock* const m_llvmBB; diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index e485148fb..9c9dfd8a2 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -20,6 +20,7 @@ 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? diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 1ce63d8ec..b6c3f10c0 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -39,10 +39,10 @@ Compiler::Compiler(Options const& _options): Type::init(m_builder.getContext()); } -void Compiler::createBasicBlocks(bytes const& _bytecode) +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 = [](bytes::const_iterator _curr, bytes::const_iterator _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); @@ -52,11 +52,11 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) return _curr + offset; }; - auto begin = _bytecode.begin(); + auto begin = _codeBegin; // begin of current block bool nextJumpDest = false; - for (auto curr = begin, next = begin; curr != _bytecode.end(); curr = next) + for (auto curr = begin, next = begin; curr != _codeEnd; curr = next) { - next = skipPushDataAndGetNext(curr, _bytecode.end()); + next = skipPushDataAndGetNext(curr, _codeEnd); bool isEnd = false; switch (Instruction(*curr)) @@ -77,13 +77,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) break; } - assert(next <= _bytecode.end()); - if (next == _bytecode.end() || Instruction(*next) == Instruction::JUMPDEST) + assert(next <= _codeEnd); + if (next == _codeEnd || Instruction(*next) == Instruction::JUMPDEST) isEnd = true; if (isEnd) { - auto beginIdx = begin - _bytecode.begin(); + auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; @@ -124,7 +124,7 @@ llvm::BasicBlock* Compiler::getBadJumpBlock() return m_badJumpBlock->llvm(); } -std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) +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())); @@ -138,7 +138,8 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - createBasicBlocks(_bytecode); + m_codeBegin = _begin; + createBasicBlocks(_begin, _end); // Init runtime structures. RuntimeManager runtimeManager(m_builder); @@ -156,7 +157,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str auto iterCopy = basicBlockPairIt; ++iterCopy; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; - compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); + compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); } // Code for special blocks: @@ -223,7 +224,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str } -void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, RuntimeManager& _runtimeManager, +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 @@ -622,7 +623,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::PC: { - auto value = Constant::get(it - _bytecode.begin()); + auto value = Constant::get(it - m_codeBegin); stack.push(value); break; } diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 720a48cf9..3c9bb9c68 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -33,13 +33,13 @@ public: Compiler(Options const& _options); - std::unique_ptr compile(bytes const& _bytecode, std::string const& _id); + std::unique_ptr compile(code_iterator _begin, code_iterator _end, std::string const& _id); private: - void createBasicBlocks(bytes const& _bytecode); + void createBasicBlocks(code_iterator _begin, code_iterator _end); - void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); llvm::BasicBlock* getJumpTableBlock(); @@ -76,6 +76,8 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; + + code_iterator m_codeBegin = {}; }; } diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index ee92a6ba9..e23a625e3 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -52,15 +52,15 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(bytes const& _code) +std::string codeHash(code_iterator _begin, code_iterator _end) { uint32_t hash = 0; - for (auto b : _code) + std::for_each(_begin, _end, [&hash](decltype(*_begin) b) { hash += b; hash += (hash << 10); hash ^= (hash >> 6); - } + }); hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); @@ -69,13 +69,16 @@ std::string codeHash(bytes const& _code) } -ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _env) +ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); - auto mainFuncName = codeHash(_code); + auto codeBegin = _data->code; + auto codeEnd = codeBegin + _data->codeSize; + assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? + auto mainFuncName = codeHash(codeBegin, codeEnd); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls @@ -89,7 +92,7 @@ ReturnCode ExecutionEngine::run(bytes const& _code, RuntimeData* _data, Env* _en if (objectCache) module = Cache::getObject(mainFuncName); if (!module) - module = Compiler({}).compile(_code, mainFuncName); + module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); if (debugDumpModule) module->dump(); if (!ee) diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index e8d1e1c05..c95bbfb62 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -16,7 +16,7 @@ public: ExecutionEngine(ExecutionEngine const&) = delete; void operator=(ExecutionEngine) = delete; - EXPORT ReturnCode run(bytes const& _code, RuntimeData* _data, Env* _env); + EXPORT ReturnCode run(RuntimeData* _data, Env* _env); /// Reference to returned data (RETURN opcode used) bytes_ref returnData; diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp index fdc40d043..909121607 100644 --- a/evmjit/libevmjit/Instruction.cpp +++ b/evmjit/libevmjit/Instruction.cpp @@ -9,7 +9,7 @@ namespace eth namespace jit { -llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +llvm::APInt readPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); @@ -26,7 +26,7 @@ llvm::APInt readPushData(bytes::const_iterator& _curr, bytes::const_iterator _en return value; } -void skipPushData(bytes::const_iterator& _curr, bytes::const_iterator _end) +void skipPushData(code_iterator& _curr, code_iterator _end) { auto pushInst = *_curr; assert(Instruction(pushInst) >= Instruction::PUSH1 && Instruction(pushInst) <= Instruction::PUSH32); diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h index 158490dee..6785213d6 100644 --- a/evmjit/libevmjit/Instruction.h +++ b/evmjit/libevmjit/Instruction.h @@ -161,11 +161,11 @@ enum class Instruction: uint8_t /// 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(bytes::const_iterator& _curr, bytes::const_iterator _end); +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(bytes::const_iterator& _curr, bytes::const_iterator _end); +void skipPushData(code_iterator& _curr, code_iterator _end); #define ANY_PUSH PUSH1: \ case Instruction::PUSH2: \ diff --git a/evmjit/libevmjit/interface.cpp b/evmjit/libevmjit/interface.cpp index 6b0992dd4..645f3d150 100644 --- a/evmjit/libevmjit/interface.cpp +++ b/evmjit/libevmjit/interface.cpp @@ -12,6 +12,7 @@ using namespace dev::eth::jit; EXPORT void* evmjit_create() noexcept { + // TODO: Make sure ExecutionEngine constructor does not throw return new(std::nothrow) ExecutionEngine; } @@ -22,14 +23,12 @@ EXPORT void evmjit_destroy(ExecutionEngine* _engine) noexcept EXPORT int evmjit_run(ExecutionEngine* _engine, RuntimeData* _data, Env* _env) noexcept { + if (!_engine || !_data) + return static_cast(ReturnCode::UnexpectedException); + try { - auto codePtr = _data->code; - auto codeSize = _data->codeSize; - bytes bytecode; - bytecode.insert(bytecode.end(), codePtr, codePtr + codeSize); - - auto returnCode = _engine->run(bytecode, _data, _env); + auto returnCode = _engine->run(_data, _env); return static_cast(returnCode); } catch(...) From 64532b6b0ab097e53331e48e6f1fb5335243724d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 18:02:55 +0100 Subject: [PATCH 016/201] Environment options for EVM JIT updated: - EVMJIT_CACHE=0 disables disk cache, default 1 - EVMJIT_DUMP=1 dumps LLVM module to error output, default 0 --- libevmjit/ExecutionEngine.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index e23a625e3..653e0d9d0 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,6 +1,7 @@ #include "ExecutionEngine.h" #include +#include // env options #include #include @@ -19,13 +20,6 @@ #include "Compiler.h" #include "Cache.h" -#if defined(NDEBUG) -#define DEBUG_ENV_OPTION(name) false -#else -#include -#define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr) -#endif - namespace dev { namespace eth @@ -67,13 +61,21 @@ std::string codeHash(code_iterator _begin, code_iterator _end) return std::to_string(hash); } +bool getEnvOption(char const* _name, bool _default) +{ + auto var = std::getenv(_name); + if (!var) + return _default; + return std::strtol(var, nullptr, 10) != 0; +} + } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); - static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); + static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); + static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; From c49f78ca4f73999ca828e73933acffdac144acde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 18:02:55 +0100 Subject: [PATCH 017/201] Environment options for EVM JIT updated: - EVMJIT_CACHE=0 disables disk cache, default 1 - EVMJIT_DUMP=1 dumps LLVM module to error output, default 0 --- evmjit/libevmjit/ExecutionEngine.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index e23a625e3..653e0d9d0 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -1,6 +1,7 @@ #include "ExecutionEngine.h" #include +#include // env options #include #include @@ -19,13 +20,6 @@ #include "Compiler.h" #include "Cache.h" -#if defined(NDEBUG) -#define DEBUG_ENV_OPTION(name) false -#else -#include -#define DEBUG_ENV_OPTION(name) (std::getenv(#name) != nullptr) -#endif - namespace dev { namespace eth @@ -67,13 +61,21 @@ std::string codeHash(code_iterator _begin, code_iterator _end) return std::to_string(hash); } +bool getEnvOption(char const* _name, bool _default) +{ + auto var = std::getenv(_name); + if (!var) + return _default; + return std::strtol(var, nullptr, 10) != 0; +} + } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? - static auto debugDumpModule = DEBUG_ENV_OPTION(EVMJIT_DUMP_MODULE); - static bool objectCacheEnabled = !DEBUG_ENV_OPTION(EVMJIT_CACHE_OFF); + static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); + static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; From c914c877e30de0c00b80f2513f589b9778621c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 19:36:41 +0100 Subject: [PATCH 018/201] Add code hash to RuntimeData. JIT is using it as an code identifier (do not need to invent any internal hashing) --- libevmjit-cpp/JitVM.cpp | 2 ++ libevmjit/ExecutionEngine.cpp | 27 +++++++++++++++------------ libevmjit/RuntimeData.h | 1 + 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index f92b114df..08113122b 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -2,6 +2,7 @@ #include "JitVM.h" #include #include +#include #include #include "Utils.h" @@ -45,6 +46,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) 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); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 653e0d9d0..69cf28afd 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -20,6 +20,8 @@ #include "Compiler.h" #include "Cache.h" +#include + namespace dev { namespace eth @@ -46,19 +48,20 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(code_iterator _begin, code_iterator _end) +std::string codeHash(i256 const& _hash) { - uint32_t hash = 0; - std::for_each(_begin, _end, [&hash](decltype(*_begin) b) + 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) { - hash += b; - hash += (hash << 10); - hash ^= (hash >> 6); - }); - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return std::to_string(hash); + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; + } + return str; } bool getEnvOption(char const* _name, bool _default) @@ -80,7 +83,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(codeBegin, codeEnd); + auto mainFuncName = codeHash(_data->codeHash); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index 58d68db8a..ff6e82fe8 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -50,6 +50,7 @@ struct RuntimeData int64_t timestamp = 0; byte const* code = nullptr; uint64_t codeSize = 0; + i256 codeHash; }; /// VM Environment (ExtVM) opaque type From b999cc28c41990ebcbf4602c146454656adfe6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 29 Jan 2015 19:36:41 +0100 Subject: [PATCH 019/201] Add code hash to RuntimeData. JIT is using it as an code identifier (do not need to invent any internal hashing) --- evmjit/libevmjit-cpp/JitVM.cpp | 2 ++ evmjit/libevmjit/ExecutionEngine.cpp | 27 +++++++++++++++------------ evmjit/libevmjit/RuntimeData.h | 1 + 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index f92b114df..08113122b 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -2,6 +2,7 @@ #include "JitVM.h" #include #include +#include #include #include "Utils.h" @@ -45,6 +46,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) 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); diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 653e0d9d0..69cf28afd 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -20,6 +20,8 @@ #include "Compiler.h" #include "Cache.h" +#include + namespace dev { namespace eth @@ -46,19 +48,20 @@ ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) return returnCode; } -std::string codeHash(code_iterator _begin, code_iterator _end) +std::string codeHash(i256 const& _hash) { - uint32_t hash = 0; - std::for_each(_begin, _end, [&hash](decltype(*_begin) b) + 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) { - hash += b; - hash += (hash << 10); - hash ^= (hash >> 6); - }); - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return std::to_string(hash); + *(outIt++) = hexChars[b & 0xf]; + *(outIt++) = hexChars[b >> 4]; + } + return str; } bool getEnvOption(char const* _name, bool _default) @@ -80,7 +83,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(codeBegin, codeEnd); + auto mainFuncName = codeHash(_data->codeHash); EntryFuncPtr entryFuncPtr{}; Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h index 58d68db8a..ff6e82fe8 100644 --- a/evmjit/libevmjit/RuntimeData.h +++ b/evmjit/libevmjit/RuntimeData.h @@ -50,6 +50,7 @@ struct RuntimeData int64_t timestamp = 0; byte const* code = nullptr; uint64_t codeSize = 0; + i256 codeHash; }; /// VM Environment (ExtVM) opaque type From bdba3104d6776ed4550eeae62aab2d68d4840cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 10:58:34 +0100 Subject: [PATCH 020/201] Improve versioning --- libevmjit/CMakeLists.txt | 47 ++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 545e55344..f062c65e6 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -11,19 +11,48 @@ if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) endif() -find_package(Git) -if(GIT_FOUND) - execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} describe --dirty --always - OUTPUT_VARIABLE EVMJIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + +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(NOT EVMJIT_VERSION) - set(EVMJIT_VERSION "unknown") + +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 0) + list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) + endif() +endif() + +if(${EVMJIT_VERSION_MAJOR} EQUAL 0) + set(EVMJIT_SOVERSION "0.${EVMJIT_VERSION_MINOR}") +else() + set(EVMJIT_SOVERSION ${EVMJIT_VERSION_MAJOR}) endif() -message("EVM JIT version: ${EVMJIT_VERSION}") +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}) -set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${EVMJIT_VERSION} FOLDER "libs") +set_target_properties(${TARGET_NAME} PROPERTIES + VERSION ${EVMJIT_VERSION} SOVERSION ${EVMJIT_SOVERSION} + FOLDER "libs") include_directories(${LLVM_INCLUDE_DIRS}) @@ -32,4 +61,4 @@ 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}) +#install(FILES ${INTERFACE_HEADERS} DESTINATION include/${TARGET_NAME}) \ No newline at end of file From e8e9490b566563d0991ddf7f14cd2e0958ee5ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 11:20:56 +0100 Subject: [PATCH 021/201] Disable RTTI for evmjit library --- CMakeLists.txt | 6 +++--- libevmjit-cpp/CMakeLists.txt | 5 +++++ libevmjit/CMakeLists.txt | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a449f9a60..05a918ad0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,12 @@ project(evmjit) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -fPIC") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra") endif() -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") +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() diff --git a/libevmjit-cpp/CMakeLists.txt b/libevmjit-cpp/CMakeLists.txt index 58375e4ee..53448332b 100644 --- a/libevmjit-cpp/CMakeLists.txt +++ b/libevmjit-cpp/CMakeLists.txt @@ -9,6 +9,11 @@ set(SOURCES ) 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") diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index f062c65e6..f88a5468b 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -6,9 +6,9 @@ set(INTERFACE_HEADERS interface.h) source_group("" FILES ${HEADERS}) source_group("" FILES ${SOURCES}) -if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # Disable rtti for Cache as LLVM has no rtti - set_source_files_properties(Cache.cpp PROPERTIES COMPILE_FLAGS -fno-rtti) +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") endif() From 27ca018c35c9c80b0dc593852989777c315e900f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:13:04 +0100 Subject: [PATCH 022/201] Add first instruction index to BasicBlock --- CMakeLists.txt | 1 + libevmjit/BasicBlock.cpp | 9 +++++---- libevmjit/BasicBlock.h | 17 ++++++++--------- libevmjit/Compiler.cpp | 5 ++--- libevmjit/Compiler.h | 2 -- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05a918ad0..ce05c422d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ 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() diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index c3668c61e..d907aada1 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -18,13 +18,14 @@ namespace eth namespace jit { -const char* BasicBlock::NamePrefix = "Instr."; +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; -BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +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), - // TODO: Add begin index to name - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), m_stack(*this), m_builder(_builder), m_isJumpDest(isJumpDest) diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 26d6914d2..1be742f9f 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -11,7 +11,7 @@ namespace eth namespace jit { -using ProgramCounter = uint64_t; // TODO: Rename +using instr_idx = uint64_t; class BasicBlock { @@ -50,10 +50,7 @@ public: BasicBlock& m_bblock; }; - /// Basic block name prefix. The rest is instruction index. - static const char* NamePrefix; - - explicit BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + 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; @@ -61,8 +58,9 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - code_iterator begin() { return m_begin; } - code_iterator end() { return m_end; } + 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; } @@ -84,8 +82,9 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - code_iterator const m_begin = {}; - code_iterator const m_end = {}; + 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; diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b6c3f10c0..eddd16492 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -85,7 +85,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn { auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), - std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; begin = next; } @@ -138,7 +138,6 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - m_codeBegin = _begin; createBasicBlocks(_begin, _end); // Init runtime structures. @@ -623,7 +622,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::PC: { - auto value = Constant::get(it - m_codeBegin); + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); stack.push(value); break; } diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 3c9bb9c68..89b2f1a8e 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -76,8 +76,6 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; - - code_iterator m_codeBegin = {}; }; } From 01dffe28f32756aca7e2be0389ff5552bf8c0105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:13:04 +0100 Subject: [PATCH 023/201] Add first instruction index to BasicBlock --- evmjit/CMakeLists.txt | 1 + evmjit/libevmjit/BasicBlock.cpp | 9 +++++---- evmjit/libevmjit/BasicBlock.h | 17 ++++++++--------- evmjit/libevmjit/Compiler.cpp | 5 ++--- evmjit/libevmjit/Compiler.h | 2 -- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 05a918ad0..ce05c422d 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -3,6 +3,7 @@ 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() diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index c3668c61e..d907aada1 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -18,13 +18,14 @@ namespace eth namespace jit { -const char* BasicBlock::NamePrefix = "Instr."; +static const char* jumpDestName = "JmpDst."; +static const char* basicBlockName = "Instr."; -BasicBlock::BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) : +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), - // TODO: Add begin index to name - m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), NamePrefix, _mainFunc)), + m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), m_stack(*this), m_builder(_builder), m_isJumpDest(isJumpDest) diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 26d6914d2..1be742f9f 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -11,7 +11,7 @@ namespace eth namespace jit { -using ProgramCounter = uint64_t; // TODO: Rename +using instr_idx = uint64_t; class BasicBlock { @@ -50,10 +50,7 @@ public: BasicBlock& m_bblock; }; - /// Basic block name prefix. The rest is instruction index. - static const char* NamePrefix; - - explicit BasicBlock(code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest); + 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; @@ -61,8 +58,9 @@ public: llvm::BasicBlock* llvm() { return m_llvmBB; } - code_iterator begin() { return m_begin; } - code_iterator end() { return m_end; } + 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; } @@ -84,8 +82,9 @@ public: void dump(std::ostream& os, bool _dotOutput = false); private: - code_iterator const m_begin = {}; - code_iterator const m_end = {}; + 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; diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index b6c3f10c0..eddd16492 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -85,7 +85,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn { auto beginIdx = begin - _codeBegin; m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), - std::forward_as_tuple(begin, next, m_mainFunc, m_builder, nextJumpDest)); + std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest)); nextJumpDest = false; begin = next; } @@ -138,7 +138,6 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); m_builder.SetInsertPoint(entryBlock); - m_codeBegin = _begin; createBasicBlocks(_begin, _end); // Init runtime structures. @@ -623,7 +622,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::PC: { - auto value = Constant::get(it - m_codeBegin); + auto value = Constant::get(it - _basicBlock.begin() + _basicBlock.firstInstrIdx()); stack.push(value); break; } diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 3c9bb9c68..89b2f1a8e 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -76,8 +76,6 @@ private: /// Main program function llvm::Function* m_mainFunc = nullptr; - - code_iterator m_codeBegin = {}; }; } From 561028862681b3ccb73249305c93536198b00018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:30:25 +0100 Subject: [PATCH 024/201] Improve allocas order and namings --- libevmjit/Ext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index a37a6fe99..965ef2e06 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -60,14 +60,16 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) llvm::Value* Ext::getArgAlloca() { - auto& a = m_argAllocas[m_argCounter++]; + auto& a = m_argAllocas[m_argCounter]; if (!a) { - // FIXME: Improve order and names InsertPointGuard g{getBuilder()}; - getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); - a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); + 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; } From 019aa6dd638e68c3259aaebda297eb564ec8a1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 30 Jan 2015 14:30:25 +0100 Subject: [PATCH 025/201] Improve allocas order and namings --- evmjit/libevmjit/Ext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index a37a6fe99..965ef2e06 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -60,14 +60,16 @@ llvm::Function* createFunc(EnvFunc _id, llvm::Module* _module) llvm::Value* Ext::getArgAlloca() { - auto& a = m_argAllocas[m_argCounter++]; + auto& a = m_argAllocas[m_argCounter]; if (!a) { - // FIXME: Improve order and names InsertPointGuard g{getBuilder()}; - getBuilder().SetInsertPoint(getMainFunction()->front().getFirstNonPHI()); - a = getBuilder().CreateAlloca(Type::Word, nullptr, "arg"); + 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; } From c633e62102ccb1bedbb5c79c341201627950c2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 14:31:53 +0100 Subject: [PATCH 026/201] Gas counting changes: allow memory words counter not greater than gas max (int64 max) --- libevmjit-cpp/JitVM.cpp | 1 + libevmjit/GasMeter.cpp | 11 +++++++++-- libevmjit/Type.cpp | 5 +++++ libevmjit/Type.h | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index 08113122b..ab1a4cf2b 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -16,6 +16,7 @@ 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(); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 4aa6a738d..d54eea754 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -94,12 +94,13 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - m_builder.SetInsertPoint(checkBB); auto arg = m_gasCheckFunc->arg_begin(); arg->setName("rt"); ++arg; arg->setName("cost"); auto cost = arg; + + m_builder.SetInsertPoint(checkBB); auto gas = m_runtimeManager.getGas(); auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); @@ -208,8 +209,14 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { + assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - count(_additionalMemoryInWords); + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); + auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); + additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); + auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); + count(additionalMemoryInWords256); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 22ccea12e..169691904 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -17,6 +17,7 @@ llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -24,6 +25,7 @@ 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) { @@ -35,6 +37,7 @@ void Type::init(llvm::LLVMContext& _context) // TODO: Size should be architecture-dependent Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); + Gas = Size; Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); @@ -43,6 +46,8 @@ void Type::init(llvm::LLVMContext& _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()); } } diff --git a/libevmjit/Type.h b/libevmjit/Type.h index d4804ee59..cfac1e2c6 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -23,6 +23,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; @@ -41,6 +42,8 @@ struct Type 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); From 3290856061b9478f084f02f10f08b35d04adb407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 14:31:53 +0100 Subject: [PATCH 027/201] Gas counting changes: allow memory words counter not greater than gas max (int64 max) --- evmjit/libevmjit-cpp/JitVM.cpp | 1 + evmjit/libevmjit/GasMeter.cpp | 11 +++++++++-- evmjit/libevmjit/Type.cpp | 5 +++++ evmjit/libevmjit/Type.h | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 08113122b..ab1a4cf2b 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -16,6 +16,7 @@ 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(); diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 4aa6a738d..d54eea754 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -94,12 +94,13 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - m_builder.SetInsertPoint(checkBB); auto arg = m_gasCheckFunc->arg_begin(); arg->setName("rt"); ++arg; arg->setName("cost"); auto cost = arg; + + m_builder.SetInsertPoint(checkBB); auto gas = m_runtimeManager.getGas(); auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); @@ -208,8 +209,14 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { + assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - count(_additionalMemoryInWords); + auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); + auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); + auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); + additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); + auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); + count(additionalMemoryInWords256); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 22ccea12e..169691904 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -17,6 +17,7 @@ llvm::PointerType* Type::WordPtr; llvm::IntegerType* Type::lowPrecision; llvm::IntegerType* Type::Bool; llvm::IntegerType* Type::Size; +llvm::IntegerType* Type::Gas; llvm::IntegerType* Type::Byte; llvm::PointerType* Type::BytePtr; llvm::Type* Type::Void; @@ -24,6 +25,7 @@ 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) { @@ -35,6 +37,7 @@ void Type::init(llvm::LLVMContext& _context) // TODO: Size should be architecture-dependent Bool = llvm::Type::getInt1Ty(_context); Size = llvm::Type::getInt64Ty(_context); + Gas = Size; Byte = llvm::Type::getInt8Ty(_context); BytePtr = Byte->getPointerTo(); Void = llvm::Type::getVoidTy(_context); @@ -43,6 +46,8 @@ void Type::init(llvm::LLVMContext& _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()); } } diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index d4804ee59..cfac1e2c6 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -23,6 +23,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; + static llvm::IntegerType* Gas; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; @@ -41,6 +42,8 @@ struct Type 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); From 407cae129f38abcdd1fbdfca366267cc59374c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:08:57 +0100 Subject: [PATCH 028/201] Count gas using int64 --- libevmjit/BasicBlock.cpp | 1 + libevmjit/Compiler.cpp | 3 +- libevmjit/Ext.cpp | 6 +- libevmjit/GasMeter.cpp | 103 ++++++++++++++++++----------------- libevmjit/GasMeter.h | 2 +- libevmjit/RuntimeManager.cpp | 10 ++-- 6 files changed, 66 insertions(+), 59 deletions(-) diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index d907aada1..c71bae94f 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -44,6 +44,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _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; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index eddd16492..b6206b8d8 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -630,7 +630,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::GAS: { _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); break; } @@ -770,6 +770,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti receiveAddress = _runtimeManager.get(RuntimeData::Address); _gasMeter.count(gas); + // TODO: pass gas to call as int64 auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); _gasMeter.giveBack(gas); stack.push(ret); diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 965ef2e06..28e10366c 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -128,12 +128,14 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas = byPtr(_gas); + auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); + auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas + gas256 = m_builder.CreateLoad(gas); // Return gas + _gas = m_builder.CreateTrunc(gas256, Type::Gas); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index d54eea754..8ac575338 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -19,29 +19,29 @@ namespace jit namespace // Helper functions { -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) +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) { @@ -72,7 +72,7 @@ uint64_t getStepCost(Instruction inst) case Instruction::LOG3: case Instruction::LOG4: { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } } @@ -86,7 +86,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + 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); @@ -94,15 +94,15 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; + 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(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + 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); @@ -110,7 +110,6 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -120,7 +119,7 @@ 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::Word)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); } m_blockCost += getStepCost(_inst); @@ -128,6 +127,15 @@ void GasMeter::count(Instruction _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}); } @@ -137,12 +145,13 @@ void GasMeter::countExp(llvm::Value* _exponent) // lz - leading zeros // cost = ((256 - lz) + 7) / 8 - // OPT: All calculations can be done on 32/64 bits + // OPT: Can gas update be done in exp algorithm? auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + 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); } @@ -155,8 +164,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu 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, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + 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); } @@ -179,13 +188,13 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); + count(cost64); } void GasMeter::giveBack(llvm::Value* _gas) { - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); + assert(_gas->getType() == Type::Word); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); } void GasMeter::commitCostBlock() @@ -200,7 +209,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + 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; } @@ -209,14 +218,8 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { - assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); - auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); - auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); - additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); - auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); - count(additionalMemoryInWords256); + count(_additionalMemoryInWords); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 56da6eb9f..27f55253f 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -50,7 +50,7 @@ public: private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow - uint64_t m_blockCost = 0; + int64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; llvm::Function* m_gasCheckFunc = nullptr; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 408f2dee3..1441f475a 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -216,15 +216,15 @@ llvm::Value* RuntimeManager::getJmpBuf() llvm::Value* RuntimeManager::getGas() { - auto value = get(RuntimeData::Gas); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; } void RuntimeManager::setGas(llvm::Value* _gas) { - auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); - set(RuntimeData::Gas, newGas); + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); } } From b4749247833375646afb578f9172539bf78f5392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:08:57 +0100 Subject: [PATCH 029/201] Count gas using int64 --- evmjit/libevmjit/BasicBlock.cpp | 1 + evmjit/libevmjit/Compiler.cpp | 3 +- evmjit/libevmjit/Ext.cpp | 6 +- evmjit/libevmjit/GasMeter.cpp | 103 ++++++++++++++-------------- evmjit/libevmjit/GasMeter.h | 2 +- evmjit/libevmjit/RuntimeManager.cpp | 10 +-- 6 files changed, 66 insertions(+), 59 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index d907aada1..c71bae94f 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -44,6 +44,7 @@ BasicBlock::LocalStack::LocalStack(BasicBlock& _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; } diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index eddd16492..b6206b8d8 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -630,7 +630,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::GAS: { _gasMeter.commitCostBlock(); - stack.push(_runtimeManager.getGas()); + stack.push(m_builder.CreateZExt(_runtimeManager.getGas(), Type::Word)); break; } @@ -770,6 +770,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti receiveAddress = _runtimeManager.get(RuntimeData::Address); _gasMeter.count(gas); + // TODO: pass gas to call as int64 auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); _gasMeter.giveBack(gas); stack.push(ret); diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 965ef2e06..28e10366c 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -128,12 +128,14 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas = byPtr(_gas); + auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); + auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - _gas = m_builder.CreateLoad(gas); // Return gas + gas256 = m_builder.CreateLoad(gas); // Return gas + _gas = m_builder.CreateTrunc(gas256, Type::Gas); llvm::Value* address = m_builder.CreateLoad(ret); address = Endianness::toNative(m_builder, address); return address; diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index d54eea754..8ac575338 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -19,29 +19,29 @@ namespace jit namespace // Helper functions { -uint64_t const c_stepGas = 1; -uint64_t const c_balanceGas = 20; -uint64_t const c_sha3Gas = 10; -uint64_t const c_sha3WordGas = 10; -uint64_t const c_sloadGas = 20; -uint64_t const c_sstoreSetGas = 300; -uint64_t const c_sstoreResetGas = 100; -uint64_t const c_sstoreRefundGas = 100; -uint64_t const c_createGas = 100; -uint64_t const c_createDataGas = 5; -uint64_t const c_callGas = 20; -uint64_t const c_expGas = 1; -uint64_t const c_expByteGas = 1; -uint64_t const c_memoryGas = 1; -uint64_t const c_txDataZeroGas = 1; -uint64_t const c_txDataNonZeroGas = 5; -uint64_t const c_txGas = 500; -uint64_t const c_logGas = 32; -uint64_t const c_logDataGas = 1; -uint64_t const c_logTopicGas = 32; -uint64_t const c_copyGas = 1; - -uint64_t getStepCost(Instruction inst) +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) { @@ -72,7 +72,7 @@ uint64_t getStepCost(Instruction inst) case Instruction::LOG3: case Instruction::LOG4: { - auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); + auto numTopics = static_cast(inst) - static_cast(Instruction::LOG0); return c_logGas + numTopics * c_logTopicGas; } } @@ -86,7 +86,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) { auto module = getModule(); - llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word}; + 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); @@ -94,15 +94,15 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) auto outOfGasBB = llvm::BasicBlock::Create(_builder.getContext(), "OutOfGas", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); - auto arg = m_gasCheckFunc->arg_begin(); - arg->setName("rt"); - ++arg; - arg->setName("cost"); - auto cost = arg; + 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(); - auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); + 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); @@ -110,7 +110,6 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); - gas = m_builder.CreateSub(gas, cost); m_runtimeManager.setGas(gas); m_builder.CreateRetVoid(); } @@ -120,7 +119,7 @@ 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::Word)}); + m_checkCall = createCall(m_gasCheckFunc, {m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Gas)}); } m_blockCost += getStepCost(_inst); @@ -128,6 +127,15 @@ void GasMeter::count(Instruction _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}); } @@ -137,12 +145,13 @@ void GasMeter::countExp(llvm::Value* _exponent) // lz - leading zeros // cost = ((256 - lz) + 7) / 8 - // OPT: All calculations can be done on 32/64 bits + // OPT: Can gas update be done in exp algorithm? auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); - auto lz = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); - auto sigBits = m_builder.CreateSub(Constant::get(256), lz); - auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, Constant::get(7)), Constant::get(8)); + 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); } @@ -155,8 +164,8 @@ void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValu 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, Constant::get(c_sstoreSetGas), Constant::get(c_sstoreResetGas), "cost"); - cost = m_builder.CreateSelect(isDelete, Constant::get(0), cost, "cost"); + 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); } @@ -179,13 +188,13 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); auto cost64 = m_builder.CreateNUWMul(getBuilder().getInt64(c_sha3WordGas), words64); - auto cost = getBuilder().CreateZExt(cost64, Type::Word); - count(cost); + count(cost64); } void GasMeter::giveBack(llvm::Value* _gas) { - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); + assert(_gas->getType() == Type::Word); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); } void GasMeter::commitCostBlock() @@ -200,7 +209,7 @@ void GasMeter::commitCostBlock() return; } - m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call + 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; } @@ -209,14 +218,8 @@ void GasMeter::commitCostBlock() void GasMeter::countMemory(llvm::Value* _additionalMemoryInWords) { - assert(_additionalMemoryInWords->getType() == Type::Word); static_assert(c_memoryGas == 1, "Memory gas cost has changed. Update GasMeter."); - auto gasMax256 = m_builder.CreateZExt(Constant::gasMax, Type::Word); - auto tooHigh = m_builder.CreateICmpUGT(_additionalMemoryInWords, gasMax256, "tooHigh"); - auto additionalMemoryInWords64 = m_builder.CreateTrunc(_additionalMemoryInWords, Type::Gas); - additionalMemoryInWords64 = m_builder.CreateSelect(tooHigh, Constant::gasMax, additionalMemoryInWords64, "additionalMemoryInWords"); - auto additionalMemoryInWords256 = m_builder.CreateZExt(additionalMemoryInWords64, Type::Word); - count(additionalMemoryInWords256); + count(_additionalMemoryInWords); } void GasMeter::countCopy(llvm::Value* _copyWords) diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h index 56da6eb9f..27f55253f 100644 --- a/evmjit/libevmjit/GasMeter.h +++ b/evmjit/libevmjit/GasMeter.h @@ -50,7 +50,7 @@ public: private: /// Cumulative gas cost of a block of instructions /// @TODO Handle overflow - uint64_t m_blockCost = 0; + int64_t m_blockCost = 0; llvm::CallInst* m_checkCall = nullptr; llvm::Function* m_gasCheckFunc = nullptr; diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 408f2dee3..1441f475a 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -216,15 +216,15 @@ llvm::Value* RuntimeManager::getJmpBuf() llvm::Value* RuntimeManager::getGas() { - auto value = get(RuntimeData::Gas); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + auto gas = get(RuntimeData::Gas); + assert(gas->getType() == Type::Gas); + return gas; } void RuntimeManager::setGas(llvm::Value* _gas) { - auto newGas = getBuilder().CreateTrunc(_gas, Type::Size); - set(RuntimeData::Gas, newGas); + assert(_gas->getType() == Type::Gas); + set(RuntimeData::Gas, _gas); } } From 494e96a89c2af3752942e4879d818a649ae1a776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:32:55 +0100 Subject: [PATCH 030/201] Pass gas counter to env_create as int64* --- libevmjit-cpp/Env.cpp | 9 ++++----- libevmjit/Compiler.cpp | 5 +---- libevmjit/Ext.cpp | 10 +++------- libevmjit/Ext.h | 2 +- libevmjit/RuntimeManager.cpp | 5 +++++ libevmjit/RuntimeManager.h | 3 ++- libevmjit/Type.cpp | 2 ++ libevmjit/Type.h | 1 + 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index f89897792..e279e1a56 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -46,16 +46,15 @@ extern "C" *o_hash = _env->blockhash(llvm2eth(*_number)); } - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + 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); - auto gas = llvm2eth(*io_gas); - OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); *o_address = address; } else diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b6206b8d8..c41fcb0bb 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -740,10 +740,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti _memory.require(initOff, initSize); _gasMeter.commitCostBlock(); - - auto gas = _runtimeManager.getGas(); - auto address = _ext.create(gas, endowment, initOff, initSize); - _runtimeManager.setGas(gas); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 28e10366c..dcc761062 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -41,7 +41,7 @@ std::array::value> const& getEnvFuncDescs() 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::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, 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::WordPtr, 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})}, @@ -126,16 +126,12 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) return Endianness::toNative(getBuilder(), hash); } -llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); - auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - gas256 = m_builder.CreateLoad(gas); // Return gas - _gas = m_builder.CreateTrunc(gas256, Type::Gas); + 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; diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 2601d32ab..b4ca30783 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -50,7 +50,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* call(llvm::Value*& _gas, 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); diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 1441f475a..6d6cc09a0 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -221,6 +221,11 @@ llvm::Value* RuntimeManager::getGas() return gas; } +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); +} + void RuntimeManager::setGas(llvm::Value* _gas) { assert(_gas->getType() == Type::Gas); diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index b5f3ca657..e483f67cd 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -23,7 +23,8 @@ public: llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); // TODO: Remove + llvm::Value* getGas(); + llvm::Value* getGasPtr(); llvm::Value* getCallData(); llvm::Value* getCode(); llvm::Value* getCodeSize(); diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 169691904..2bbb3fa6f 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -18,6 +18,7 @@ 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; @@ -38,6 +39,7 @@ void Type::init(llvm::LLVMContext& _context) 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); diff --git a/libevmjit/Type.h b/libevmjit/Type.h index cfac1e2c6..e7757abbf 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -24,6 +24,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; From ce8642787115011ae36c08d77d2413fed3db062d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:32:55 +0100 Subject: [PATCH 031/201] Pass gas counter to env_create as int64* --- evmjit/libevmjit-cpp/Env.cpp | 9 ++++----- evmjit/libevmjit/Compiler.cpp | 5 +---- evmjit/libevmjit/Ext.cpp | 10 +++------- evmjit/libevmjit/Ext.h | 2 +- evmjit/libevmjit/RuntimeManager.cpp | 5 +++++ evmjit/libevmjit/RuntimeManager.h | 3 ++- evmjit/libevmjit/Type.cpp | 2 ++ evmjit/libevmjit/Type.h | 1 + 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index f89897792..e279e1a56 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -46,16 +46,15 @@ extern "C" *o_hash = _env->blockhash(llvm2eth(*_number)); } - EXPORT void env_create(ExtVMFace* _env, i256* io_gas, i256* _endowment, byte* _initBeg, uint64_t _initSize, h256* o_address) + 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); - auto gas = llvm2eth(*io_gas); - OnOpFunc onOp {}; // TODO: Handle that thing - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, onOp), h256::AlignRight); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + *io_gas = static_cast(gas); *o_address = address; } else diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index b6206b8d8..c41fcb0bb 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -740,10 +740,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti _memory.require(initOff, initSize); _gasMeter.commitCostBlock(); - - auto gas = _runtimeManager.getGas(); - auto address = _ext.create(gas, endowment, initOff, initSize); - _runtimeManager.setGas(gas); + auto address = _ext.create(endowment, initOff, initSize); stack.push(address); break; } diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 28e10366c..dcc761062 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -41,7 +41,7 @@ std::array::value> const& getEnvFuncDescs() 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::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, 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::WordPtr, 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})}, @@ -126,16 +126,12 @@ llvm::Value* Ext::blockhash(llvm::Value* _number) return Endianness::toNative(getBuilder(), hash); } -llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) +llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) { - auto gas256 = m_builder.CreateZExt(_gas, Type::Word, "gas256"); - auto gas = byPtr(gas256); auto ret = getArgAlloca(); auto begin = m_memoryMan.getBytePtr(_initOff); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); - createCall(EnvFunc::create, {getRuntimeManager().getEnvPtr(), gas, byPtr(_endowment), begin, size, ret}); - gas256 = m_builder.CreateLoad(gas); // Return gas - _gas = m_builder.CreateTrunc(gas256, Type::Gas); + 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; diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index 2601d32ab..b4ca30783 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -50,7 +50,7 @@ public: llvm::Value* balance(llvm::Value* _address); llvm::Value* calldataload(llvm::Value* _index); - llvm::Value* create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); + llvm::Value* create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize); llvm::Value* call(llvm::Value*& _gas, 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); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 1441f475a..6d6cc09a0 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -221,6 +221,11 @@ llvm::Value* RuntimeManager::getGas() return gas; } +llvm::Value* RuntimeManager::getGasPtr() +{ + return getPtr(RuntimeData::Gas); +} + void RuntimeManager::setGas(llvm::Value* _gas) { assert(_gas->getType() == Type::Gas); diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index b5f3ca657..e483f67cd 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -23,7 +23,8 @@ public: llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); - llvm::Value* getGas(); // TODO: Remove + llvm::Value* getGas(); + llvm::Value* getGasPtr(); llvm::Value* getCallData(); llvm::Value* getCode(); llvm::Value* getCodeSize(); diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 169691904..2bbb3fa6f 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -18,6 +18,7 @@ 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; @@ -38,6 +39,7 @@ void Type::init(llvm::LLVMContext& _context) 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); diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index cfac1e2c6..e7757abbf 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -24,6 +24,7 @@ struct Type static llvm::IntegerType* Bool; static llvm::IntegerType* Size; static llvm::IntegerType* Gas; + static llvm::PointerType* GasPtr; static llvm::IntegerType* Byte; static llvm::PointerType* BytePtr; From 3cbe1186cc3f5c6d2a2a12b7a9e13699f772dc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:57:26 +0100 Subject: [PATCH 032/201] Pass gas counter to env_call as int64* --- libevmjit-cpp/Env.cpp | 9 ++++----- libevmjit/Compiler.cpp | 13 ++++++++----- libevmjit/Ext.cpp | 8 +++----- libevmjit/Ext.h | 2 +- libevmjit/GasMeter.cpp | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libevmjit-cpp/Env.cpp b/libevmjit-cpp/Env.cpp index e279e1a56..cdca56b99 100644 --- a/libevmjit-cpp/Env.cpp +++ b/libevmjit-cpp/Env.cpp @@ -61,7 +61,7 @@ extern "C" *o_address = {}; } - EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + 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) @@ -70,11 +70,10 @@ extern "C" auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; auto outRef = bytesConstRef{_outBeg, _outSize}; - OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); - auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); return ret; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index c41fcb0bb..b19a1479e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -748,7 +748,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::CALL: case Instruction::CALLCODE: { - auto gas = stack.pop(); + auto callGas256 = stack.pop(); auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); @@ -766,10 +766,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - _gasMeter.count(gas); - // TODO: pass gas to call as int64 - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); + 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; } diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index dcc761062..0a465bb80 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -42,7 +42,7 @@ std::array::value> const& getEnvFuncDescs() 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::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, 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()})}, @@ -137,17 +137,15 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V return address; } -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +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 gas = byPtr(_gas); 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(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); - _gas = m_builder.CreateLoad(gas); // Return gas + 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"); } diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index b4ca30783..8ad69ea6e 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -51,7 +51,7 @@ public: 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*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + 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); diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 8ac575338..9c02bce8e 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -193,8 +193,8 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) void GasMeter::giveBack(llvm::Value* _gas) { - assert(_gas->getType() == Type::Word); - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); + assert(_gas->getType() == Type::Gas); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } void GasMeter::commitCostBlock() From ee036d3c97b9f772769e12985eee46d3b008e3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 17:57:26 +0100 Subject: [PATCH 033/201] Pass gas counter to env_call as int64* --- evmjit/libevmjit-cpp/Env.cpp | 9 ++++----- evmjit/libevmjit/Compiler.cpp | 13 ++++++++----- evmjit/libevmjit/Ext.cpp | 8 +++----- evmjit/libevmjit/Ext.h | 2 +- evmjit/libevmjit/GasMeter.cpp | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index e279e1a56..cdca56b99 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -61,7 +61,7 @@ extern "C" *o_address = {}; } - EXPORT bool env_call(ExtVMFace* _env, i256* io_gas, h256* _receiveAddress, i256* _value, byte* _inBeg, uint64_t _inSize, byte* _outBeg, uint64_t _outSize, h256* _codeAddress) + 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) @@ -70,11 +70,10 @@ extern "C" auto receiveAddress = right160(*_receiveAddress); auto inRef = bytesConstRef{_inBeg, _inSize}; auto outRef = bytesConstRef{_outBeg, _outSize}; - OnOpFunc onOp {}; // TODO: Handle that thing auto codeAddress = right160(*_codeAddress); - auto gas = llvm2eth(*io_gas); - auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, onOp, {}, codeAddress); - *io_gas = eth2llvm(gas); + u256 gas = *io_gas; + auto ret = _env->call(receiveAddress, value, inRef, gas, outRef, {}, {}, codeAddress); + *io_gas = static_cast(gas); return ret; } diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index c41fcb0bb..b19a1479e 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -748,7 +748,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti case Instruction::CALL: case Instruction::CALLCODE: { - auto gas = stack.pop(); + auto callGas256 = stack.pop(); auto codeAddress = stack.pop(); auto value = stack.pop(); auto inOff = stack.pop(); @@ -766,10 +766,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti if (inst == Instruction::CALLCODE) receiveAddress = _runtimeManager.get(RuntimeData::Address); - _gasMeter.count(gas); - // TODO: pass gas to call as int64 - auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); - _gasMeter.giveBack(gas); + 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; } diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index dcc761062..0a465bb80 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -42,7 +42,7 @@ std::array::value> const& getEnvFuncDescs() 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::WordPtr, Type::WordPtr, Type::WordPtr, Type::BytePtr, Type::Size, 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()})}, @@ -137,17 +137,15 @@ llvm::Value* Ext::create(llvm::Value* _endowment, llvm::Value* _initOff, llvm::V return address; } -llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress) +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 gas = byPtr(_gas); 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(), gas, byPtr(receiveAddress), byPtr(_value), inBeg, inSize, outBeg, outSize, byPtr(codeAddress)}); - _gas = m_builder.CreateLoad(gas); // Return gas + 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"); } diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index b4ca30783..8ad69ea6e 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -51,7 +51,7 @@ public: 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*& _gas, llvm::Value* _receiveAddress, llvm::Value* _value, llvm::Value* _inOff, llvm::Value* _inSize, llvm::Value* _outOff, llvm::Value* _outSize, llvm::Value* _codeAddress); + 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); diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 8ac575338..9c02bce8e 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -193,8 +193,8 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) void GasMeter::giveBack(llvm::Value* _gas) { - assert(_gas->getType() == Type::Word); - m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), m_builder.CreateTrunc(_gas, Type::Gas))); + assert(_gas->getType() == Type::Gas); + m_runtimeManager.setGas(m_builder.CreateAdd(m_runtimeManager.getGas(), _gas)); } void GasMeter::commitCostBlock() From 73bf7087e7e976174701ec29beafbb42065b22a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 18:23:23 +0100 Subject: [PATCH 034/201] Do not check memory requirements when size is 0 --- libevmjit/Memory.cpp | 483 ++++++++++++++++++++++--------------------- 1 file changed, 244 insertions(+), 239 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c6f8a9ec0..1e9646f68 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,239 +1,244 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#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::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_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); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} - -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) -{ - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto 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"); - - 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"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_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::Value* Memory::loadWord(llvm::Value* _addr) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {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) -{ - createCall(m_require, {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 copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(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::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, 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(); - } -} +#include "Memory.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + m_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); + m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); + + m_require = createRequireFunc(_gasMeter); + m_loadWord = createFunc(false, Type::Word, _gasMeter); + m_storeWord = createFunc(true, Type::Word, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, _gasMeter); +} + +llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +{ + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + auto 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"); + + 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"); + _gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(m_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::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(m_storeByte, {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(m_require, {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 copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(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::lowPrecision); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); + auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, 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(); + } +} From 4c8ae3e707c8d32f65fc20505ef457133229eb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 18:23:23 +0100 Subject: [PATCH 035/201] Do not check memory requirements when size is 0 --- evmjit/libevmjit/Memory.cpp | 483 ++++++++++++++++++------------------ 1 file changed, 244 insertions(+), 239 deletions(-) diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index c6f8a9ec0..1e9646f68 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -1,239 +1,244 @@ -#include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#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::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_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); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} - -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) -{ - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto 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"); - - 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"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_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::Value* Memory::loadWord(llvm::Value* _addr) -{ - return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); -} - -void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) -{ - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); -} - -void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) -{ - auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); - createCall(m_storeByte, {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) -{ - createCall(m_require, {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 copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(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::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); - auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, 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(); - } -} +#include "Memory.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; + m_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); + m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); + + m_require = createRequireFunc(_gasMeter); + m_loadWord = createFunc(false, Type::Word, _gasMeter); + m_storeWord = createFunc(true, Type::Word, _gasMeter); + m_storeByte = createFunc(true, Type::Byte, _gasMeter); +} + +llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +{ + llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; + auto 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"); + + 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"); + _gasMeter.countMemory(newWords); + // Resize + m_builder.CreateStore(sizeRequired, sizePtr); + auto newData = m_builder.CreateCall2(m_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::Value* Memory::loadWord(llvm::Value* _addr) +{ + return createCall(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); +} + +void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) +{ + createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _word}); +} + +void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) +{ + auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); + createCall(m_storeByte, {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(m_require, {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 copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(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::lowPrecision); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); + auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); + auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); + auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); + auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants + auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, 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(); + } +} From 3505e832ee35066275e3fe6cd50ca2383696d8da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 19:01:12 +0100 Subject: [PATCH 036/201] Some tweaks in gas counting --- libevmjit/GasMeter.cpp | 5 ++--- libevmjit/Memory.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 9c02bce8e..eb06795f0 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -183,10 +183,9 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) assert(m_blockCost > 0); // SHA3 instruction is already counted // TODO: This round ups to 32 happens in many places - // FIXME: 64-bit arith used, but not verified static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); - auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + 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); } diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 1e9646f68..c212b2d1a 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -197,7 +197,8 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // Additional copy cost // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + 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: @@ -210,14 +211,12 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + 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 From 7cbb44faa11259827c18a5a849cc90927b042e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Feb 2015 19:01:12 +0100 Subject: [PATCH 037/201] Some tweaks in gas counting --- evmjit/libevmjit/GasMeter.cpp | 5 ++--- evmjit/libevmjit/Memory.cpp | 15 +++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 9c02bce8e..eb06795f0 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -183,10 +183,9 @@ void GasMeter::countSha3Data(llvm::Value* _dataLength) assert(m_blockCost > 0); // SHA3 instruction is already counted // TODO: This round ups to 32 happens in many places - // FIXME: 64-bit arith used, but not verified static_assert(c_sha3WordGas != 1, "SHA3 data cost has changed. Update GasMeter"); - auto dataLength64 = getBuilder().CreateTrunc(_dataLength, Type::lowPrecision); - auto words64 = m_builder.CreateUDiv(m_builder.CreateAdd(dataLength64, getBuilder().getInt64(31)), getBuilder().getInt64(32)); + 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); } diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index 1e9646f68..c212b2d1a 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -197,7 +197,8 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // Additional copy cost // TODO: This round ups to 32 happens in many places - auto copyWords = m_builder.CreateUDiv(m_builder.CreateAdd(_reqBytes, Constant::get(31)), Constant::get(32)); + 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: @@ -210,14 +211,12 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* // bytesToCopy = select(isOutsideData, 0, bytesToCopy0) auto isOutsideData = m_builder.CreateICmpUGE(_srcIdx, _srcSize); - auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::lowPrecision); - auto size64 = m_builder.CreateTrunc(_srcSize, Type::lowPrecision); + auto idx64 = m_builder.CreateTrunc(_srcIdx, Type::Size); + auto size64 = m_builder.CreateTrunc(_srcSize, Type::Size); auto dataLeftSize = m_builder.CreateNUWSub(size64, idx64); - auto reqBytes64 = m_builder.CreateTrunc(_reqBytes, Type::lowPrecision); - auto outOfBound = m_builder.CreateICmpUGT(reqBytes64, dataLeftSize); - auto bytesToCopyInner = m_builder.CreateSelect(outOfBound, dataLeftSize, reqBytes64); - auto zero64 = llvm::ConstantInt::get(Type::lowPrecision, 0); // TODO: Cache common constants - auto bytesToCopy = m_builder.CreateSelect(isOutsideData, zero64, bytesToCopyInner); + 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 From f281e5ea262636477d9640ab54497d0360bf5102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 13:45:18 +0100 Subject: [PATCH 038/201] Workaround for linker removing JIT callback functions --- libevmjit-cpp/JitVM.cpp | 16 +++++----------- libevmjit/Common.h | 2 ++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/libevmjit-cpp/JitVM.cpp b/libevmjit-cpp/JitVM.cpp index ab1a4cf2b..53282e3ae 100644 --- a/libevmjit-cpp/JitVM.cpp +++ b/libevmjit-cpp/JitVM.cpp @@ -11,6 +11,8 @@ 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; @@ -65,6 +67,9 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) 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; } @@ -75,14 +80,3 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) } } - -namespace -{ - // MSVS linker ignores export symbols in Env.cpp if nothing points at least one of them - extern "C" void env_sload(); - void linkerWorkaround() - { - env_sload(); - (void)&linkerWorkaround; // suppress unused function warning from GCC - } -} diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 9c9dfd8a2..20d9bdab3 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -44,6 +44,8 @@ enum class ReturnCode LLVMLinkError = -103, UnexpectedException = -111, + + LinkerWorkaround = -299, }; /// Representation of 256-bit value binary compatible with LLVM i256 From 62587cfd73c66a411ef97601f0e4a17bd288dd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 13:45:18 +0100 Subject: [PATCH 039/201] Workaround for linker removing JIT callback functions --- evmjit/libevmjit-cpp/JitVM.cpp | 16 +++++----------- evmjit/libevmjit/Common.h | 2 ++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index ab1a4cf2b..53282e3ae 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -11,6 +11,8 @@ 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; @@ -65,6 +67,9 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) 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; } @@ -75,14 +80,3 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) } } - -namespace -{ - // MSVS linker ignores export symbols in Env.cpp if nothing points at least one of them - extern "C" void env_sload(); - void linkerWorkaround() - { - env_sload(); - (void)&linkerWorkaround; // suppress unused function warning from GCC - } -} diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index 9c9dfd8a2..20d9bdab3 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -44,6 +44,8 @@ enum class ReturnCode LLVMLinkError = -103, UnexpectedException = -111, + + LinkerWorkaround = -299, }; /// Representation of 256-bit value binary compatible with LLVM i256 From 4391c9b27bf6a3ae61eadb797d14dfef096dc764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 15:18:09 +0100 Subject: [PATCH 040/201] Update README.md - add information about options --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 30ed2f489..a480e83dc 100644 --- a/README.md +++ b/README.md @@ -30,5 +30,14 @@ It can be used to substitute classic interpreter-like EVM Virtual Machine in Eth ### 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 From 625095473a6ea45dc45e244056affff4c9a3eb34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 17:00:58 +0100 Subject: [PATCH 041/201] Remove dead jump table block --- libevmjit/Compiler.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 1ce63d8ec..ad8a14fc7 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -91,6 +91,7 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) } } + // TODO: Create Stop basic block on demand m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } @@ -863,6 +864,18 @@ void Compiler::removeDeadBlocks() } } 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) From 970939ddb79b3896e1130791bd059af24e20b2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 18:21:04 +0100 Subject: [PATCH 042/201] Fix after-merge problems --- libevmjit/ExecutionEngine.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 904531a9e..69cf28afd 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -72,13 +72,6 @@ bool getEnvOption(char const* _name, bool _default) return std::strtol(var, nullptr, 10) != 0; } -bool getEnvOption(char const* _name, bool _default) -{ - auto var = std::getenv(_name); - if (!var) - return _default; - return std::strtol(var, nullptr, 10) != 0; - } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) From bb9df15d75281e9240b8ab5f21286948c00958d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 3 Feb 2015 19:32:27 +0100 Subject: [PATCH 043/201] Generate BuildInfo header and display some information about evmjit library on demand --- libevmjit/BuildInfo.h.in | 10 ++++++++++ libevmjit/CMakeLists.txt | 5 ++++- libevmjit/ExecutionEngine.cpp | 13 +++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 libevmjit/BuildInfo.h.in diff --git a/libevmjit/BuildInfo.h.in b/libevmjit/BuildInfo.h.in new file mode 100644 index 000000000..204b4d89b --- /dev/null +++ b/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/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index f88a5468b..330eaf3c8 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -47,14 +47,17 @@ 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}) +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}) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 69cf28afd..1402faacc 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "BuildInfo.gen.h" #include @@ -72,6 +73,16 @@ bool getEnvOption(char const* _name, bool _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) @@ -79,6 +90,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? static auto debugDumpModule = getEnvOption("EVMJIT_DUMP", false); static auto objectCacheEnabled = getEnvOption("EVMJIT_CACHE", true); + static auto infoShown = showInfo(); + (void) infoShown; auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; From 82972e47dfc3843d00cffe36bca2b3854cfbafd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 11:45:13 +0100 Subject: [PATCH 044/201] Start of stats collector --- evmjit/libevmjit/ExecStats.cpp | 22 ++++++++++ evmjit/libevmjit/ExecStats.h | 32 +++++++++++++++ evmjit/libevmjit/ExecutionEngine.cpp | 61 ++++++++++++++++++++++++++-- evmjit/libevmjit/ExecutionEngine.h | 8 ++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 evmjit/libevmjit/ExecStats.cpp create mode 100644 evmjit/libevmjit/ExecStats.h diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..e3f5293f8 --- /dev/null +++ b/evmjit/libevmjit/ExecStats.cpp @@ -0,0 +1,22 @@ +#include "ExecStats.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::execStarted() +{ + m_tp = std::chrono::high_resolution_clock::now(); +} + +void ExecStats::execEnded() +{ + execTime = std::chrono::high_resolution_clock::now() - m_tp; +} + +} +} +} diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h new file mode 100644 index 000000000..3ee730836 --- /dev/null +++ b/evmjit/libevmjit/ExecStats.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats +{ +public: + std::string id; + std::chrono::high_resolution_clock::duration compileTime; + std::chrono::high_resolution_clock::duration codegenTime; + std::chrono::high_resolution_clock::duration cacheLoadTime; + std::chrono::high_resolution_clock::duration execTime; + + void execStarted(); + void execEnded(); + +private: + std::chrono::high_resolution_clock::time_point m_tp; + +}; + +} +} +} diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 1402faacc..6c1bc5c3b 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -83,6 +83,50 @@ bool showInfo() return show; } +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector() + { + if (stats.empty()) + return; + + using d = decltype(ExecStats{}.execTime); + d total = d::zero(); + d max = d::zero(); + d min = d::max(); + + for (auto&& s : stats) + { + auto t = s->execTime; + total += t; + if (t < min) + min = t; + if (t > max) + max = t; + } + + using u = std::chrono::microseconds; + auto nTotal = std::chrono::duration_cast(total).count(); + auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); + auto nMax = std::chrono::duration_cast(max).count(); + auto nMin = std::chrono::duration_cast(min).count(); + + std::cout << "Total exec time: " << nTotal << " us" << std::endl + << "Averge exec time: " << nAverage << " us" << std::endl + << "Min exec time: " << nMin << " us" << std::endl + << "Max exec time: " << nMax << " us" << std::endl; + } +}; + +} + +void ExecutionEngine::collectStats() +{ + if (!m_stats) + m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -90,9 +134,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? 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; + static StatsCollector statsCollector; + + if (statsCollectingEnabled) + collectStats(); + auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? @@ -153,17 +203,22 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } assert(entryFuncPtr); - auto executionStartTime = std::chrono::high_resolution_clock::now(); + if (m_stats) + m_stats->execStarted(); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + + if (m_stats) + m_stats->execEnded(); + if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(m_stats)); return returnCode; } diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index c95bbfb62..e12f86af4 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -1,6 +1,8 @@ #pragma once +#include #include "RuntimeData.h" +#include "ExecStats.h" namespace dev { @@ -18,6 +20,10 @@ public: EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + void collectStats(); + + std::unique_ptr getStats(); + /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -25,6 +31,8 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; + + std::unique_ptr m_stats; }; } From d27352b8e1ea9507341c496ece2f31f5c8c14e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 11:45:13 +0100 Subject: [PATCH 045/201] Start of stats collector --- libevmjit/ExecStats.cpp | 22 +++++++++++++ libevmjit/ExecStats.h | 32 ++++++++++++++++++ libevmjit/ExecutionEngine.cpp | 61 +++++++++++++++++++++++++++++++++-- libevmjit/ExecutionEngine.h | 8 +++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 libevmjit/ExecStats.cpp create mode 100644 libevmjit/ExecStats.h diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp new file mode 100644 index 000000000..e3f5293f8 --- /dev/null +++ b/libevmjit/ExecStats.cpp @@ -0,0 +1,22 @@ +#include "ExecStats.h" + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +void ExecStats::execStarted() +{ + m_tp = std::chrono::high_resolution_clock::now(); +} + +void ExecStats::execEnded() +{ + execTime = std::chrono::high_resolution_clock::now() - m_tp; +} + +} +} +} diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h new file mode 100644 index 000000000..3ee730836 --- /dev/null +++ b/libevmjit/ExecStats.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace dev +{ +namespace eth +{ +namespace jit +{ + +class ExecStats +{ +public: + std::string id; + std::chrono::high_resolution_clock::duration compileTime; + std::chrono::high_resolution_clock::duration codegenTime; + std::chrono::high_resolution_clock::duration cacheLoadTime; + std::chrono::high_resolution_clock::duration execTime; + + void execStarted(); + void execEnded(); + +private: + std::chrono::high_resolution_clock::time_point m_tp; + +}; + +} +} +} diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 1402faacc..6c1bc5c3b 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -83,6 +83,50 @@ bool showInfo() return show; } +class StatsCollector +{ +public: + std::vector> stats; + + ~StatsCollector() + { + if (stats.empty()) + return; + + using d = decltype(ExecStats{}.execTime); + d total = d::zero(); + d max = d::zero(); + d min = d::max(); + + for (auto&& s : stats) + { + auto t = s->execTime; + total += t; + if (t < min) + min = t; + if (t > max) + max = t; + } + + using u = std::chrono::microseconds; + auto nTotal = std::chrono::duration_cast(total).count(); + auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); + auto nMax = std::chrono::duration_cast(max).count(); + auto nMin = std::chrono::duration_cast(min).count(); + + std::cout << "Total exec time: " << nTotal << " us" << std::endl + << "Averge exec time: " << nAverage << " us" << std::endl + << "Min exec time: " << nMin << " us" << std::endl + << "Max exec time: " << nMax << " us" << std::endl; + } +}; + +} + +void ExecutionEngine::collectStats() +{ + if (!m_stats) + m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -90,9 +134,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? 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; + static StatsCollector statsCollector; + + if (statsCollectingEnabled) + collectStats(); + auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? @@ -153,17 +203,22 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } assert(entryFuncPtr); - auto executionStartTime = std::chrono::high_resolution_clock::now(); + if (m_stats) + m_stats->execStarted(); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + + if (m_stats) + m_stats->execEnded(); + if (returnCode == ReturnCode::Return) { returnData = runtime.getReturnData(); // Save reference to return data std::swap(m_memory, runtime.getMemory()); // Take ownership of memory } - auto executionEndTime = std::chrono::high_resolution_clock::now(); - clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).count() << " ms\n"; + if (statsCollectingEnabled) + statsCollector.stats.push_back(std::move(m_stats)); return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index c95bbfb62..e12f86af4 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,6 +1,8 @@ #pragma once +#include #include "RuntimeData.h" +#include "ExecStats.h" namespace dev { @@ -18,6 +20,10 @@ public: EXPORT ReturnCode run(RuntimeData* _data, Env* _env); + void collectStats(); + + std::unique_ptr getStats(); + /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -25,6 +31,8 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; + + std::unique_ptr m_stats; }; } From b22f672f0bfd8c1dcb1face3e3b551fe80027db3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 13:09:55 +0100 Subject: [PATCH 046/201] Move mul function to LLVM --- evmjit/libevmjit/Arith256.cpp | 94 ++++++++++++++++++++--------------- evmjit/libevmjit/Arith256.h | 11 +--- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 2ec227dcc..0345a4854 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -5,6 +5,7 @@ #include #include + #include namespace dev @@ -16,20 +17,7 @@ namespace jit Arith256::Arith256(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) -{ - using namespace llvm; - - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); - - using Linkage = GlobalValue::LinkageTypes; - - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); -} +{} void Arith256::debug(llvm::Value* _value, char _c) { @@ -41,6 +29,54 @@ void Arith256::debug(llvm::Value* _value, char _c) createCall(m_debug, {_value, 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 m_mul; +} + llvm::Function* Arith256::getDivFunc(llvm::Type* _type) { auto& func = _type == Type::Word ? m_div : m_div512; @@ -135,7 +171,7 @@ 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, "arith.exp", getModule()); + 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"); @@ -159,9 +195,6 @@ llvm::Function* Arith256::getExpFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1"); - auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2"); - auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3"); m_builder.CreateBr(headerBB); m_builder.SetInsertPoint(headerBB); @@ -176,20 +209,14 @@ llvm::Function* Arith256::getExpFunc() m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(r, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto r0 = m_builder.CreateLoad(a3, "r0"); + 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); - m_builder.CreateStore(b, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto b1 = m_builder.CreateLoad(a3, "b1"); + auto b1 = createCall(getMulFunc(), {b, b}); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); m_builder.CreateBr(headerBB); @@ -273,17 +300,9 @@ llvm::Function* Arith256::getMulModFunc() return m_mulmod; } -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mul, _arg1, _arg2); + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) @@ -496,11 +515,6 @@ extern "C" std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) - { - *o_result = mul(*_arg1, *_arg2); - } - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) { *o_result = mul512(*_arg1, *_arg2); diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index 5852137f8..f8f1c9eb2 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/libevmjit/Arith256.h @@ -24,26 +24,19 @@ public: void debug(llvm::Value* _value, char _c); private: + llvm::Function* getMulFunc(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - - llvm::Function* m_mul; - + llvm::Function* m_mul = 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; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; }; From d58f35343bb16630d751188778e19d8c5dd09877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 13:09:55 +0100 Subject: [PATCH 047/201] Move mul function to LLVM --- libevmjit/Arith256.cpp | 94 ++++++++++++++++++++++++------------------ libevmjit/Arith256.h | 11 +---- 2 files changed, 56 insertions(+), 49 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 2ec227dcc..0345a4854 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -5,6 +5,7 @@ #include #include + #include namespace dev @@ -16,20 +17,7 @@ namespace jit Arith256::Arith256(llvm::IRBuilder<>& _builder) : CompilerHelper(_builder) -{ - using namespace llvm; - - m_result = m_builder.CreateAlloca(Type::Word, nullptr, "arith.result"); - m_arg1 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg1"); - m_arg2 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg2"); - m_arg3 = m_builder.CreateAlloca(Type::Word, nullptr, "arith.arg3"); - - using Linkage = GlobalValue::LinkageTypes; - - llvm::Type* arg2Types[] = {Type::WordPtr, Type::WordPtr, Type::WordPtr}; - - m_mul = Function::Create(FunctionType::get(Type::Void, arg2Types, false), Linkage::ExternalLinkage, "arith_mul", getModule()); -} +{} void Arith256::debug(llvm::Value* _value, char _c) { @@ -41,6 +29,54 @@ void Arith256::debug(llvm::Value* _value, char _c) createCall(m_debug, {_value, 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 m_mul; +} + llvm::Function* Arith256::getDivFunc(llvm::Type* _type) { auto& func = _type == Type::Word ? m_div : m_div512; @@ -135,7 +171,7 @@ 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, "arith.exp", getModule()); + 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"); @@ -159,9 +195,6 @@ llvm::Function* Arith256::getExpFunc() auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", m_exp); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word, nullptr, "a1"); - auto a2 = m_builder.CreateAlloca(Type::Word, nullptr, "a2"); - auto a3 = m_builder.CreateAlloca(Type::Word, nullptr, "a3"); m_builder.CreateBr(headerBB); m_builder.SetInsertPoint(headerBB); @@ -176,20 +209,14 @@ llvm::Function* Arith256::getExpFunc() m_builder.CreateCondBr(eOdd, updateBB, continueBB); m_builder.SetInsertPoint(updateBB); - m_builder.CreateStore(r, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto r0 = m_builder.CreateLoad(a3, "r0"); + 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); - m_builder.CreateStore(b, a1); - m_builder.CreateStore(b, a2); - createCall(m_mul, {a1, a2, a3}); - auto b1 = m_builder.CreateLoad(a3, "b1"); + auto b1 = createCall(getMulFunc(), {b, b}); auto e1 = m_builder.CreateLShr(e, Constant::get(1), "e1"); m_builder.CreateBr(headerBB); @@ -273,17 +300,9 @@ llvm::Function* Arith256::getMulModFunc() return m_mulmod; } -llvm::Value* Arith256::binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2) -{ - m_builder.CreateStore(_arg1, m_arg1); - m_builder.CreateStore(_arg2, m_arg2); - m_builder.CreateCall3(_op, m_arg1, m_arg2, m_result); - return m_builder.CreateLoad(m_result); -} - llvm::Value* Arith256::mul(llvm::Value* _arg1, llvm::Value* _arg2) { - return binaryOp(m_mul, _arg1, _arg2); + return createCall(getMulFunc(), {_arg1, _arg2}); } std::pair Arith256::div(llvm::Value* _arg1, llvm::Value* _arg2) @@ -496,11 +515,6 @@ extern "C" std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - EXPORT void arith_mul(uint256* _arg1, uint256* _arg2, uint256* o_result) - { - *o_result = mul(*_arg1, *_arg2); - } - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) { *o_result = mul512(*_arg1, *_arg2); diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 5852137f8..f8f1c9eb2 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -24,26 +24,19 @@ public: void debug(llvm::Value* _value, char _c); private: + llvm::Function* getMulFunc(); llvm::Function* getDivFunc(llvm::Type* _type); llvm::Function* getExpFunc(); llvm::Function* getAddModFunc(); llvm::Function* getMulModFunc(); - llvm::Value* binaryOp(llvm::Function* _op, llvm::Value* _arg1, llvm::Value* _arg2); - - llvm::Function* m_mul; - + llvm::Function* m_mul = 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; - - llvm::Value* m_arg1; - llvm::Value* m_arg2; - llvm::Value* m_arg3; - llvm::Value* m_result; }; From 553c47ebcf34b031f2a60c6501b015e418b6231e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 14:16:17 +0100 Subject: [PATCH 048/201] Move mul512 function to LLVM --- evmjit/libevmjit/Arith256.cpp | 209 +++++++--------------------------- evmjit/libevmjit/Arith256.h | 2 + 2 files changed, 42 insertions(+), 169 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 0345a4854..a77050adc 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -74,7 +74,45 @@ llvm::Function* Arith256::getMulFunc() p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); m_builder.CreateRet(p); } - return m_mul; + 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, "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 i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + + auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + + 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) @@ -271,9 +309,6 @@ llvm::Function* Arith256::getMulModFunc() m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); auto i512Ty = m_builder.getIntNTy(512); - llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()}; - auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule()); - auto x = &m_mulmod->getArgumentList().front(); x->setName("x"); auto y = x->getNextNode(); @@ -285,13 +320,7 @@ llvm::Function* Arith256::getMulModFunc() auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word); - auto a2 = m_builder.CreateAlloca(Type::Word); - auto a3 = m_builder.CreateAlloca(i512Ty); - m_builder.CreateStore(x, a1); - m_builder.CreateStore(y, a2); - createCall(mul512, {a1, a2, a3}); - auto p = m_builder.CreateLoad(a3, "p"); + 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"); @@ -350,157 +379,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } -namespace -{ -#ifdef __SIZEOF_INT128__ - using uint128 = __uint128_t; -#else - struct uint128 - { - uint64_t lo = 0; - uint64_t hi = 0; - - uint128(uint64_t lo) : lo(lo) {} - - uint128 operator+(uint128 a) - { - uint128 r = 0; - bool overflow = lo > std::numeric_limits::max() - a.lo; - r.lo = lo + a.lo; - r.hi = hi + a.hi + overflow; - return r; - } - - uint128 operator>>(int s) - { - assert(s == 64); - return hi; - } - - uint128 operator<<(int s) - { - assert(s == 64); - uint128 r = 0; - r.hi = lo; - return r; - } - - explicit operator uint64_t() { return lo; } - - static uint128 mul(uint64_t a, uint64_t b) - { - auto x_lo = 0xFFFFFFFF & a; - auto y_lo = 0xFFFFFFFF & b; - auto x_hi = a >> 32; - auto y_hi = b >> 32; - - auto t1 = x_lo * y_lo; - auto t2 = x_lo * y_hi; - auto t3 = x_hi * y_lo; - auto t4 = x_hi * y_hi; - - auto lo = (uint32_t)t1; - auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3; - auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32); - - uint128 r = 0; - r.lo = (uint64_t)lo + (mid << 32); - r.hi = hi; - return r; - } - - uint128 operator*(uint128 a) - { - auto t1 = mul(lo, a.lo); - auto t2 = mul(lo, a.hi); - auto t3 = mul(hi, a.lo); - return t1 + (t2 << 64) + (t3 << 64); - } - }; -#endif - - struct uint256 - { - uint64_t lo = 0; - uint64_t mid = 0; - uint128 hi = 0; - - uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} - uint256(uint128 n) - { - lo = (uint64_t) n; - mid = (uint64_t) (n >> 64); - } - - explicit operator uint128() - { - uint128 r = lo; - r |= ((uint128) mid) << 64; - return r; - } - - uint256 operator+(uint256 a) - { - auto _lo = (uint128) lo + a.lo; - auto _mid = (uint128) mid + a.mid + (_lo >> 64); - auto _hi = hi + a.hi + (_mid >> 64); - return {(uint64_t)_lo, (uint64_t)_mid, _hi}; - } - - uint256 lo2hi() - { - hi = (uint128)*this; - lo = 0; - mid = 0; - return *this; - } - }; - - struct uint512 - { - uint128 lo; - uint128 mid; - uint256 hi; - }; - - uint256 mul(uint256 x, uint256 y) - { - auto t1 = (uint128) x.lo * y.lo; - auto t2 = (uint128) x.lo * y.mid; - auto t3 = (uint128) x.lo * y.hi; - auto t4 = (uint128) x.mid * y.lo; - auto t5 = (uint128) x.mid * y.mid; - auto t6 = (uint128) x.mid * y.hi; - auto t7 = x.hi * y.lo; - auto t8 = x.hi * y.mid; - - auto lo = (uint64_t) t1; - auto m1 = (t1 >> 64) + (uint64_t) t2; - auto m2 = (uint64_t) m1; - auto mid = (uint128) m2 + (uint64_t) t4; - auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7 - + (t8 << 64) + (m1 >> 64) + (mid >> 64); - - return {lo, (uint64_t)mid, hi}; - } - - uint512 mul512(uint256 x, uint256 y) - { - auto x_lo = (uint128) x; - auto y_lo = (uint128) y; - - auto t1 = mul(x_lo, y_lo); - auto t2 = mul(x_lo, y.hi); - auto t3 = mul(x.hi, y_lo); - auto t4 = mul(x.hi, y.hi); - - auto lo = (uint128) t1; - auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3; - auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi; - - return {lo, (uint128)mid, hi}; - } -} } } @@ -508,15 +386,8 @@ namespace extern "C" { - using namespace dev::eth::jit; - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) - { - *o_result = mul512(*_arg1, *_arg2); - } } diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index f8f1c9eb2..2513ca568 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/libevmjit/Arith256.h @@ -25,12 +25,14 @@ public: 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; From 96c89cbedc7fb4b93e3b60a1032d11b09c46edc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 14:16:17 +0100 Subject: [PATCH 049/201] Move mul512 function to LLVM --- libevmjit/Arith256.cpp | 209 ++++++++--------------------------------- libevmjit/Arith256.h | 2 + 2 files changed, 42 insertions(+), 169 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 0345a4854..a77050adc 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -74,7 +74,45 @@ llvm::Function* Arith256::getMulFunc() p = m_builder.CreateAdd(p, m_builder.CreateShl(m_builder.CreateZExt(t8, i256), Constant::get(192))); m_builder.CreateRet(p); } - return m_mul; + 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, "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 i128 = m_builder.getIntNTy(128); + auto i256 = Type::Word; + auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); + auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); + auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); + auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + + auto t1 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); + auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); + auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_hi, i256)}); + + 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) @@ -271,9 +309,6 @@ llvm::Function* Arith256::getMulModFunc() m_mulmod = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "mulmod", getModule()); auto i512Ty = m_builder.getIntNTy(512); - llvm::Type* mul512ArgTypes[] = {Type::WordPtr, Type::WordPtr, i512Ty->getPointerTo()}; - auto mul512 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, mul512ArgTypes, false), llvm::Function::ExternalLinkage, "arith_mul512", getModule()); - auto x = &m_mulmod->getArgumentList().front(); x->setName("x"); auto y = x->getNextNode(); @@ -285,13 +320,7 @@ llvm::Function* Arith256::getMulModFunc() auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mulmod); m_builder.SetInsertPoint(entryBB); - auto a1 = m_builder.CreateAlloca(Type::Word); - auto a2 = m_builder.CreateAlloca(Type::Word); - auto a3 = m_builder.CreateAlloca(i512Ty); - m_builder.CreateStore(x, a1); - m_builder.CreateStore(y, a2); - createCall(mul512, {a1, a2, a3}); - auto p = m_builder.CreateLoad(a3, "p"); + 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"); @@ -350,157 +379,6 @@ llvm::Value* Arith256::mulmod(llvm::Value* _arg1, llvm::Value* _arg2, llvm::Valu return createCall(getMulModFunc(), {_arg1, _arg2, _arg3}); } -namespace -{ -#ifdef __SIZEOF_INT128__ - using uint128 = __uint128_t; -#else - struct uint128 - { - uint64_t lo = 0; - uint64_t hi = 0; - - uint128(uint64_t lo) : lo(lo) {} - - uint128 operator+(uint128 a) - { - uint128 r = 0; - bool overflow = lo > std::numeric_limits::max() - a.lo; - r.lo = lo + a.lo; - r.hi = hi + a.hi + overflow; - return r; - } - - uint128 operator>>(int s) - { - assert(s == 64); - return hi; - } - - uint128 operator<<(int s) - { - assert(s == 64); - uint128 r = 0; - r.hi = lo; - return r; - } - - explicit operator uint64_t() { return lo; } - - static uint128 mul(uint64_t a, uint64_t b) - { - auto x_lo = 0xFFFFFFFF & a; - auto y_lo = 0xFFFFFFFF & b; - auto x_hi = a >> 32; - auto y_hi = b >> 32; - - auto t1 = x_lo * y_lo; - auto t2 = x_lo * y_hi; - auto t3 = x_hi * y_lo; - auto t4 = x_hi * y_hi; - - auto lo = (uint32_t)t1; - auto mid = (uint64_t)(t1 >> 32) + (uint32_t)t2 + (uint32_t)t3; - auto hi = (uint64_t)(t2 >> 32) + (t3 >> 32) + t4 + (mid >> 32); - - uint128 r = 0; - r.lo = (uint64_t)lo + (mid << 32); - r.hi = hi; - return r; - } - - uint128 operator*(uint128 a) - { - auto t1 = mul(lo, a.lo); - auto t2 = mul(lo, a.hi); - auto t3 = mul(hi, a.lo); - return t1 + (t2 << 64) + (t3 << 64); - } - }; -#endif - - struct uint256 - { - uint64_t lo = 0; - uint64_t mid = 0; - uint128 hi = 0; - - uint256(uint64_t lo, uint64_t mid, uint128 hi): lo(lo), mid(mid), hi(hi) {} - uint256(uint128 n) - { - lo = (uint64_t) n; - mid = (uint64_t) (n >> 64); - } - - explicit operator uint128() - { - uint128 r = lo; - r |= ((uint128) mid) << 64; - return r; - } - - uint256 operator+(uint256 a) - { - auto _lo = (uint128) lo + a.lo; - auto _mid = (uint128) mid + a.mid + (_lo >> 64); - auto _hi = hi + a.hi + (_mid >> 64); - return {(uint64_t)_lo, (uint64_t)_mid, _hi}; - } - - uint256 lo2hi() - { - hi = (uint128)*this; - lo = 0; - mid = 0; - return *this; - } - }; - - struct uint512 - { - uint128 lo; - uint128 mid; - uint256 hi; - }; - - uint256 mul(uint256 x, uint256 y) - { - auto t1 = (uint128) x.lo * y.lo; - auto t2 = (uint128) x.lo * y.mid; - auto t3 = (uint128) x.lo * y.hi; - auto t4 = (uint128) x.mid * y.lo; - auto t5 = (uint128) x.mid * y.mid; - auto t6 = (uint128) x.mid * y.hi; - auto t7 = x.hi * y.lo; - auto t8 = x.hi * y.mid; - - auto lo = (uint64_t) t1; - auto m1 = (t1 >> 64) + (uint64_t) t2; - auto m2 = (uint64_t) m1; - auto mid = (uint128) m2 + (uint64_t) t4; - auto hi = (t2 >> 64) + t3 + (t4 >> 64) + t5 + (t6 << 64) + t7 - + (t8 << 64) + (m1 >> 64) + (mid >> 64); - - return {lo, (uint64_t)mid, hi}; - } - - uint512 mul512(uint256 x, uint256 y) - { - auto x_lo = (uint128) x; - auto y_lo = (uint128) y; - - auto t1 = mul(x_lo, y_lo); - auto t2 = mul(x_lo, y.hi); - auto t3 = mul(x.hi, y_lo); - auto t4 = mul(x.hi, y.hi); - - auto lo = (uint128) t1; - auto mid = (uint256) t1.hi + (uint128) t2 + (uint128) t3; - auto hi = (uint256)t2.hi + t3.hi + t4 + mid.hi; - - return {lo, (uint128)mid, hi}; - } -} } } @@ -508,15 +386,8 @@ namespace extern "C" { - using namespace dev::eth::jit; - EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; } - - EXPORT void arith_mul512(uint256* _arg1, uint256* _arg2, uint512* o_result) - { - *o_result = mul512(*_arg1, *_arg2); - } } diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index f8f1c9eb2..2513ca568 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -25,12 +25,14 @@ public: 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; From 99b7607ae295f09063fc7164b66bc7c3bfa2279b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 16:47:38 +0100 Subject: [PATCH 050/201] Use code (and code size) as constants --- evmjit/libevmjit/Compiler.cpp | 2 +- evmjit/libevmjit/ExecutionEngine.cpp | 1 + evmjit/libevmjit/RuntimeManager.cpp | 13 ++++++++----- evmjit/libevmjit/RuntimeManager.h | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index b9d0143f1..02e2e920a 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -142,7 +142,7 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder); + RuntimeManager runtimeManager(m_builder, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 6c1bc5c3b..bc1202e79 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -174,6 +174,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) std::unique_ptr memoryManager(new llvm::SectionMemoryManager); builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); + builder.setVerifyModules(true); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 6d6cc09a0..98386e1fe 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -87,7 +87,10 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) { m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); @@ -191,14 +194,14 @@ llvm::Value* RuntimeManager::getCallData() llvm::Value* RuntimeManager::getCode() { - return get(RuntimeData::Code); + // 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() { - auto value = get(RuntimeData::CodeSize); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + return Constant::get(m_codeEnd - m_codeBegin); } llvm::Value* RuntimeManager::getCallDataSize() diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index e483f67cd..b3ce6f997 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -15,11 +15,11 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder); + RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? + llvm::Value* getEnvPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -47,6 +47,9 @@ private: llvm::Function* m_longjmp = nullptr; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; }; } From f70b7f5fd2db6f1d07780bd51fe6c785a2ed95be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 16:47:38 +0100 Subject: [PATCH 051/201] Use code (and code size) as constants --- libevmjit/Compiler.cpp | 2 +- libevmjit/ExecutionEngine.cpp | 1 + libevmjit/RuntimeManager.cpp | 13 ++++++++----- libevmjit/RuntimeManager.h | 7 +++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index b9d0143f1..02e2e920a 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -142,7 +142,7 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera createBasicBlocks(_begin, _end); // Init runtime structures. - RuntimeManager runtimeManager(m_builder); + RuntimeManager runtimeManager(m_builder, _begin, _end); GasMeter gasMeter(m_builder, runtimeManager); Memory memory(runtimeManager, gasMeter); Ext ext(runtimeManager, memory); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 6c1bc5c3b..bc1202e79 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -174,6 +174,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) std::unique_ptr memoryManager(new llvm::SectionMemoryManager); builder.setMCJITMemoryManager(memoryManager.get()); builder.setOptLevel(llvm::CodeGenOpt::None); + builder.setVerifyModules(true); auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 6d6cc09a0..98386e1fe 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -87,7 +87,10 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) +RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): + CompilerHelper(_builder), + m_codeBegin(_codeBegin), + m_codeEnd(_codeEnd) { m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); @@ -191,14 +194,14 @@ llvm::Value* RuntimeManager::getCallData() llvm::Value* RuntimeManager::getCode() { - return get(RuntimeData::Code); + // 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() { - auto value = get(RuntimeData::CodeSize); - assert(value->getType() == Type::Size); - return getBuilder().CreateZExt(value, Type::Word); + return Constant::get(m_codeEnd - m_codeBegin); } llvm::Value* RuntimeManager::getCallDataSize() diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index e483f67cd..b3ce6f997 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -15,11 +15,11 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder); + RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); - llvm::Value* getEnvPtr(); // TODO: Can we make it const? + llvm::Value* getEnvPtr(); llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(Instruction _inst); @@ -47,6 +47,9 @@ private: llvm::Function* m_longjmp = nullptr; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; + + code_iterator m_codeBegin = {}; + code_iterator m_codeEnd = {}; }; } From 4c58e6ffa59ab2a3aaa30ff645dbfff831b9afcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 18:33:27 +0100 Subject: [PATCH 052/201] Create memory helper functions on demand --- evmjit/libevmjit/Memory.cpp | 171 ++++++++++++++++++++---------------- evmjit/libevmjit/Memory.h | 15 ++-- 2 files changed, 106 insertions(+), 80 deletions(-) diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index c212b2d1a..6a46fa8ca 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -26,78 +26,77 @@ namespace jit Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_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); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} +{} -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +llvm::Function* Memory::getRequireFunc() { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto 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"); - - 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"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_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(); + 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; } @@ -143,21 +142,45 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet 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(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _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(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); } llvm::Value* Memory::getData() @@ -187,7 +210,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) if (!constant->getValue()) return; } - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h index ed9c51805..e8edce735 100644 --- a/evmjit/libevmjit/Memory.h +++ b/evmjit/libevmjit/Memory.h @@ -31,13 +31,16 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; + 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; }; } From 3fe31f0b800232a0602cc63cb02252f112a2d98e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 4 Feb 2015 18:33:27 +0100 Subject: [PATCH 053/201] Create memory helper functions on demand --- libevmjit/Memory.cpp | 171 ++++++++++++++++++++++++------------------- libevmjit/Memory.h | 15 ++-- 2 files changed, 106 insertions(+), 80 deletions(-) diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index c212b2d1a..6a46fa8ca 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -26,78 +26,77 @@ namespace jit Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed m_gasMeter(_gasMeter) -{ - llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr}; - m_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); - m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); - - m_require = createRequireFunc(_gasMeter); - m_loadWord = createFunc(false, Type::Word, _gasMeter); - m_storeWord = createFunc(true, Type::Word, _gasMeter); - m_storeByte = createFunc(true, Type::Byte, _gasMeter); -} +{} -llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter) +llvm::Function* Memory::getRequireFunc() { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word}; - auto 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"); - - 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"); - _gasMeter.countMemory(newWords); - // Resize - m_builder.CreateStore(sizeRequired, sizePtr); - auto newData = m_builder.CreateCall2(m_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(); + 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; } @@ -143,21 +142,45 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet 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(m_loadWord, {getRuntimeManager().getRuntimePtr(), _addr}); + return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr}); } void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) { - createCall(m_storeWord, {getRuntimeManager().getRuntimePtr(), _addr, _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(m_storeByte, {getRuntimeManager().getRuntimePtr(), _addr, byte}); + createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte}); } llvm::Value* Memory::getData() @@ -187,7 +210,7 @@ void Memory::require(llvm::Value* _offset, llvm::Value* _size) if (!constant->getValue()) return; } - createCall(m_require, {getRuntimeManager().getRuntimePtr(), _offset, _size}); + createCall(getRequireFunc(), {getRuntimeManager().getRuntimePtr(), _offset, _size}); } void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index ed9c51805..e8edce735 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -31,13 +31,16 @@ private: GasMeter& m_gasMeter; llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); - llvm::Function* createRequireFunc(GasMeter& _gasMeter); - llvm::Function* m_resize; - llvm::Function* m_require; - llvm::Function* m_loadWord; - llvm::Function* m_storeWord; - llvm::Function* m_storeByte; + 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; }; } From f203843114a192dee037aad2a5a614e1bb3b5b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:04:54 +0100 Subject: [PATCH 054/201] Stats for execution states times --- evmjit/libevmjit/Cache.cpp | 29 +++++++---- evmjit/libevmjit/Cache.h | 7 +-- evmjit/libevmjit/ExecStats.cpp | 77 ++++++++++++++++++++++++++-- evmjit/libevmjit/ExecStats.h | 27 +++++++--- evmjit/libevmjit/ExecutionEngine.cpp | 67 +++++------------------- evmjit/libevmjit/ExecutionEngine.h | 35 ++++++++++--- 6 files changed, 153 insertions(+), 89 deletions(-) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 0e6fb517a..305b97d5c 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "ExecutionEngine.h" namespace dev { @@ -18,20 +19,25 @@ namespace jit //#define LOG(...) std::cerr << "CACHE " #define LOG(...) std::ostream(nullptr) -ObjectCache* Cache::getObjectCache() +namespace { - static ObjectCache objectCache; - return &objectCache; + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; } -namespace +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) { - llvm::MemoryBuffer* lastObject; + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; } std::unique_ptr Cache::getObject(std::string const& id) { - assert(!lastObject); + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); @@ -51,11 +57,11 @@ std::unique_ptr Cache::getObject(std::string const& id) #endif if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + 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 (lastObject) // if object found create fake module + if (g_lastObject) // if object found create fake module { auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); @@ -67,6 +73,9 @@ std::unique_ptr Cache::getObject(std::string const& id) 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); @@ -84,8 +93,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) { - auto o = lastObject; - lastObject = nullptr; + auto o = g_lastObject; + g_lastObject = nullptr; return o; } diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h index 1cad537cd..d7b32c651 100644 --- a/evmjit/libevmjit/Cache.h +++ b/evmjit/libevmjit/Cache.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -11,6 +10,7 @@ namespace eth { namespace jit { +class ExecutionEngineListener; class ObjectCache : public llvm::ObjectCache { @@ -23,16 +23,13 @@ public: /// 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; - -private: - std::unordered_map> m_map; }; class Cache { public: - static ObjectCache* getObjectCache(); + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); }; diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index e3f5293f8..deb322521 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -1,4 +1,7 @@ #include "ExecStats.h" +#include +#include +#include namespace dev { @@ -7,14 +10,80 @@ namespace eth namespace jit { -void ExecStats::execStarted() +void ExecStats::stateChanged(ExecState _state) { - m_tp = std::chrono::high_resolution_clock::now(); + assert(m_state != ExecState::Finished); + 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; } -void ExecStats::execEnded() +namespace { - execTime = std::chrono::high_resolution_clock::now() - m_tp; +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::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 index 3ee730836..284ecad7b 100644 --- a/evmjit/libevmjit/ExecStats.h +++ b/evmjit/libevmjit/ExecStats.h @@ -2,6 +2,7 @@ #include #include +#include "ExecutionEngine.h" namespace dev { @@ -10,21 +11,31 @@ namespace eth namespace jit { -class ExecStats +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; - std::chrono::high_resolution_clock::duration compileTime; - std::chrono::high_resolution_clock::duration codegenTime; - std::chrono::high_resolution_clock::duration cacheLoadTime; - std::chrono::high_resolution_clock::duration execTime; + duration time[(int)ExecState::Finished] = {}; - void execStarted(); - void execEnded(); + void stateChanged(ExecState _state) override; private: - std::chrono::high_resolution_clock::time_point m_tp; + 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 index bc1202e79..dd545cd03 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "ExecStats.h" #include "BuildInfo.gen.h" #include @@ -83,50 +84,6 @@ bool showInfo() return show; } -class StatsCollector -{ -public: - std::vector> stats; - - ~StatsCollector() - { - if (stats.empty()) - return; - - using d = decltype(ExecStats{}.execTime); - d total = d::zero(); - d max = d::zero(); - d min = d::max(); - - for (auto&& s : stats) - { - auto t = s->execTime; - total += t; - if (t < min) - min = t; - if (t > max) - max = t; - } - - using u = std::chrono::microseconds; - auto nTotal = std::chrono::duration_cast(total).count(); - auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); - auto nMax = std::chrono::duration_cast(max).count(); - auto nMin = std::chrono::duration_cast(min).count(); - - std::cout << "Total exec time: " << nTotal << " us" << std::endl - << "Averge exec time: " << nAverage << " us" << std::endl - << "Min exec time: " << nMin << " us" << std::endl - << "Max exec time: " << nMax << " us" << std::endl; - } -}; - -} - -void ExecutionEngine::collectStats() -{ - if (!m_stats) - m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -140,8 +97,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static StatsCollector statsCollector; - if (statsCollectingEnabled) - collectStats(); + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; @@ -155,12 +112,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } else { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; std::unique_ptr module; if (objectCache) module = Cache::getObject(mainFuncName); if (!module) + { + listener->stateChanged(ExecState::Compilation); module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + } if (debugDumpModule) module->dump(); if (!ee) @@ -190,6 +150,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (objectCache) ee->setObjectCache(objectCache); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else @@ -198,28 +159,26 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { ee->addModule(module.get()); module.release(); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } } } assert(entryFuncPtr); - if (m_stats) - m_stats->execStarted(); - + listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); - - if (m_stats) - m_stats->execEnded(); + 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(m_stats)); + statsCollector.stats.push_back(std::move(listener)); return returnCode; } diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index e12f86af4..101475b11 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -2,7 +2,6 @@ #include #include "RuntimeData.h" -#include "ExecStats.h" namespace dev { @@ -11,19 +10,41 @@ 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; - void operator=(ExecutionEngine) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; EXPORT ReturnCode run(RuntimeData* _data, Env* _env); - void collectStats(); - - std::unique_ptr getStats(); - /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -31,8 +52,6 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; - - std::unique_ptr m_stats; }; } From 83701a2fcda281faaf3d58f39b2fcc220ca4d150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:04:54 +0100 Subject: [PATCH 055/201] Stats for execution states times --- libevmjit/Cache.cpp | 29 ++++++++----- libevmjit/Cache.h | 7 +--- libevmjit/ExecStats.cpp | 77 +++++++++++++++++++++++++++++++++-- libevmjit/ExecStats.h | 27 ++++++++---- libevmjit/ExecutionEngine.cpp | 67 ++++++------------------------ libevmjit/ExecutionEngine.h | 35 ++++++++++++---- 6 files changed, 153 insertions(+), 89 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 0e6fb517a..305b97d5c 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -7,6 +7,7 @@ #include #include #include +#include "ExecutionEngine.h" namespace dev { @@ -18,20 +19,25 @@ namespace jit //#define LOG(...) std::cerr << "CACHE " #define LOG(...) std::ostream(nullptr) -ObjectCache* Cache::getObjectCache() +namespace { - static ObjectCache objectCache; - return &objectCache; + llvm::MemoryBuffer* g_lastObject; + ExecutionEngineListener* g_listener; } -namespace +ObjectCache* Cache::getObjectCache(ExecutionEngineListener* _listener) { - llvm::MemoryBuffer* lastObject; + static ObjectCache objectCache; + g_listener = _listener; + return &objectCache; } std::unique_ptr Cache::getObject(std::string const& id) { - assert(!lastObject); + if (g_listener) + g_listener->stateChanged(ExecState::CacheLoad); + + assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); llvm::sys::path::append(cachePath, "evm_objs", id); @@ -51,11 +57,11 @@ std::unique_ptr Cache::getObject(std::string const& id) #endif if (auto r = llvm::MemoryBuffer::getFile(cachePath.str(), -1, false)) - lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer()); + 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 (lastObject) // if object found create fake module + if (g_lastObject) // if object found create fake module { auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); @@ -67,6 +73,9 @@ std::unique_ptr Cache::getObject(std::string const& id) 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); @@ -84,8 +93,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const*) { - auto o = lastObject; - lastObject = nullptr; + auto o = g_lastObject; + g_lastObject = nullptr; return o; } diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 1cad537cd..d7b32c651 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -11,6 +10,7 @@ namespace eth { namespace jit { +class ExecutionEngineListener; class ObjectCache : public llvm::ObjectCache { @@ -23,16 +23,13 @@ public: /// 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; - -private: - std::unordered_map> m_map; }; class Cache { public: - static ObjectCache* getObjectCache(); + static ObjectCache* getObjectCache(ExecutionEngineListener* _listener); static std::unique_ptr getObject(std::string const& id); }; diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index e3f5293f8..deb322521 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -1,4 +1,7 @@ #include "ExecStats.h" +#include +#include +#include namespace dev { @@ -7,14 +10,80 @@ namespace eth namespace jit { -void ExecStats::execStarted() +void ExecStats::stateChanged(ExecState _state) { - m_tp = std::chrono::high_resolution_clock::now(); + assert(m_state != ExecState::Finished); + 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; } -void ExecStats::execEnded() +namespace { - execTime = std::chrono::high_resolution_clock::now() - m_tp; +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::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/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 3ee730836..284ecad7b 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -2,6 +2,7 @@ #include #include +#include "ExecutionEngine.h" namespace dev { @@ -10,21 +11,31 @@ namespace eth namespace jit { -class ExecStats +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; - std::chrono::high_resolution_clock::duration compileTime; - std::chrono::high_resolution_clock::duration codegenTime; - std::chrono::high_resolution_clock::duration cacheLoadTime; - std::chrono::high_resolution_clock::duration execTime; + duration time[(int)ExecState::Finished] = {}; - void execStarted(); - void execEnded(); + void stateChanged(ExecState _state) override; private: - std::chrono::high_resolution_clock::time_point m_tp; + ExecState m_state = {}; + time_point m_tp = {}; + +}; + + +class StatsCollector +{ +public: + std::vector> stats; + ~StatsCollector(); }; } diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index bc1202e79..dd545cd03 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -19,6 +19,7 @@ #include "Runtime.h" #include "Compiler.h" #include "Cache.h" +#include "ExecStats.h" #include "BuildInfo.gen.h" #include @@ -83,50 +84,6 @@ bool showInfo() return show; } -class StatsCollector -{ -public: - std::vector> stats; - - ~StatsCollector() - { - if (stats.empty()) - return; - - using d = decltype(ExecStats{}.execTime); - d total = d::zero(); - d max = d::zero(); - d min = d::max(); - - for (auto&& s : stats) - { - auto t = s->execTime; - total += t; - if (t < min) - min = t; - if (t > max) - max = t; - } - - using u = std::chrono::microseconds; - auto nTotal = std::chrono::duration_cast(total).count(); - auto nAverage = std::chrono::duration_cast(total / stats.size()).count(); - auto nMax = std::chrono::duration_cast(max).count(); - auto nMin = std::chrono::duration_cast(min).count(); - - std::cout << "Total exec time: " << nTotal << " us" << std::endl - << "Averge exec time: " << nAverage << " us" << std::endl - << "Min exec time: " << nMin << " us" << std::endl - << "Max exec time: " << nMax << " us" << std::endl; - } -}; - -} - -void ExecutionEngine::collectStats() -{ - if (!m_stats) - m_stats.reset(new ExecStats); } ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) @@ -140,8 +97,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) static StatsCollector statsCollector; - if (statsCollectingEnabled) - collectStats(); + std::unique_ptr listener{new ExecStats}; + listener->stateChanged(ExecState::Started); auto codeBegin = _data->code; auto codeEnd = codeBegin + _data->codeSize; @@ -155,12 +112,15 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } else { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache() : nullptr; + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; std::unique_ptr module; if (objectCache) module = Cache::getObject(mainFuncName); if (!module) + { + listener->stateChanged(ExecState::Compilation); module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + } if (debugDumpModule) module->dump(); if (!ee) @@ -190,6 +150,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (objectCache) ee->setObjectCache(objectCache); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } else @@ -198,28 +159,26 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { ee->addModule(module.get()); module.release(); + listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } } } assert(entryFuncPtr); - if (m_stats) - m_stats->execStarted(); - + listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); - - if (m_stats) - m_stats->execEnded(); + 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(m_stats)); + statsCollector.stats.push_back(std::move(listener)); return returnCode; } diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index e12f86af4..101475b11 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -2,7 +2,6 @@ #include #include "RuntimeData.h" -#include "ExecStats.h" namespace dev { @@ -11,19 +10,41 @@ 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; - void operator=(ExecutionEngine) = delete; + ExecutionEngine& operator=(ExecutionEngine) = delete; EXPORT ReturnCode run(RuntimeData* _data, Env* _env); - void collectStats(); - - std::unique_ptr getStats(); - /// Reference to returned data (RETURN opcode used) bytes_ref returnData; @@ -31,8 +52,6 @@ private: /// After execution, if RETURN used, memory is moved there /// to allow client copy the returned data bytes m_memory; - - std::unique_ptr m_stats; }; } From ac8ddfdcd80eef27eb6bb0bd71caa285d2ee3105 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 5 Feb 2015 16:34:46 +0100 Subject: [PATCH 056/201] first definition of block tests - header only --- libethcore/BlockInfo.cpp | 2 +- test/blValidBlockTestFiller.json | 20 ++++ test/block.cpp | 185 ++++++++++++++++++++++++++++++- 3 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 test/blValidBlockTestFiller.json diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 62017796e..8465424a8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -134,7 +134,7 @@ void BlockInfo::populate(bytesConstRef _block, bool _checkNonce) RLP header = root[0]; if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data())); + BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data()) << errinfo_comment("block header needs to be a list")); populateFromHeader(header, _checkNonce); if (!root[1].isList()) diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json new file mode 100644 index 000000000..ab0369fa4 --- /dev/null +++ b/test/blValidBlockTestFiller.json @@ -0,0 +1,20 @@ +{ + "validBlock" : { + "block" : { + "parentHash": "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1", + "stateRoot": "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "023101", + "number": "62", + "gasLimit": "0x0dddb6", + "gasUsed": "100", + "timestamp": "0x54c98c81", + "extraData": "42", + "nonce": "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d" + } + } +} diff --git a/test/block.cpp b/test/block.cpp index 974acbf6d..674c7c40d 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -14,8 +14,189 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file state.cpp +/** @file block.cpp * @author Christoph Jentzsch - * @date 2014 + * @date 2015 * block test functions. */ + +#include "TestHelper.h" + +using namespace std; +using namespace json_spirit; +using namespace dev; +using namespace dev::eth; + +namespace dev { namespace test { + +bytes createBlockRLPFromFields(mObject& _tObj) +{ + BOOST_REQUIRE(_tObj.count("parentHash") > 0); + BOOST_REQUIRE(_tObj.count("uncleHash") > 0); + BOOST_REQUIRE(_tObj.count("coinbase") > 0); + BOOST_REQUIRE(_tObj.count("stateRoot") > 0); + BOOST_REQUIRE(_tObj.count("transactionsTrie")> 0); + BOOST_REQUIRE(_tObj.count("receiptTrie") > 0); + BOOST_REQUIRE(_tObj.count("bloom") > 0); + BOOST_REQUIRE(_tObj.count("difficulty") > 0); + BOOST_REQUIRE(_tObj.count("number") > 0); + BOOST_REQUIRE(_tObj.count("gasLimit")> 0); + BOOST_REQUIRE(_tObj.count("gasUsed") > 0); + BOOST_REQUIRE(_tObj.count("timestamp") > 0); + BOOST_REQUIRE(_tObj.count("extraData") > 0); + BOOST_REQUIRE(_tObj.count("nonce") > 0); + + // construct RLP of the given block + cout << "done with require\n"; + RLPStream rlpStream; + rlpStream.appendList(14); + cout << "increate aha1\n"; + rlpStream << h256(_tObj["parentHash"].get_str()) << h256(_tObj["uncleHash"].get_str()) << Address(_tObj["coinbase"].get_str()); + rlpStream << h256(_tObj["stateRoot"].get_str()) << h256(_tObj["transactionsTrie"].get_str()) << Address(_tObj["receiptTrie"].get_str()); + rlpStream << LogBloom(_tObj["bloom"].get_str()) << u256(_tObj["difficulty"].get_str()) << u256(_tObj["number"].get_str()); + rlpStream << u256(_tObj["gasLimit"].get_str()) << u256(_tObj["gasUsed"].get_str()) << u256(_tObj["timestamp"].get_str()); + rlpStream << importByteArray(_tObj["extraData"].get_str()) << h256(_tObj["nonce"].get_str()); + + return rlpStream.out(); +} + +void doBlockTests(json_spirit::mValue& _v, bool _fillin) +{ + for (auto& i: _v.get_obj()) + { + cerr << i.first << endl; + mObject& o = i.second.get_obj(); + + if (_fillin == false) + { + BOOST_REQUIRE(o.count("rlp") > 0); + const bytes rlpReaded = importByteArray(o["rlp"].get_str()); + RLP myRLP(rlpReaded); + BlockInfo blockFromRlp; + + try + { + blockFromRlp.populateFromHeader(myRLP, false); + //blockFromRlp.verifyInternals(rlpReaded); + } + catch(Exception const& _e) + { + cnote << "block construction did throw an exception: " << diagnostic_information(_e); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + BOOST_CHECK_MESSAGE(o.count("block") == 0, "A block object should not be defined because the block RLP is invalid!"); + return; + } + + BOOST_REQUIRE(o.count("block") > 0); + + mObject tObj = o["block"].get_obj(); + BlockInfo blockFromFields; + const bytes rlpreade2 = createBlockRLPFromFields(tObj); + RLP mysecondRLP(rlpreade2); + blockFromFields.populateFromHeader(mysecondRLP, false); + + //Check the fields restored from RLP to original fields + BOOST_CHECK_MESSAGE(blockFromFields.hash == blockFromRlp.hash, "hash in given RLP not matching the block hash!"); + BOOST_CHECK_MESSAGE(blockFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); + BOOST_CHECK_MESSAGE(blockFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); + BOOST_CHECK_MESSAGE(blockFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); + BOOST_CHECK_MESSAGE(blockFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); + BOOST_CHECK_MESSAGE(blockFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); + BOOST_CHECK_MESSAGE(blockFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); + BOOST_CHECK_MESSAGE(blockFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); + BOOST_CHECK_MESSAGE(blockFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); + BOOST_CHECK_MESSAGE(blockFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); + BOOST_CHECK_MESSAGE(blockFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); + BOOST_CHECK_MESSAGE(blockFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); + BOOST_CHECK_MESSAGE(blockFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); + + BOOST_CHECK_MESSAGE(blockFromFields == blockFromRlp, "However, blockFromFields != blockFromRlp!"); + + } + else + { + BOOST_REQUIRE(o.count("block") > 0); + + // construct Rlp of the given block + bytes blockRLP = createBlockRLPFromFields(o["block"].get_obj()); + RLP myRLP(blockRLP); + o["rlp"] = toHex(blockRLP); + + try + { + BlockInfo blockFromFields; + blockFromFields.populateFromHeader(myRLP, false); + (void)blockFromFields; + //blockFromFields.verifyInternals(blockRLP); + } + catch (Exception const& _e) + { + cnote << "block construction did throw an exception: " << diagnostic_information(_e); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + o.erase(o.find("block")); + } + catch (std::exception const& _e) + { + cnote << "block construction did throw an exception: " << _e.what(); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + o.erase(o.find("block")); + } + catch(...) + { + o.erase(o.find("block")); + } + } + } +} + +} }// Namespace Close + + +BOOST_AUTO_TEST_SUITE(BlockTests) + +BOOST_AUTO_TEST_CASE(blValidBlocksTest) +{ + dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); +} + +BOOST_AUTO_TEST_CASE(ttCreateTest) +{ + for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) + { + string arg = boost::unit_test::framework::master_test_suite().argv[i]; + if (arg == "--createtest") + { + if (boost::unit_test::framework::master_test_suite().argc <= i + 2) + { + cnote << "usage: ./testeth --createtest \n"; + return; + } + try + { + cnote << "Populating tests..."; + json_spirit::mValue v; + string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1])); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty."); + json_spirit::read_string(s, v); + dev::test::doBlockTests(v, true); + writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true))); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed block test with Exception: " << diagnostic_information(_e)); + } + catch (std::exception const& _e) + { + BOOST_ERROR("Failed block test with Exception: " << _e.what()); + } + } + } +} + +BOOST_AUTO_TEST_CASE(userDefinedFileTT) +{ + dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); +} + +BOOST_AUTO_TEST_SUITE_END() From 8fd2b949c147bc0a5723f60e9e164282d9a4a257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:55:46 +0100 Subject: [PATCH 057/201] Fix cache bug: code was always compiled --- libevmjit/Cache.cpp | 20 ++++++++++++++------ libevmjit/ExecutionEngine.cpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 305b97d5c..e6d76beba 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -16,8 +16,8 @@ namespace eth namespace jit { -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) namespace { @@ -37,6 +37,7 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_listener) g_listener->stateChanged(ExecState::CacheLoad); + CACHE_LOG << id << ": search\n"; assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -63,10 +64,15 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_lastObject) // if object found create fake module { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + 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()); + llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + return module; } + CACHE_LOG << id << ": not found\n"; return nullptr; } @@ -86,13 +92,15 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory 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*) +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/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index dd545cd03..59764eaff 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -164,7 +164,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } } } - assert(entryFuncPtr); + assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); From ddf4724ce134d8176bc1adbdf8fa02a38daaeba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 5 Feb 2015 16:55:46 +0100 Subject: [PATCH 058/201] Fix cache bug: code was always compiled --- evmjit/libevmjit/Cache.cpp | 20 ++++++++++++++------ evmjit/libevmjit/ExecutionEngine.cpp | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 305b97d5c..e6d76beba 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -16,8 +16,8 @@ namespace eth namespace jit { -//#define LOG(...) std::cerr << "CACHE " -#define LOG(...) std::ostream(nullptr) +//#define CACHE_LOG std::cerr << "CACHE " +#define CACHE_LOG std::ostream(nullptr) namespace { @@ -37,6 +37,7 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_listener) g_listener->stateChanged(ExecState::CacheLoad); + CACHE_LOG << id << ": search\n"; assert(!g_lastObject); llvm::SmallString<256> cachePath; llvm::sys::path::system_temp_directory(false, cachePath); @@ -63,10 +64,15 @@ std::unique_ptr Cache::getObject(std::string const& id) if (g_lastObject) // if object found create fake module { - auto module = std::unique_ptr(new llvm::Module(id, llvm::getGlobalContext())); - auto mainFuncType = llvm::FunctionType::get(llvm::IntegerType::get(llvm::getGlobalContext(), 32), {}, false); - llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get()); + 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()); + llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + return module; } + CACHE_LOG << id << ": not found\n"; return nullptr; } @@ -86,13 +92,15 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory 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*) +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/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index dd545cd03..59764eaff 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -164,7 +164,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) } } } - assert(entryFuncPtr); + assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); auto returnCode = runEntryFunc(entryFuncPtr, &runtime); From 699ab0045cc220fb7c2603ecffddf2e316e86d55 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 6 Feb 2015 00:29:03 +0800 Subject: [PATCH 059/201] fix Mac build error for evmjit We need to include , otherwise it complains: cpp-ethereum/evmjit/libevmjit/ExecutionEngine.cpp:147:2: error: implicit instantiation of undefined template 'std::__1::basic_ostream >' clog(JIT) << " + " << std::chrono::duration_cast(executionEndTime - executionStartTime).cou... ^ cpp-ethereum/evmjit/libevmjit/Utils.h:15:23: note: expanded from macro 'clog' #define clog(CHANNEL) std::ostream(nullptr) ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iosfwd:111:33: note: template is declared here class _LIBCPP_TYPE_VIS_ONLY basic_ostream; ^ --- libevmjit/Utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1e6705667..7e6133ced 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "Common.h" namespace dev From 49893ce8916cb3ea7cc216125131c868edebd0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:39:36 +0100 Subject: [PATCH 060/201] Add `unreachable` instruction to fake module generated by Cache --- libevmjit/Cache.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index e6d76beba..cad3f2094 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,8 @@ std::unique_ptr Cache::getObject(std::string const& id) 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()); - llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); return module; } CACHE_LOG << id << ": not found\n"; From cbc1c99beb059444014670581fecc8b47a8c3630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:39:36 +0100 Subject: [PATCH 061/201] Add `unreachable` instruction to fake module generated by Cache --- evmjit/libevmjit/Cache.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index e6d76beba..cad3f2094 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,8 @@ std::unique_ptr Cache::getObject(std::string const& id) 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()); - llvm::BasicBlock::Create(context, {}, mainFunc); // FIXME: Check if empty basic block is valid + auto bb = llvm::BasicBlock::Create(context, {}, mainFunc); + bb->getInstList().push_back(new llvm::UnreachableInst{context}); return module; } CACHE_LOG << id << ": not found\n"; From 9640644f7237b5763f88a231027d847d88cc06cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:46:28 +0100 Subject: [PATCH 062/201] Place warning pragmas for LLVM includes in separated files --- libevmjit/ExecutionEngine.cpp | 8 ++------ libevmjit/preprocessor/llvm_includes_end.h | 3 +++ libevmjit/preprocessor/llvm_includes_start.h | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 libevmjit/preprocessor/llvm_includes_end.h create mode 100644 libevmjit/preprocessor/llvm_includes_start.h diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 59764eaff..ef62e8441 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -2,19 +2,15 @@ #include #include // env options - +#include "preprocessor/llvm_includes_start.h" #include #include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" diff --git a/libevmjit/preprocessor/llvm_includes_end.h b/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..3a47dca15 --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,3 @@ + +#pragma warning(pop) +#pragma GCC diagnostic pop diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..6600886f4 --- /dev/null +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,4 @@ + +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" From 33205fb9c954aa078d499c26dd3bf6a9fe287632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 11:46:28 +0100 Subject: [PATCH 063/201] Place warning pragmas for LLVM includes in separated files --- evmjit/libevmjit/ExecutionEngine.cpp | 8 ++------ evmjit/libevmjit/preprocessor/llvm_includes_end.h | 3 +++ evmjit/libevmjit/preprocessor/llvm_includes_start.h | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_end.h create mode 100644 evmjit/libevmjit/preprocessor/llvm_includes_start.h diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 59764eaff..ef62e8441 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -2,19 +2,15 @@ #include #include // env options - +#include "preprocessor/llvm_includes_start.h" #include #include -#pragma warning(push) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include #include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include #include +#include "preprocessor/llvm_includes_end.h" #include "Runtime.h" #include "Compiler.h" diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_end.h b/evmjit/libevmjit/preprocessor/llvm_includes_end.h new file mode 100644 index 000000000..3a47dca15 --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_end.h @@ -0,0 +1,3 @@ + +#pragma warning(pop) +#pragma GCC diagnostic pop diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h new file mode 100644 index 000000000..6600886f4 --- /dev/null +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -0,0 +1,4 @@ + +#pragma warning(push) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" From 00293a05b642e5091357f7f1b8fa44051859a396 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 6 Feb 2015 15:00:06 +0100 Subject: [PATCH 064/201] include transaction list --- test/block.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/block.cpp b/test/block.cpp index 674c7c40d..40984e8da 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -144,8 +144,30 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) } catch(...) { + cnote << "block construction did throw an unknow exception\n"; o.erase(o.find("block")); } + + BOOST_REQUIRE(o.count("transactions") > 0); + + for (auto const& txObj: o["transactions"].get_array()) + { + mObject tx = txObj.get_obj(); + BOOST_REQUIRE(tx.count("nonce") > 0); + BOOST_REQUIRE(tx.count("gasPrice") > 0); + BOOST_REQUIRE(tx.count("gasLimit") > 0); + BOOST_REQUIRE(tx.count("to") > 0); + BOOST_REQUIRE(tx.count("value") > 0); + BOOST_REQUIRE(tx.count("v") > 0); + BOOST_REQUIRE(tx.count("r") > 0); + BOOST_REQUIRE(tx.count("s") > 0); + BOOST_REQUIRE(tx.count("data") > 0); + + Transaction txFromFields = createTransactionFromFields(tx); + + + + } } } } From 4bcee00be98ac55a659f3f866136e4b5ab17dc8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 17:11:24 +0100 Subject: [PATCH 065/201] #include cleanups --- libevmjit/Arith256.cpp | 3 +- libevmjit/Arith256.h | 1 - libevmjit/BasicBlock.cpp | 14 +- libevmjit/BasicBlock.h | 3 +- libevmjit/Cache.cpp | 11 +- libevmjit/Cache.h | 4 +- libevmjit/Common.h | 1 - libevmjit/Compiler.cpp | 29 ++-- libevmjit/Compiler.h | 4 - libevmjit/CompilerHelper.cpp | 98 ++++++------ libevmjit/CompilerHelper.h | 153 ++++++++++--------- libevmjit/Endianness.cpp | 76 ++++----- libevmjit/Endianness.h | 49 +++--- libevmjit/ExecStats.h | 4 +- libevmjit/ExecutionEngine.cpp | 15 +- libevmjit/ExecutionEngine.h | 3 +- libevmjit/Ext.cpp | 10 +- libevmjit/Ext.h | 4 +- libevmjit/GasMeter.cpp | 12 +- libevmjit/GasMeter.h | 2 - libevmjit/Instruction.cpp | 4 +- libevmjit/Instruction.h | 1 - libevmjit/Memory.cpp | 15 +- libevmjit/Memory.h | 1 - libevmjit/Runtime.cpp | 6 +- libevmjit/Runtime.h | 4 +- libevmjit/RuntimeData.h | 4 +- libevmjit/RuntimeManager.cpp | 10 +- libevmjit/RuntimeManager.h | 1 - libevmjit/Stack.cpp | 2 - libevmjit/Stack.h | 83 +++++----- libevmjit/Type.cpp | 4 - libevmjit/Type.h | 7 +- libevmjit/Utils.cpp | 1 - libevmjit/Utils.h | 1 - libevmjit/preprocessor/llvm_includes_start.h | 1 + 36 files changed, 296 insertions(+), 345 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index a77050adc..6ae62b9d3 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -3,8 +3,9 @@ #include "Type.h" #include "Endianness.h" -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 2513ca568..4b94652d8 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index c71bae94f..112e9d652 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,15 +1,15 @@ - #include "BasicBlock.h" +#include "Type.h" -#include - +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include +#include "preprocessor/llvm_includes_end.h" -#include "Type.h" +#include namespace dev { @@ -141,7 +141,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) auto endIter = m_currentStack.end(); // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; currIter < endIter && idx >= 0; ++currIter, --idx) { @@ -308,7 +308,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; + bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor @@ -321,7 +321,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } } diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 1be742f9f..0f639602a 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,8 +1,7 @@ #pragma once -#include -#include #include "Common.h" #include "Stack.h" +#include namespace dev { diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index cad3f2094..64015a820 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -1,14 +1,17 @@ #include "Cache.h" -#include -#include -#include +#include "ExecutionEngine.h" + +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include #include -#include "ExecutionEngine.h" +#include "preprocessor/llvm_includes_end.h" + +#include +#include namespace dev { diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index d7b32c651..18f9237f1 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,8 +1,6 @@ #pragma once - -#include #include - +#include namespace dev { diff --git a/libevmjit/Common.h b/libevmjit/Common.h index 62731292f..cd7177e67 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -1,5 +1,4 @@ #pragma once - #include #include #include diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 02e2e920a..9ad53ce3c 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,19 +1,4 @@ - #include "Compiler.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - #include "Instruction.h" #include "Type.h" #include "Memory.h" @@ -25,6 +10,20 @@ #include "Arith256.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include +#include +#include +#include + namespace dev { namespace eth diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 89b2f1a8e..30130798c 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -1,8 +1,4 @@ - #pragma once - -#include - #include "Common.h" #include "BasicBlock.h" diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index 9cccecd79..bf2929429 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -1,51 +1,47 @@ - -#include "CompilerHelper.h" - -#include -#include - -#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) -{} - -} -} -} +#include "CompilerHelper.h" +#include "RuntimeManager.h" +#include + +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/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 62733ca72..912f7e93f 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -1,78 +1,79 @@ +#pragma once -#pragma once - +#include "preprocessor/llvm_includes_start.h" #include - - -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; - void 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; -}; - -} -} -} +#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/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index db7edfdc9..f3ee4c783 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -1,38 +1,38 @@ - -#include "Endianness.h" - -#include - -#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; -} - -} -} -} +#include "Endianness.h" +#include "Type.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.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/libevmjit/Endianness.h b/libevmjit/Endianness.h index 8a1f41085..73224fb21 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,24 +1,25 @@ - -#pragma once - -#include - -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); -}; - -} -} -} +#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/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 284ecad7b..17f58ccac 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -1,8 +1,6 @@ #pragma once - -#include -#include #include "ExecutionEngine.h" +#include namespace dev { diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ef62e8441..24ed74f15 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,7 +1,10 @@ #include "ExecutionEngine.h" +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "BuildInfo.gen.h" -#include -#include // env options #include "preprocessor/llvm_includes_start.h" #include #include @@ -12,12 +15,8 @@ #include #include "preprocessor/llvm_includes_end.h" -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" -#include "ExecStats.h" -#include "BuildInfo.gen.h" - +#include +#include // env options #include namespace dev diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index 101475b11..a31b6bf1e 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,7 +1,6 @@ #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index 0a465bb80..c06d01f74 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -1,15 +1,13 @@ - #include "Ext.h" - -#include -#include -#include - #include "RuntimeManager.h" #include "Memory.h" #include "Type.h" #include "Endianness.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 8ad69ea6e..669797848 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "CompilerHelper.h" +#include namespace dev { diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index eb06795f0..3f3cf2e04 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -1,14 +1,12 @@ - #include "GasMeter.h" - -#include -#include -#include - -#include "Type.h" #include "Ext.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + + namespace dev { namespace eth diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 27f55253f..4f29f5c29 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,6 +1,4 @@ - #pragma once - #include "CompilerHelper.h" #include "Instruction.h" diff --git a/libevmjit/Instruction.cpp b/libevmjit/Instruction.cpp index 909121607..f70b020f8 100644 --- a/libevmjit/Instruction.cpp +++ b/libevmjit/Instruction.cpp @@ -1,6 +1,8 @@ - #include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index 6785213d6..db18c934a 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace llvm diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index 6a46fa8ca..e29bbcaba 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,21 +1,14 @@ #include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - #include "Type.h" #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index e8edce735..90c01c1ca 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index eb70e01d1..09ad7854f 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -1,9 +1,5 @@ - #include "Runtime.h" - -#include -#include -#include +#include namespace dev { diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 20cf56984..31341d7d3 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index ff6e82fe8..50522f0bc 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,7 +1,5 @@ #pragma once - -#include "Utils.h" - +#include "Common.h" namespace dev { diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 98386e1fe..7b3db7477 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -1,12 +1,8 @@ - #include "RuntimeManager.h" -#include -#include -#include - -#include "RuntimeData.h" -#include "Instruction.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index b3ce6f997..92c210289 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" #include "Type.h" #include "RuntimeData.h" diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 44f1c21c1..79864f3ca 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,10 +1,8 @@ #include "Stack.h" #include "RuntimeManager.h" #include "Runtime.h" -#include "Type.h" #include -#include namespace dev { diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 3e8881e4f..f453d14c0 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,43 +1,40 @@ -#pragma once - -#include "CompilerHelper.h" - -#include - -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: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#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: + RuntimeManager& m_runtimeManager; + + llvm::Function* m_push; + llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/libevmjit/Type.cpp b/libevmjit/Type.cpp index 2bbb3fa6f..8e2bc13fc 100644 --- a/libevmjit/Type.cpp +++ b/libevmjit/Type.cpp @@ -1,8 +1,4 @@ - #include "Type.h" - -#include - #include "RuntimeManager.h" namespace dev diff --git a/libevmjit/Type.h b/libevmjit/Type.h index e7757abbf..46fd5c9b7 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -1,9 +1,10 @@ - #pragma once +#include "Common.h" +#include "preprocessor/llvm_includes_start.h" #include -#include -#include "Common.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/libevmjit/Utils.cpp b/libevmjit/Utils.cpp index 5f7f75bfd..bf3bf93b3 100644 --- a/libevmjit/Utils.cpp +++ b/libevmjit/Utils.cpp @@ -1,4 +1,3 @@ - #include "Utils.h" namespace dev diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 1e6705667..652c7bc35 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace dev diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h index 6600886f4..264a6e1ef 100644 --- a/libevmjit/preprocessor/llvm_includes_start.h +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -1,4 +1,5 @@ #pragma warning(push) +#pragma warning(disable: 4267 4244 4800) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" From 3365f3f4380d1c8f859cca659e44e8ab9af8017a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 6 Feb 2015 17:11:24 +0100 Subject: [PATCH 066/201] #include cleanups --- evmjit/libevmjit/Arith256.cpp | 3 +- evmjit/libevmjit/Arith256.h | 1 - evmjit/libevmjit/BasicBlock.cpp | 14 +- evmjit/libevmjit/BasicBlock.h | 3 +- evmjit/libevmjit/Cache.cpp | 11 +- evmjit/libevmjit/Cache.h | 4 +- evmjit/libevmjit/Common.h | 1 - evmjit/libevmjit/Compiler.cpp | 29 ++-- evmjit/libevmjit/Compiler.h | 4 - evmjit/libevmjit/CompilerHelper.cpp | 98 ++++++----- evmjit/libevmjit/CompilerHelper.h | 153 +++++++++--------- evmjit/libevmjit/Endianness.cpp | 76 ++++----- evmjit/libevmjit/Endianness.h | 49 +++--- evmjit/libevmjit/ExecStats.h | 4 +- evmjit/libevmjit/ExecutionEngine.cpp | 15 +- evmjit/libevmjit/ExecutionEngine.h | 3 +- evmjit/libevmjit/Ext.cpp | 10 +- evmjit/libevmjit/Ext.h | 4 +- evmjit/libevmjit/GasMeter.cpp | 12 +- evmjit/libevmjit/GasMeter.h | 2 - evmjit/libevmjit/Instruction.cpp | 4 +- evmjit/libevmjit/Instruction.h | 1 - evmjit/libevmjit/Memory.cpp | 15 +- evmjit/libevmjit/Memory.h | 1 - evmjit/libevmjit/Runtime.cpp | 6 +- evmjit/libevmjit/Runtime.h | 4 +- evmjit/libevmjit/RuntimeData.h | 4 +- evmjit/libevmjit/RuntimeManager.cpp | 10 +- evmjit/libevmjit/RuntimeManager.h | 1 - evmjit/libevmjit/Stack.cpp | 2 - evmjit/libevmjit/Stack.h | 83 +++++----- evmjit/libevmjit/Type.cpp | 4 - evmjit/libevmjit/Type.h | 7 +- evmjit/libevmjit/Utils.cpp | 1 - evmjit/libevmjit/Utils.h | 1 - .../preprocessor/llvm_includes_start.h | 1 + 36 files changed, 296 insertions(+), 345 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index a77050adc..6ae62b9d3 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -3,8 +3,9 @@ #include "Type.h" #include "Endianness.h" -#include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" #include diff --git a/evmjit/libevmjit/Arith256.h b/evmjit/libevmjit/Arith256.h index 2513ca568..4b94652d8 100644 --- a/evmjit/libevmjit/Arith256.h +++ b/evmjit/libevmjit/Arith256.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index c71bae94f..112e9d652 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/evmjit/libevmjit/BasicBlock.cpp @@ -1,15 +1,15 @@ - #include "BasicBlock.h" +#include "Type.h" -#include - +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include +#include "preprocessor/llvm_includes_end.h" -#include "Type.h" +#include namespace dev { @@ -141,7 +141,7 @@ void BasicBlock::synchronizeLocalStack(Stack& _evmStack) auto endIter = m_currentStack.end(); // Update (emit set()) changed values - for (int idx = m_currentStack.size() - 1 - m_tosOffset; + for (int idx = (int)m_currentStack.size() - 1 - m_tosOffset; currIter < endIter && idx >= 0; ++currIter, --idx) { @@ -308,7 +308,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& initialStack = bblock.m_initialStack; initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems); // Initial stack shrinks, so the size difference grows: - bblock.m_tosOffset += info.inputItems; + bblock.m_tosOffset += (int)info.inputItems; } // We must account for the items that were pushed directly to successor @@ -321,7 +321,7 @@ void BasicBlock::linkLocalStacks(std::vector basicBlocks, llvm::IRB auto& exitStack = bblock.m_currentStack; exitStack.erase(exitStack.end() - info.outputItems, exitStack.end()); - bblock.m_tosOffset -= info.outputItems; + bblock.m_tosOffset -= (int)info.outputItems; // FIXME: Fix types } } diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 1be742f9f..0f639602a 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/evmjit/libevmjit/BasicBlock.h @@ -1,8 +1,7 @@ #pragma once -#include -#include #include "Common.h" #include "Stack.h" +#include namespace dev { diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index cad3f2094..64015a820 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -1,14 +1,17 @@ #include "Cache.h" -#include -#include -#include +#include "ExecutionEngine.h" + +#include "preprocessor/llvm_includes_start.h" #include #include #include #include #include #include -#include "ExecutionEngine.h" +#include "preprocessor/llvm_includes_end.h" + +#include +#include namespace dev { diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h index d7b32c651..18f9237f1 100644 --- a/evmjit/libevmjit/Cache.h +++ b/evmjit/libevmjit/Cache.h @@ -1,8 +1,6 @@ #pragma once - -#include #include - +#include namespace dev { diff --git a/evmjit/libevmjit/Common.h b/evmjit/libevmjit/Common.h index 62731292f..cd7177e67 100644 --- a/evmjit/libevmjit/Common.h +++ b/evmjit/libevmjit/Common.h @@ -1,5 +1,4 @@ #pragma once - #include #include #include diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 02e2e920a..9ad53ce3c 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -1,19 +1,4 @@ - #include "Compiler.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - #include "Instruction.h" #include "Type.h" #include "Memory.h" @@ -25,6 +10,20 @@ #include "Arith256.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include +#include +#include +#include +#include +#include "preprocessor/llvm_includes_end.h" + +#include +#include +#include +#include + namespace dev { namespace eth diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index 89b2f1a8e..30130798c 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/evmjit/libevmjit/Compiler.h @@ -1,8 +1,4 @@ - #pragma once - -#include - #include "Common.h" #include "BasicBlock.h" diff --git a/evmjit/libevmjit/CompilerHelper.cpp b/evmjit/libevmjit/CompilerHelper.cpp index 9cccecd79..bf2929429 100644 --- a/evmjit/libevmjit/CompilerHelper.cpp +++ b/evmjit/libevmjit/CompilerHelper.cpp @@ -1,51 +1,47 @@ - -#include "CompilerHelper.h" - -#include -#include - -#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) -{} - -} -} -} +#include "CompilerHelper.h" +#include "RuntimeManager.h" +#include + +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 index 62733ca72..912f7e93f 100644 --- a/evmjit/libevmjit/CompilerHelper.h +++ b/evmjit/libevmjit/CompilerHelper.h @@ -1,78 +1,79 @@ +#pragma once -#pragma once - +#include "preprocessor/llvm_includes_start.h" #include - - -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; - void 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; -}; - -} -} -} +#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 index db7edfdc9..f3ee4c783 100644 --- a/evmjit/libevmjit/Endianness.cpp +++ b/evmjit/libevmjit/Endianness.cpp @@ -1,38 +1,38 @@ - -#include "Endianness.h" - -#include - -#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; -} - -} -} -} +#include "Endianness.h" +#include "Type.h" + +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.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 index 8a1f41085..73224fb21 100644 --- a/evmjit/libevmjit/Endianness.h +++ b/evmjit/libevmjit/Endianness.h @@ -1,24 +1,25 @@ - -#pragma once - -#include - -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); -}; - -} -} -} +#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.h b/evmjit/libevmjit/ExecStats.h index 284ecad7b..17f58ccac 100644 --- a/evmjit/libevmjit/ExecStats.h +++ b/evmjit/libevmjit/ExecStats.h @@ -1,8 +1,6 @@ #pragma once - -#include -#include #include "ExecutionEngine.h" +#include namespace dev { diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index ef62e8441..24ed74f15 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -1,7 +1,10 @@ #include "ExecutionEngine.h" +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "BuildInfo.gen.h" -#include -#include // env options #include "preprocessor/llvm_includes_start.h" #include #include @@ -12,12 +15,8 @@ #include #include "preprocessor/llvm_includes_end.h" -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" -#include "ExecStats.h" -#include "BuildInfo.gen.h" - +#include +#include // env options #include namespace dev diff --git a/evmjit/libevmjit/ExecutionEngine.h b/evmjit/libevmjit/ExecutionEngine.h index 101475b11..a31b6bf1e 100644 --- a/evmjit/libevmjit/ExecutionEngine.h +++ b/evmjit/libevmjit/ExecutionEngine.h @@ -1,7 +1,6 @@ #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/evmjit/libevmjit/Ext.cpp b/evmjit/libevmjit/Ext.cpp index 0a465bb80..c06d01f74 100644 --- a/evmjit/libevmjit/Ext.cpp +++ b/evmjit/libevmjit/Ext.cpp @@ -1,15 +1,13 @@ - #include "Ext.h" - -#include -#include -#include - #include "RuntimeManager.h" #include "Memory.h" #include "Type.h" #include "Endianness.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/evmjit/libevmjit/Ext.h b/evmjit/libevmjit/Ext.h index 8ad69ea6e..669797848 100644 --- a/evmjit/libevmjit/Ext.h +++ b/evmjit/libevmjit/Ext.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "CompilerHelper.h" +#include namespace dev { diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index eb06795f0..3f3cf2e04 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -1,14 +1,12 @@ - #include "GasMeter.h" - -#include -#include -#include - -#include "Type.h" #include "Ext.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + + namespace dev { namespace eth diff --git a/evmjit/libevmjit/GasMeter.h b/evmjit/libevmjit/GasMeter.h index 27f55253f..4f29f5c29 100644 --- a/evmjit/libevmjit/GasMeter.h +++ b/evmjit/libevmjit/GasMeter.h @@ -1,6 +1,4 @@ - #pragma once - #include "CompilerHelper.h" #include "Instruction.h" diff --git a/evmjit/libevmjit/Instruction.cpp b/evmjit/libevmjit/Instruction.cpp index 909121607..f70b020f8 100644 --- a/evmjit/libevmjit/Instruction.cpp +++ b/evmjit/libevmjit/Instruction.cpp @@ -1,6 +1,8 @@ - #include "Instruction.h" + +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/evmjit/libevmjit/Instruction.h b/evmjit/libevmjit/Instruction.h index 6785213d6..db18c934a 100644 --- a/evmjit/libevmjit/Instruction.h +++ b/evmjit/libevmjit/Instruction.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace llvm diff --git a/evmjit/libevmjit/Memory.cpp b/evmjit/libevmjit/Memory.cpp index 6a46fa8ca..e29bbcaba 100644 --- a/evmjit/libevmjit/Memory.cpp +++ b/evmjit/libevmjit/Memory.cpp @@ -1,21 +1,14 @@ #include "Memory.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - #include "Type.h" #include "Runtime.h" #include "GasMeter.h" #include "Endianness.h" #include "RuntimeManager.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" + namespace dev { namespace eth diff --git a/evmjit/libevmjit/Memory.h b/evmjit/libevmjit/Memory.h index e8edce735..90c01c1ca 100644 --- a/evmjit/libevmjit/Memory.h +++ b/evmjit/libevmjit/Memory.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" namespace dev diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp index eb70e01d1..09ad7854f 100644 --- a/evmjit/libevmjit/Runtime.cpp +++ b/evmjit/libevmjit/Runtime.cpp @@ -1,9 +1,5 @@ - #include "Runtime.h" - -#include -#include -#include +#include namespace dev { diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index 20cf56984..31341d7d3 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -1,8 +1,6 @@ - #pragma once - -#include #include "RuntimeData.h" +#include namespace dev { diff --git a/evmjit/libevmjit/RuntimeData.h b/evmjit/libevmjit/RuntimeData.h index ff6e82fe8..50522f0bc 100644 --- a/evmjit/libevmjit/RuntimeData.h +++ b/evmjit/libevmjit/RuntimeData.h @@ -1,7 +1,5 @@ #pragma once - -#include "Utils.h" - +#include "Common.h" namespace dev { diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 98386e1fe..7b3db7477 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,12 +1,8 @@ - #include "RuntimeManager.h" -#include -#include -#include - -#include "RuntimeData.h" -#include "Instruction.h" +#include "preprocessor/llvm_includes_start.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index b3ce6f997..92c210289 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -1,5 +1,4 @@ #pragma once - #include "CompilerHelper.h" #include "Type.h" #include "RuntimeData.h" diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 44f1c21c1..79864f3ca 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -1,10 +1,8 @@ #include "Stack.h" #include "RuntimeManager.h" #include "Runtime.h" -#include "Type.h" #include -#include namespace dev { diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h index 3e8881e4f..f453d14c0 100644 --- a/evmjit/libevmjit/Stack.h +++ b/evmjit/libevmjit/Stack.h @@ -1,43 +1,40 @@ -#pragma once - -#include "CompilerHelper.h" - -#include - -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: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#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: + RuntimeManager& m_runtimeManager; + + llvm::Function* m_push; + llvm::Function* m_pop; + llvm::Function* m_get; + llvm::Function* m_set; + + llvm::Value* m_arg; +}; + + +} +} +} + + diff --git a/evmjit/libevmjit/Type.cpp b/evmjit/libevmjit/Type.cpp index 2bbb3fa6f..8e2bc13fc 100644 --- a/evmjit/libevmjit/Type.cpp +++ b/evmjit/libevmjit/Type.cpp @@ -1,8 +1,4 @@ - #include "Type.h" - -#include - #include "RuntimeManager.h" namespace dev diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index e7757abbf..46fd5c9b7 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -1,9 +1,10 @@ - #pragma once +#include "Common.h" +#include "preprocessor/llvm_includes_start.h" #include -#include -#include "Common.h" +#include +#include "preprocessor/llvm_includes_end.h" namespace dev { diff --git a/evmjit/libevmjit/Utils.cpp b/evmjit/libevmjit/Utils.cpp index 5f7f75bfd..bf3bf93b3 100644 --- a/evmjit/libevmjit/Utils.cpp +++ b/evmjit/libevmjit/Utils.cpp @@ -1,4 +1,3 @@ - #include "Utils.h" namespace dev diff --git a/evmjit/libevmjit/Utils.h b/evmjit/libevmjit/Utils.h index 1e6705667..652c7bc35 100644 --- a/evmjit/libevmjit/Utils.h +++ b/evmjit/libevmjit/Utils.h @@ -1,5 +1,4 @@ #pragma once - #include "Common.h" namespace dev diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h index 6600886f4..264a6e1ef 100644 --- a/evmjit/libevmjit/preprocessor/llvm_includes_start.h +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -1,4 +1,5 @@ #pragma warning(push) +#pragma warning(disable: 4267 4244 4800) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" From 7d03f7be2e1c6e7cadeaa7e8768766441d1940e3 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 6 Feb 2015 23:43:49 +0100 Subject: [PATCH 067/201] create block from transaction with genesis block as parent --- libethereum/State.h | 2 +- test/TestHelper.cpp | 27 +++++ test/TestHelper.h | 1 + test/blFirstTestFiller.json | 15 +++ test/block.cpp | 197 +++++++++++++++++++++++------------- test/transaction.cpp | 30 +----- 6 files changed, 170 insertions(+), 102 deletions(-) create mode 100644 test/blFirstTestFiller.json diff --git a/libethereum/State.h b/libethereum/State.h index 65a333fb4..5a296c0dd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -128,7 +128,7 @@ public: * commitToMine(_blockChain); // will call uncommitToMine if a repeat. * // unlock * MineInfo info; - * for (info.complete = false; !info.complete; info = mine()) {} + * for (info.completed = false; !info.completed; info = mine()) {} * } * // lock * completeMine(); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 5a579702a..3289305cd 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -487,6 +487,33 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun } } +bytes createTransactionFromFields(json_spirit::mObject& _tObj) +{ + BOOST_REQUIRE(_tObj.count("data") > 0); + BOOST_REQUIRE(_tObj.count("value") > 0); + BOOST_REQUIRE(_tObj.count("gasPrice") > 0); + BOOST_REQUIRE(_tObj.count("gasLimit") > 0); + BOOST_REQUIRE(_tObj.count("nonce")> 0); + BOOST_REQUIRE(_tObj.count("to") > 0); + + BOOST_REQUIRE(_tObj.count("v") > 0); + BOOST_REQUIRE(_tObj.count("r") > 0); + BOOST_REQUIRE(_tObj.count("s") > 0); + + //Construct Rlp of the given transaction + RLPStream rlpStream; + rlpStream.appendList(9); + rlpStream << bigint(_tObj["nonce"].get_str()) << bigint(_tObj["gasPrice"].get_str()) << bigint(_tObj["gasLimit"].get_str()); + if (_tObj["to"].get_str().empty()) + rlpStream << ""; + else + rlpStream << Address(_tObj["to"].get_str()); + rlpStream << bigint(_tObj["value"].get_str()) << importData(_tObj); + rlpStream << bigint(_tObj["v"].get_str()) << bigint(_tObj["r"].get_str()) << bigint(_tObj["s"].get_str()); + + return rlpStream.out(); +} + void processCommandLineOptions() { diff --git a/test/TestHelper.h b/test/TestHelper.h index ae6ea20cc..344f61a3f 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -79,6 +79,7 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function doTests); std::string getTestPath(); void userDefinedTest(std::string testTypeFlag, std::function doTests); +bytes createTransactionFromFields(json_spirit::mObject& _tObj); void processCommandLineOptions(); eth::LastHashes lastHashes(u256 _currentBlockNumber); diff --git a/test/blFirstTestFiller.json b/test/blFirstTestFiller.json new file mode 100644 index 000000000..0084fda13 --- /dev/null +++ b/test/blFirstTestFiller.json @@ -0,0 +1,15 @@ +{ + "firstBlockTest" : { + "transactions": [{ + "nonce": "0", + "gasPrice": "0x09184e72a000", + "gasLimit": "0x0f3e6f", + "to": "", + "value": "", + "data": "0x60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b56", + "v": "0x1b", + "r": "0xd4287e915ebac7a8af390560fa53c8f0b7f13802ba0393d7afa5823c2560ca89", + "s": "0xae75db31a34f7e386ad459646de98ec3a1c88cc91b11620b4ffd86871f579942" + }] + } +} diff --git a/test/block.cpp b/test/block.cpp index 40984e8da..518b61238 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -20,6 +20,7 @@ * block test functions. */ +#include #include "TestHelper.h" using namespace std; @@ -116,40 +117,42 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) } else { - BOOST_REQUIRE(o.count("block") > 0); - - // construct Rlp of the given block - bytes blockRLP = createBlockRLPFromFields(o["block"].get_obj()); - RLP myRLP(blockRLP); - o["rlp"] = toHex(blockRLP); - - try - { - BlockInfo blockFromFields; - blockFromFields.populateFromHeader(myRLP, false); - (void)blockFromFields; - //blockFromFields.verifyInternals(blockRLP); - } - catch (Exception const& _e) - { - cnote << "block construction did throw an exception: " << diagnostic_information(_e); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - o.erase(o.find("block")); - } - catch (std::exception const& _e) - { - cnote << "block construction did throw an exception: " << _e.what(); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - o.erase(o.find("block")); - } - catch(...) - { - cnote << "block construction did throw an unknow exception\n"; - o.erase(o.find("block")); - } +// BOOST_REQUIRE(o.count("block") > 0); + +// // construct Rlp of the given block +// bytes blockRLP = createBlockRLPFromFields(o["block"].get_obj()); +// RLP myRLP(blockRLP); +// o["rlp"] = toHex(blockRLP); + +// try +// { +// BlockInfo blockFromFields; +// blockFromFields.populateFromHeader(myRLP, false); +// (void)blockFromFields; +// //blockFromFields.verifyInternals(blockRLP); +// } +// catch (Exception const& _e) +// { +// cnote << "block construction did throw an exception: " << diagnostic_information(_e); +// BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); +// o.erase(o.find("block")); +// } +// catch (std::exception const& _e) +// { +// cnote << "block construction did throw an exception: " << _e.what(); +// BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); +// o.erase(o.find("block")); +// } +// catch(...) +// { +// cnote << "block construction did throw an unknow exception\n"; +// o.erase(o.find("block")); +// } BOOST_REQUIRE(o.count("transactions") > 0); + TransactionQueue txs; + for (auto const& txObj: o["transactions"].get_array()) { mObject tx = txObj.get_obj(); @@ -162,12 +165,60 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(tx.count("r") > 0); BOOST_REQUIRE(tx.count("s") > 0); BOOST_REQUIRE(tx.count("data") > 0); + cout << "attempt to import transaction\n"; + txs.attemptImport(createTransactionFromFields(tx)); + } + cout << "done importing txs\n"; - Transaction txFromFields = createTransactionFromFields(tx); + //BOOST_REQUIRE(o.count("env") > 0); + //BOOST_REQUIRE(o.count("pre") > 0); + +// ImportTest importer; +// importer.importEnv(o["env"].get_obj()); +// importer.importState(o["pre"].get_obj(), m_statePre); + +// State theState = importer.m_statePre; +// bytes output; + + cout << "construct bc\n"; + CanonBlockChain bc(true); + cout << "construct state\n"; + State theState; + + try + { + cout << "sync bc and txs in state\n"; + theState.sync(bc,txs); + // lock + cout << "commit to mine\n"; + theState.commitToMine(bc); // will call uncommitToMine if a repeat. + // unlock + MineInfo info; + cout << "mine...\n"; + for (info.completed = false; !info.completed; info = theState.mine()) {} + cout << "done mining, completeMine\n"; + // lock + theState.completeMine(); + // unlock + + cout << "new block: " << theState.blockData() << endl << theState.info() << endl; + } + catch (Exception const& _e) + { + cnote << "state sync did throw an exception: " << diagnostic_information(_e); + } + catch (std::exception const& _e) + { + cnote << "state sync did throw an exception: " << _e.what(); + } + + // write block and rlp to json + + //TODO if block rlp is invalid, delete transactions, and block + - } } } } @@ -177,48 +228,48 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_AUTO_TEST_SUITE(BlockTests) -BOOST_AUTO_TEST_CASE(blValidBlocksTest) -{ - dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); -} - -BOOST_AUTO_TEST_CASE(ttCreateTest) +BOOST_AUTO_TEST_CASE(blFirstTest) { - for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) - { - string arg = boost::unit_test::framework::master_test_suite().argv[i]; - if (arg == "--createtest") - { - if (boost::unit_test::framework::master_test_suite().argc <= i + 2) - { - cnote << "usage: ./testeth --createtest \n"; - return; - } - try - { - cnote << "Populating tests..."; - json_spirit::mValue v; - string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1])); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty."); - json_spirit::read_string(s, v); - dev::test::doBlockTests(v, true); - writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true))); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed block test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed block test with Exception: " << _e.what()); - } - } - } + dev::test::executeTests("blFirstTest", "/BlockTests", dev::test::doBlockTests); } -BOOST_AUTO_TEST_CASE(userDefinedFileTT) -{ - dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); -} +//BOOST_AUTO_TEST_CASE(ttCreateTest) +//{ +// for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) +// { +// string arg = boost::unit_test::framework::master_test_suite().argv[i]; +// if (arg == "--createtest") +// { +// if (boost::unit_test::framework::master_test_suite().argc <= i + 2) +// { +// cnote << "usage: ./testeth --createtest \n"; +// return; +// } +// try +// { +// cnote << "Populating tests..."; +// json_spirit::mValue v; +// string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1])); +// BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty."); +// json_spirit::read_string(s, v); +// dev::test::doBlockTests(v, true); +// writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true))); +// } +// catch (Exception const& _e) +// { +// BOOST_ERROR("Failed block test with Exception: " << diagnostic_information(_e)); +// } +// catch (std::exception const& _e) +// { +// BOOST_ERROR("Failed block test with Exception: " << _e.what()); +// } +// } +// } +//} + +//BOOST_AUTO_TEST_CASE(userDefinedFileTT) +//{ +// dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); +//} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/transaction.cpp b/test/transaction.cpp index e1e275302..00de5fb23 100644 --- a/test/transaction.cpp +++ b/test/transaction.cpp @@ -29,33 +29,6 @@ using namespace dev::eth; namespace dev { namespace test { -Transaction createTransactionFromFields(mObject& _tObj) -{ - BOOST_REQUIRE(_tObj.count("data") > 0); - BOOST_REQUIRE(_tObj.count("value") > 0); - BOOST_REQUIRE(_tObj.count("gasPrice") > 0); - BOOST_REQUIRE(_tObj.count("gasLimit") > 0); - BOOST_REQUIRE(_tObj.count("nonce")> 0); - BOOST_REQUIRE(_tObj.count("to") > 0); - - BOOST_REQUIRE(_tObj.count("v") > 0); - BOOST_REQUIRE(_tObj.count("r") > 0); - BOOST_REQUIRE(_tObj.count("s") > 0); - - //Construct Rlp of the given transaction - RLPStream rlpStream; - rlpStream.appendList(9); - rlpStream << bigint(_tObj["nonce"].get_str()) << bigint(_tObj["gasPrice"].get_str()) << bigint(_tObj["gasLimit"].get_str()); - if (_tObj["to"].get_str().empty()) - rlpStream << ""; - else - rlpStream << Address(_tObj["to"].get_str()); - rlpStream << bigint(_tObj["value"].get_str()) << importData(_tObj); - rlpStream << bigint(_tObj["v"].get_str()) << bigint(_tObj["r"].get_str()) << bigint(_tObj["s"].get_str()); - - return Transaction(rlpStream.out(), CheckSignature::Sender); -} - void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { for (auto& i: _v.get_obj()) @@ -84,7 +57,8 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(o.count("transaction") > 0); mObject tObj = o["transaction"].get_obj(); - Transaction txFromFields = createTransactionFromFields(tObj); + bytes txRLP = createTransactionFromFields(tObj); + Transaction txFromFields(txRLP, CheckSignature::Sender); //Check the fields restored from RLP to original fields BOOST_CHECK_MESSAGE(txFromFields.data() == txFromRlp.data(), "Data in given RLP not matching the Transaction data!"); From cf74b2a875016e317437f0ec451189d42abd3e99 Mon Sep 17 00:00:00 2001 From: Lu Guanqun Date: Fri, 6 Feb 2015 15:19:22 +0800 Subject: [PATCH 068/201] change typedef to using according to preferred coding style --- libevmjit/ExecutionEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 2db125c2d..aae5349d8 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -29,7 +29,7 @@ namespace jit namespace { -typedef ReturnCode(*EntryFuncPtr)(Runtime*); +using EntryFuncPtr = ReturnCode(*)(Runtime*); ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) { From e63b1521f43216f1478519493d35cee8b627cc7a Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 9 Feb 2015 08:17:30 +0100 Subject: [PATCH 069/201] write block header and uncle list --- test/block.cpp | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/test/block.cpp b/test/block.cpp index 518b61238..adf8a3ad9 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -214,11 +214,33 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) cnote << "state sync did throw an exception: " << _e.what(); } - // write block and rlp to json - - //TODO if block rlp is invalid, delete transactions, and block - - + o["rlp"] = "0x" + toHex(theState.blockData()); + + // write block header + + mObject oBlockHeader; + BlockInfo current_BlockHeader = theState.info(); + oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); + oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); + oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); + oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot); + oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot); + oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot); + oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom); + oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty); + oBlockHeader["number"] = toString(current_BlockHeader.number); + oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit); + oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); + oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); + oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); + oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); + + o["blockHeader"] = oBlockHeader; + + // write uncle list + + mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. That might change. + o["uncleHeaders"] = aUncleList; } } } From 2faa67bae22990ad28afede6f650276ff26f7248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 9 Feb 2015 19:21:54 +0100 Subject: [PATCH 070/201] Dynamic stack modification: do not use longjmp in external functions --- libevmjit/Stack.cpp | 96 ++++++++++++++++++++++++++++++++++++--------- libevmjit/Stack.h | 83 ++++++++++++++++++++------------------- 2 files changed, 121 insertions(+), 58 deletions(-) diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 79864f3ca..0afefdd22 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -25,18 +25,81 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); 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}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + 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); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + 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}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + 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); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + return m_builder.CreateLoad(valuePtr); } void Stack::set(size_t _index, llvm::Value* _value) @@ -47,7 +110,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); } void Stack::push(llvm::Value* _value) @@ -67,13 +130,14 @@ extern "C" { using namespace dev::eth::jit; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + return false; stack.erase(stack.end() - _count, stack.end()); + return true; } EXPORT void stack_push(Runtime* _rt, i256 const* _word) @@ -85,22 +149,18 @@ extern "C" Stack::maxStackSize = stack.size(); } - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *o_ret = *(stack.rbegin() + _index); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; } EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; *(stack.rbegin() + _index) = *_word; } diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index f453d14c0..0a549597f 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,40 +1,43 @@ -#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: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#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; +}; + + +} +} +} + + From 7b4892c9162be1834b279894edf08b6c850e1e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 9 Feb 2015 19:21:54 +0100 Subject: [PATCH 071/201] Dynamic stack modification: do not use longjmp in external functions --- evmjit/libevmjit/Stack.cpp | 96 +++++++++++++++++++++++++++++++------- evmjit/libevmjit/Stack.h | 83 ++++++++++++++++---------------- 2 files changed, 121 insertions(+), 58 deletions(-) diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 79864f3ca..0afefdd22 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -25,18 +25,81 @@ Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager): llvm::Type* pushArgTypes[] = {Type::RuntimePtr, Type::WordPtr}; m_push = Function::Create(FunctionType::get(Type::Void, pushArgTypes, false), Linkage::ExternalLinkage, "stack_push", module); - llvm::Type* popArgTypes[] = {Type::RuntimePtr, Type::Size}; - m_pop = Function::Create(FunctionType::get(Type::Void, popArgTypes, false), Linkage::ExternalLinkage, "stack_pop", module); - llvm::Type* getSetArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; - m_get = Function::Create(FunctionType::get(Type::Void, getSetArgTypes, false), Linkage::ExternalLinkage, "stack_get", module); 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}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule()); + auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + 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); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + 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}; + func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); + auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); + + auto rt = &func->getArgumentList().front(); + rt->setName("rt"); + auto index = rt->getNextNode(); + index->setName("index"); + + 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); + + m_builder.SetInsertPoint(underflowBB); + m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_builder.CreateUnreachable(); + + m_builder.SetInsertPoint(returnBB); + m_builder.CreateRet(valuePtr); + } + return func; +} + llvm::Value* Stack::get(size_t _index) { - m_builder.CreateCall3(m_get, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _index, false), m_arg); - return m_builder.CreateLoad(m_arg); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + return m_builder.CreateLoad(valuePtr); } void Stack::set(size_t _index, llvm::Value* _value) @@ -47,7 +110,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - m_builder.CreateCall2(m_pop, m_runtimeManager.getRuntimePtr(), llvm::ConstantInt::get(Type::Size, _count, false)); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); } void Stack::push(llvm::Value* _value) @@ -67,13 +130,14 @@ extern "C" { using namespace dev::eth::jit; - EXPORT void stack_pop(Runtime* _rt, uint64_t _count) + EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) { auto& stack = _rt->getStack(); if (stack.size() < _count) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + return false; stack.erase(stack.end() - _count, stack.end()); + return true; } EXPORT void stack_push(Runtime* _rt, i256 const* _word) @@ -85,22 +149,18 @@ extern "C" Stack::maxStackSize = stack.size(); } - EXPORT void stack_get(Runtime* _rt, uint64_t _index, i256* o_ret) + EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); - - *o_ret = *(stack.rbegin() + _index); + return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; } EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) { auto& stack = _rt->getStack(); - // TODO: encode _index and stack size in the return code - if (stack.size() <= _index) - longjmp(_rt->getJmpBuf(), static_cast(ReturnCode::StackTooSmall)); + assert(_index < stack.size()); + if (_index >= stack.size()) + return; *(stack.rbegin() + _index) = *_word; } diff --git a/evmjit/libevmjit/Stack.h b/evmjit/libevmjit/Stack.h index f453d14c0..0a549597f 100644 --- a/evmjit/libevmjit/Stack.h +++ b/evmjit/libevmjit/Stack.h @@ -1,40 +1,43 @@ -#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: - RuntimeManager& m_runtimeManager; - - llvm::Function* m_push; - llvm::Function* m_pop; - llvm::Function* m_get; - llvm::Function* m_set; - - llvm::Value* m_arg; -}; - - -} -} -} - - +#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; +}; + + +} +} +} + + From f47cd20e8e18aa146a89b2e5c43931507db17d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 00:49:17 +0100 Subject: [PATCH 072/201] Correct usage of LLVM builtin setjmp/longjmp. External setjmp was eliminated, hopefully Windows will be happier now. --- libevmjit/Compiler.cpp | 43 ++++++++++++++++++++++++----------- libevmjit/ExecStats.cpp | 3 ++- libevmjit/ExecutionEngine.cpp | 17 +------------- libevmjit/GasMeter.cpp | 2 +- libevmjit/Runtime.cpp | 3 +-- libevmjit/Runtime.h | 10 +++----- libevmjit/RuntimeManager.cpp | 20 ++++++++++------ libevmjit/RuntimeManager.h | 9 +++++--- libevmjit/Stack.cpp | 26 +++++++++++++-------- 9 files changed, 73 insertions(+), 60 deletions(-) diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 9ad53ce3c..91831e966 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include "preprocessor/llvm_includes_end.h" @@ -89,9 +90,6 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn begin = next; } } - - // TODO: Create Stop basic block on demand - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } llvm::BasicBlock* Compiler::getJumpTableBlock() @@ -134,21 +132,40 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + // 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, _begin, _end); + 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); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); + // 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) { @@ -164,6 +181,9 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera 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 @@ -825,12 +845,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti break; } - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation } } diff --git a/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index deb322521..97a3445b8 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -44,7 +44,8 @@ struct StatsAgg void output(char const* _name, std::ostream& _os) { auto avg = tot / count; - _os << std::setw(12) << std::left << _name + _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() diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 24ed74f15..8ec5cd83c 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -30,21 +30,6 @@ namespace { typedef ReturnCode(*EntryFuncPtr)(Runtime*); -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) -{ - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; -} - std::string codeHash(i256 const& _hash) { static const auto size = sizeof(_hash); @@ -162,7 +147,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + auto returnCode = entryFuncPtr(&runtime); listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 3f3cf2e04..9f73df7da 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -104,7 +104,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_runtimeManager.abort(); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index 09ad7854f..b8466791a 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -10,8 +10,7 @@ namespace jit Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) + m_env(*_env) {} bytes_ref Runtime::getReturnData() const diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 31341d7d3..a24d822e1 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,6 +1,5 @@ #pragma once #include "RuntimeData.h" -#include namespace dev { @@ -11,7 +10,6 @@ namespace jit using StackImpl = std::vector; using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); class Runtime { @@ -26,15 +24,13 @@ public: Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + 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; - std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; }; diff --git a/libevmjit/RuntimeManager.cpp b/libevmjit/RuntimeManager.cpp index 7b3db7477..0b5762fa2 100644 --- a/libevmjit/RuntimeManager.cpp +++ b/libevmjit/RuntimeManager.cpp @@ -83,12 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): +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::longjmp); + 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(); @@ -160,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } -void RuntimeManager::raiseException(ReturnCode _returnCode) +void RuntimeManager::abort(llvm::Value* _jmpBuf) { - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -207,10 +213,10 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBuf() +llvm::Value* RuntimeManager::getJmpBufExt() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); } llvm::Value* RuntimeManager::getGas() diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 92c210289..2fdad3fb5 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -14,7 +14,7 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); @@ -28,12 +28,14 @@ public: 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 raiseException(ReturnCode _returnCode); + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -41,9 +43,10 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); + llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index 0afefdd22..b63660aa9 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -34,14 +34,17 @@ llvm::Function* Stack::getPopFunc() auto& func = m_pop; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + 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()); - auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, 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); @@ -50,10 +53,10 @@ llvm::Function* Stack::getPopFunc() m_builder.SetInsertPoint(entryBB); auto ok = createCall(extPopFunc, {rt, index}); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -67,14 +70,17 @@ llvm::Function* Stack::getGetFunc() auto& func = m_get; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + 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()); - auto extGetFunc = 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); @@ -84,10 +90,10 @@ llvm::Function* Stack::getGetFunc() 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); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -98,7 +104,7 @@ llvm::Function* Stack::getGetFunc() llvm::Value* Stack::get(size_t _index) { - auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); return m_builder.CreateLoad(valuePtr); } @@ -110,7 +116,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); } void Stack::push(llvm::Value* _value) From 5f4bda5cef570026bbde249c0a4454ff6402c1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 00:49:17 +0100 Subject: [PATCH 073/201] Correct usage of LLVM builtin setjmp/longjmp. External setjmp was eliminated, hopefully Windows will be happier now. --- evmjit/libevmjit/Compiler.cpp | 43 +++++++++++++++++++--------- evmjit/libevmjit/ExecStats.cpp | 3 +- evmjit/libevmjit/ExecutionEngine.cpp | 17 +---------- evmjit/libevmjit/GasMeter.cpp | 2 +- evmjit/libevmjit/Runtime.cpp | 3 +- evmjit/libevmjit/Runtime.h | 10 ++----- evmjit/libevmjit/RuntimeManager.cpp | 20 ++++++++----- evmjit/libevmjit/RuntimeManager.h | 9 ++++-- evmjit/libevmjit/Stack.cpp | 26 ++++++++++------- 9 files changed, 73 insertions(+), 60 deletions(-) diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 9ad53ce3c..91831e966 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include "preprocessor/llvm_includes_end.h" @@ -89,9 +90,6 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn begin = next; } } - - // TODO: Create Stop basic block on demand - m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); } llvm::BasicBlock* Compiler::getJumpTableBlock() @@ -134,21 +132,40 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get()); m_mainFunc->getArgumentList().front().setName("rt"); - // Create the basic blocks. - auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); + // 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, _begin, _end); + 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); - m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm()); + // 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) { @@ -164,6 +181,9 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera 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 @@ -825,12 +845,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti break; } - default: // Invalid instruction - runtime exception - { - // TODO: Replace with return statement - _runtimeManager.raiseException(ReturnCode::BadInstruction); - } - + default: // Invalid instruction - abort + m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction)); + it = _basicBlock.end() - 1; // finish block compilation } } diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index deb322521..97a3445b8 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -44,7 +44,8 @@ struct StatsAgg void output(char const* _name, std::ostream& _os) { auto avg = tot / count; - _os << std::setw(12) << std::left << _name + _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() diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 24ed74f15..8ec5cd83c 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -30,21 +30,6 @@ namespace { typedef ReturnCode(*EntryFuncPtr)(Runtime*); -ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime) -{ - // That function uses long jumps to handle "execeptions". - // Do not create any non-POD objects here - - ReturnCode returnCode{}; - auto sj = setjmp(_runtime->getJmpBuf()); - if (sj == 0) - returnCode = _mainFunc(_runtime); - else - returnCode = static_cast(sj); - - return returnCode; -} - std::string codeHash(i256 const& _hash) { static const auto size = sizeof(_hash); @@ -162,7 +147,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) assert(entryFuncPtr); //TODO: Replace it with safe exception listener->stateChanged(ExecState::Execution); - auto returnCode = runEntryFunc(entryFuncPtr, &runtime); + auto returnCode = entryFuncPtr(&runtime); listener->stateChanged(ExecState::Return); if (returnCode == ReturnCode::Return) diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index 3f3cf2e04..9f73df7da 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -104,7 +104,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager) m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.SetInsertPoint(outOfGasBB); - m_runtimeManager.raiseException(ReturnCode::OutOfGas); + m_runtimeManager.abort(); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(updateBB); diff --git a/evmjit/libevmjit/Runtime.cpp b/evmjit/libevmjit/Runtime.cpp index 09ad7854f..b8466791a 100644 --- a/evmjit/libevmjit/Runtime.cpp +++ b/evmjit/libevmjit/Runtime.cpp @@ -10,8 +10,7 @@ namespace jit Runtime::Runtime(RuntimeData* _data, Env* _env) : m_data(*_data), - m_env(*_env), - m_currJmpBuf(m_jmpBuf) + m_env(*_env) {} bytes_ref Runtime::getReturnData() const diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index 31341d7d3..a24d822e1 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -1,6 +1,5 @@ #pragma once #include "RuntimeData.h" -#include namespace dev { @@ -11,7 +10,6 @@ namespace jit using StackImpl = std::vector; using MemoryImpl = bytes; -using jmp_buf_ref = decltype(&std::jmp_buf{}[0]); class Runtime { @@ -26,15 +24,13 @@ public: Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; - jmp_buf_ref getJmpBuf() { return m_jmpBuf; } private: - RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract. - Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract. - jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract. + 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; - std::jmp_buf m_jmpBuf; StackImpl m_stack; MemoryImpl m_memory; }; diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index 7b3db7477..0b5762fa2 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -83,12 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index) } } -RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd): +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::longjmp); + 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(); @@ -160,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress) set(RuntimeData::SuicideDestAddress, _balanceAddress); } -void RuntimeManager::raiseException(ReturnCode _returnCode) +void RuntimeManager::abort(llvm::Value* _jmpBuf) { - m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode)); + auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp); + createCall(longjmp, {_jmpBuf}); } llvm::Value* RuntimeManager::get(Instruction _inst) @@ -207,10 +213,10 @@ llvm::Value* RuntimeManager::getCallDataSize() return getBuilder().CreateZExt(value, Type::Word); } -llvm::Value* RuntimeManager::getJmpBuf() +llvm::Value* RuntimeManager::getJmpBufExt() { - auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr"); - return getBuilder().CreateLoad(ptr, "jmpbuf"); + auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2); + return getBuilder().CreateLoad(ptr, "jmpBufExt"); } llvm::Value* RuntimeManager::getGas() diff --git a/evmjit/libevmjit/RuntimeManager.h b/evmjit/libevmjit/RuntimeManager.h index 92c210289..2fdad3fb5 100644 --- a/evmjit/libevmjit/RuntimeManager.h +++ b/evmjit/libevmjit/RuntimeManager.h @@ -14,7 +14,7 @@ namespace jit class RuntimeManager: public CompilerHelper { public: - RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd); + RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd); llvm::Value* getRuntimePtr(); llvm::Value* getDataPtr(); @@ -28,12 +28,14 @@ public: 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 raiseException(ReturnCode _returnCode); + void abort(llvm::Value* _jmpBuf); + void abort() { abort(getJmpBufExt()); } static llvm::StructType* getRuntimeType(); static llvm::StructType* getRuntimeDataType(); @@ -41,9 +43,10 @@ public: private: llvm::Value* getPtr(RuntimeData::Index _index); void set(RuntimeData::Index _index, llvm::Value* _value); - llvm::Value* getJmpBuf(); + llvm::Value* getJmpBufExt(); llvm::Function* m_longjmp = nullptr; + llvm::Value* const m_jmpBuf; llvm::Value* m_dataPtr = nullptr; llvm::Value* m_envPtr = nullptr; diff --git a/evmjit/libevmjit/Stack.cpp b/evmjit/libevmjit/Stack.cpp index 0afefdd22..b63660aa9 100644 --- a/evmjit/libevmjit/Stack.cpp +++ b/evmjit/libevmjit/Stack.cpp @@ -34,14 +34,17 @@ llvm::Function* Stack::getPopFunc() auto& func = m_pop; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + 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()); - auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, 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); @@ -50,10 +53,10 @@ llvm::Function* Stack::getPopFunc() m_builder.SetInsertPoint(entryBB); auto ok = createCall(extPopFunc, {rt, index}); - m_builder.CreateCondBr(ok, returnBB, underflowBB); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -67,14 +70,17 @@ llvm::Function* Stack::getGetFunc() auto& func = m_get; if (!func) { - llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size}; + 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()); - auto extGetFunc = 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); @@ -84,10 +90,10 @@ llvm::Function* Stack::getGetFunc() 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); + m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight m_builder.SetInsertPoint(underflowBB); - m_runtimeManager.raiseException(ReturnCode::StackTooSmall); + m_runtimeManager.abort(jmpBuf); m_builder.CreateUnreachable(); m_builder.SetInsertPoint(returnBB); @@ -98,7 +104,7 @@ llvm::Function* Stack::getGetFunc() llvm::Value* Stack::get(size_t _index) { - auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)}); + auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); return m_builder.CreateLoad(valuePtr); } @@ -110,7 +116,7 @@ void Stack::set(size_t _index, llvm::Value* _value) void Stack::pop(size_t _count) { - createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)}); + createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); } void Stack::push(llvm::Value* _value) From 6a8c6cba6134d257e2d028a879de47181b8f42db Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 10 Feb 2015 08:35:18 +0100 Subject: [PATCH 074/201] start with test defined genesis block --- libdevcore/RLP.cpp | 2 +- test/TestHelper.h | 3 +- test/blFirstTestFiller.json | 17 ++ test/blValidBlockTestFiller.json | 71 ++++-- test/block.cpp | 365 +++++++++++++++++-------------- 5 files changed, 275 insertions(+), 183 deletions(-) diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp index d72b5c20b..0dd61b876 100644 --- a/libdevcore/RLP.cpp +++ b/libdevcore/RLP.cpp @@ -177,7 +177,7 @@ void RLPStream::noteAppended(unsigned _itemCount) while (m_listStack.size()) { if (m_listStack.back().first < _itemCount) - BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large")); + BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount)); m_listStack.back().first -= _itemCount; if (m_listStack.back().first) break; diff --git a/test/TestHelper.h b/test/TestHelper.h index 344f61a3f..9ac1f0d4d 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -45,7 +45,7 @@ namespace test class ImportTest { public: - ImportTest() = default; + ImportTest(json_spirit::mObject& _o) : m_TestObject(_o) {} ImportTest(json_spirit::mObject& _o, bool isFiller); // imports @@ -53,6 +53,7 @@ public: void importState(json_spirit::mObject& _o, eth::State& _state); void importTransaction(json_spirit::mObject& _o); void exportTest(bytes _output, eth::State& _statePost); + std::map getStateMap(eth::State& _state){return _state.m_cache;} eth::State m_statePre; eth::State m_statePost; diff --git a/test/blFirstTestFiller.json b/test/blFirstTestFiller.json index 0084fda13..d4e6d109f 100644 --- a/test/blFirstTestFiller.json +++ b/test/blFirstTestFiller.json @@ -1,5 +1,22 @@ { "firstBlockTest" : { + "block" : { + "parentHash": "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5", + "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "coinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1", + "stateRoot": "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty": "023101", + "number": "62", + "gasLimit": "0x0dddb6", + "gasUsed": "100", + "timestamp": "0x54c98c81", + "extraData": "42", + "nonce": "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d" + }, + "pre" : {}, "transactions": [{ "nonce": "0", "gasPrice": "0x09184e72a000", diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index ab0369fa4..8b951b179 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -1,20 +1,61 @@ { "validBlock" : { "block" : { - "parentHash": "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5", - "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "coinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1", - "stateRoot": "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "difficulty": "023101", - "number": "62", - "gasLimit": "0x0dddb6", - "gasUsed": "100", - "timestamp": "0x54c98c81", - "extraData": "42", - "nonce": "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d" - } + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "1024", + "extraData" : "42", + "gasLimit" : "0x0dddb6", + "gasUsed" : "100", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "blockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0000000000000000000000000000000000000000", + "difficulty" : "130944", + "extraData" : "", + "gasLimit" : "999023", + "gasUsed" : "4803", + "nonce" : "62778f62183098b7cc8d221fc199654e613ca47b85696f940de3bd2bb6a2a54e", + "number" : "1", + "parentHash" : "c9cb614fddd89b3bc6e2f0ed1f8e58e8a0d826612a607a6151be6f39c991a941", + "receiptTrie" : "8fd35225dd530f30dc39719f9791583309b5889ad79bff0d31e9b1eb12f55000", + "stateRoot" : "b3ef9fe736086bdf1b3cd235f68097aab5f4c6e40d57f417d39c2cc6fb67f6c7", + "timestamp" : "1423490430", + "transactionsTrie" : "2cb4068eb8ccc9124426a7ed5c445b1353c997fc419031254ff7e2768c4dcd7f", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : 0, + "code" : "", + "storage": {} + } + }, + "rlp" : "0xf9033bf9012fa0c9cb614fddd89b3bc6e2f0ed1f8e58e8a0d826612a607a6151be6f39c991a941a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0b3ef9fe736086bdf1b3cd235f68097aab5f4c6e40d57f417d39c2cc6fb67f6c7a02cb4068eb8ccc9124426a7ed5c445b1353c997fc419031254ff7e2768c4dcd7fa08fd35225dd530f30dc39719f9791583309b5889ad79bff0d31e9b1eb12f55000b840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008301ff8001830f3e6f8212c38454d8bd7e80a062778f62183098b7cc8d221fc199654e613ca47b85696f940de3bd2bb6a2a54ef90205f90202808609184e72a000830f3e6f8080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ba0d4287e915ebac7a8af390560fa53c8f0b7f13802ba0393d7afa5823c2560ca89a0ae75db31a34f7e386ad459646de98ec3a1c88cc91b11620b4ffd86871f579942c0", + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "1", + "nonce" : "0", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "27", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] } } + diff --git a/test/block.cpp b/test/block.cpp index adf8a3ad9..9b598bbca 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -32,168 +32,194 @@ namespace dev { namespace test { bytes createBlockRLPFromFields(mObject& _tObj) { - BOOST_REQUIRE(_tObj.count("parentHash") > 0); - BOOST_REQUIRE(_tObj.count("uncleHash") > 0); - BOOST_REQUIRE(_tObj.count("coinbase") > 0); - BOOST_REQUIRE(_tObj.count("stateRoot") > 0); - BOOST_REQUIRE(_tObj.count("transactionsTrie")> 0); - BOOST_REQUIRE(_tObj.count("receiptTrie") > 0); - BOOST_REQUIRE(_tObj.count("bloom") > 0); - BOOST_REQUIRE(_tObj.count("difficulty") > 0); - BOOST_REQUIRE(_tObj.count("number") > 0); - BOOST_REQUIRE(_tObj.count("gasLimit")> 0); - BOOST_REQUIRE(_tObj.count("gasUsed") > 0); - BOOST_REQUIRE(_tObj.count("timestamp") > 0); - BOOST_REQUIRE(_tObj.count("extraData") > 0); - BOOST_REQUIRE(_tObj.count("nonce") > 0); - - // construct RLP of the given block - cout << "done with require\n"; - RLPStream rlpStream; - rlpStream.appendList(14); - cout << "increate aha1\n"; - rlpStream << h256(_tObj["parentHash"].get_str()) << h256(_tObj["uncleHash"].get_str()) << Address(_tObj["coinbase"].get_str()); - rlpStream << h256(_tObj["stateRoot"].get_str()) << h256(_tObj["transactionsTrie"].get_str()) << Address(_tObj["receiptTrie"].get_str()); - rlpStream << LogBloom(_tObj["bloom"].get_str()) << u256(_tObj["difficulty"].get_str()) << u256(_tObj["number"].get_str()); - rlpStream << u256(_tObj["gasLimit"].get_str()) << u256(_tObj["gasUsed"].get_str()) << u256(_tObj["timestamp"].get_str()); - rlpStream << importByteArray(_tObj["extraData"].get_str()) << h256(_tObj["nonce"].get_str()); - - return rlpStream.out(); + BOOST_REQUIRE(_tObj.count("parentHash") > 0); + BOOST_REQUIRE(_tObj.count("uncleHash") > 0); + BOOST_REQUIRE(_tObj.count("coinbase") > 0); + BOOST_REQUIRE(_tObj.count("stateRoot") > 0); + BOOST_REQUIRE(_tObj.count("transactionsTrie")> 0); + BOOST_REQUIRE(_tObj.count("receiptTrie") > 0); + BOOST_REQUIRE(_tObj.count("bloom") > 0); + BOOST_REQUIRE(_tObj.count("difficulty") > 0); + BOOST_REQUIRE(_tObj.count("number") > 0); + BOOST_REQUIRE(_tObj.count("gasLimit")> 0); + BOOST_REQUIRE(_tObj.count("gasUsed") > 0); + BOOST_REQUIRE(_tObj.count("timestamp") > 0); + BOOST_REQUIRE(_tObj.count("extraData") > 0); + BOOST_REQUIRE(_tObj.count("nonce") > 0); + + // construct RLP of the given block + cout << "done with require\n"; + RLPStream rlpStream; + rlpStream.appendList(14); + cout << "increate aha1\n"; + rlpStream << h256(_tObj["parentHash"].get_str()) << h256(_tObj["uncleHash"].get_str()) << Address(_tObj["coinbase"].get_str()); + rlpStream << h256(_tObj["stateRoot"].get_str()) << h256(_tObj["transactionsTrie"].get_str()) << Address(_tObj["receiptTrie"].get_str()); + rlpStream << LogBloom(_tObj["bloom"].get_str()) << u256(_tObj["difficulty"].get_str()) << u256(_tObj["number"].get_str()); + rlpStream << u256(_tObj["gasLimit"].get_str()) << u256(_tObj["gasUsed"].get_str()) << u256(_tObj["timestamp"].get_str()); + rlpStream << importByteArray(_tObj["extraData"].get_str()) << h256(_tObj["nonce"].get_str()); + + return rlpStream.out(); } void doBlockTests(json_spirit::mValue& _v, bool _fillin) { - for (auto& i: _v.get_obj()) - { - cerr << i.first << endl; - mObject& o = i.second.get_obj(); - - if (_fillin == false) - { - BOOST_REQUIRE(o.count("rlp") > 0); - const bytes rlpReaded = importByteArray(o["rlp"].get_str()); - RLP myRLP(rlpReaded); - BlockInfo blockFromRlp; - - try - { - blockFromRlp.populateFromHeader(myRLP, false); - //blockFromRlp.verifyInternals(rlpReaded); - } - catch(Exception const& _e) - { - cnote << "block construction did throw an exception: " << diagnostic_information(_e); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - BOOST_CHECK_MESSAGE(o.count("block") == 0, "A block object should not be defined because the block RLP is invalid!"); - return; - } - - BOOST_REQUIRE(o.count("block") > 0); - - mObject tObj = o["block"].get_obj(); - BlockInfo blockFromFields; - const bytes rlpreade2 = createBlockRLPFromFields(tObj); - RLP mysecondRLP(rlpreade2); - blockFromFields.populateFromHeader(mysecondRLP, false); - - //Check the fields restored from RLP to original fields - BOOST_CHECK_MESSAGE(blockFromFields.hash == blockFromRlp.hash, "hash in given RLP not matching the block hash!"); - BOOST_CHECK_MESSAGE(blockFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); - BOOST_CHECK_MESSAGE(blockFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); - BOOST_CHECK_MESSAGE(blockFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); - BOOST_CHECK_MESSAGE(blockFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); - BOOST_CHECK_MESSAGE(blockFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); - BOOST_CHECK_MESSAGE(blockFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); - BOOST_CHECK_MESSAGE(blockFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); - BOOST_CHECK_MESSAGE(blockFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); - BOOST_CHECK_MESSAGE(blockFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); - BOOST_CHECK_MESSAGE(blockFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); - BOOST_CHECK_MESSAGE(blockFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); - BOOST_CHECK_MESSAGE(blockFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); - - BOOST_CHECK_MESSAGE(blockFromFields == blockFromRlp, "However, blockFromFields != blockFromRlp!"); - - } - else - { -// BOOST_REQUIRE(o.count("block") > 0); - -// // construct Rlp of the given block -// bytes blockRLP = createBlockRLPFromFields(o["block"].get_obj()); -// RLP myRLP(blockRLP); -// o["rlp"] = toHex(blockRLP); + for (auto& i: _v.get_obj()) + { + cerr << i.first << endl; + mObject& o = i.second.get_obj(); + + if (_fillin == false) + { + // TODO + + // BOOST_REQUIRE(o.count("rlp") > 0); + // const bytes rlpReaded = importByteArray(o["rlp"].get_str()); + // RLP myRLP(rlpReaded); + // BlockInfo blockFromRlp; + + // try + // { + // blockFromRlp.populateFromHeader(myRLP, false); + // //blockFromRlp.verifyInternals(rlpReaded); + // } + // catch(Exception const& _e) + // { + // cnote << "block construction did throw an exception: " << diagnostic_information(_e); + // BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + // BOOST_CHECK_MESSAGE(o.count("block") == 0, "A block object should not be defined because the block RLP is invalid!"); + // return; + // } + + // BOOST_REQUIRE(o.count("block") > 0); + + // mObject tObj = o["block"].get_obj(); + // BlockInfo blockFromFields; + // const bytes rlpreade2 = createBlockRLPFromFields(tObj); + // RLP mysecondRLP(rlpreade2); + // blockFromFields.populateFromHeader(mysecondRLP, false); + + // //Check the fields restored from RLP to original fields + // BOOST_CHECK_MESSAGE(blockFromFields.hash == blockFromRlp.hash, "hash in given RLP not matching the block hash!"); + // BOOST_CHECK_MESSAGE(blockFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); + // BOOST_CHECK_MESSAGE(blockFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); + // BOOST_CHECK_MESSAGE(blockFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + // BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); + // BOOST_CHECK_MESSAGE(blockFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); + // BOOST_CHECK_MESSAGE(blockFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); + // BOOST_CHECK_MESSAGE(blockFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); + // BOOST_CHECK_MESSAGE(blockFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); + // BOOST_CHECK_MESSAGE(blockFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); + // BOOST_CHECK_MESSAGE(blockFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); + // BOOST_CHECK_MESSAGE(blockFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); + // BOOST_CHECK_MESSAGE(blockFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); + // BOOST_CHECK_MESSAGE(blockFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); + + // BOOST_CHECK_MESSAGE(blockFromFields == blockFromRlp, "However, blockFromFields != blockFromRlp!"); + + } + else + { + BOOST_REQUIRE(o.count("block") > 0); + + // construct Rlp of the given block + bytes blockRLP = createBlockRLPFromFields(o["block"].get_obj()); + RLP myRLP(blockRLP); + BlockInfo blockFromFields; + cout << "blockFromFields diff:" << blockFromFields.difficulty << endl; -// try -// { -// BlockInfo blockFromFields; -// blockFromFields.populateFromHeader(myRLP, false); -// (void)blockFromFields; -// //blockFromFields.verifyInternals(blockRLP); -// } -// catch (Exception const& _e) -// { -// cnote << "block construction did throw an exception: " << diagnostic_information(_e); -// BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); -// o.erase(o.find("block")); -// } -// catch (std::exception const& _e) -// { -// cnote << "block construction did throw an exception: " << _e.what(); -// BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); -// o.erase(o.find("block")); -// } -// catch(...) -// { -// cnote << "block construction did throw an unknow exception\n"; -// o.erase(o.find("block")); -// } + try + { + + blockFromFields.populateFromHeader(myRLP, false); + //blockFromFields.verifyInternals(blockRLP); + } + catch (Exception const& _e) + { + cnote << "block construction did throw an exception: " << diagnostic_information(_e); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + o.erase(o.find("block")); + } + catch (std::exception const& _e) + { + cnote << "block construction did throw an exception: " << _e.what(); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + o.erase(o.find("block")); + } + catch(...) + { + cnote << "block construction did throw an unknown exception\n"; + o.erase(o.find("block")); + } - BOOST_REQUIRE(o.count("transactions") > 0); + BOOST_REQUIRE(o.count("transactions") > 0); TransactionQueue txs; - for (auto const& txObj: o["transactions"].get_array()) - { - mObject tx = txObj.get_obj(); - BOOST_REQUIRE(tx.count("nonce") > 0); - BOOST_REQUIRE(tx.count("gasPrice") > 0); - BOOST_REQUIRE(tx.count("gasLimit") > 0); - BOOST_REQUIRE(tx.count("to") > 0); - BOOST_REQUIRE(tx.count("value") > 0); - BOOST_REQUIRE(tx.count("v") > 0); - BOOST_REQUIRE(tx.count("r") > 0); - BOOST_REQUIRE(tx.count("s") > 0); - BOOST_REQUIRE(tx.count("data") > 0); + for (auto const& txObj: o["transactions"].get_array()) + { + mObject tx = txObj.get_obj(); + BOOST_REQUIRE(tx.count("nonce") > 0); + BOOST_REQUIRE(tx.count("gasPrice") > 0); + BOOST_REQUIRE(tx.count("gasLimit") > 0); + BOOST_REQUIRE(tx.count("to") > 0); + BOOST_REQUIRE(tx.count("value") > 0); + BOOST_REQUIRE(tx.count("v") > 0); + BOOST_REQUIRE(tx.count("r") > 0); + BOOST_REQUIRE(tx.count("s") > 0); + BOOST_REQUIRE(tx.count("data") > 0); cout << "attempt to import transaction\n"; txs.attemptImport(createTransactionFromFields(tx)); - } + } cout << "done importing txs\n"; + BOOST_REQUIRE(o.count("pre") > 0); + // create state + + ImportTest importer(o["pre"].get_obj()); + State theState(Address(), OverlayDB(), BaseState::Empty); + importer.importState(o["pre"].get_obj(), theState); + + cout << "current state diff 1 : " << theState.info().difficulty << endl; + cout << "balance of a94f5374fce5edbc8e2a8697c15331677e6ebf0b: " << theState.balance(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) << endl; + theState.commit(); + cout << "balance of a94f5374fce5edbc8e2a8697c15331677e6ebf0b: " << theState.balance(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) << endl; + blockFromFields.stateRoot = theState.rootHash(); + cout << "stateRoot: " << blockFromFields.stateRoot << endl; + // find new nonce + ProofOfWork pow; + MineInfo ret; + tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, false); - //BOOST_REQUIRE(o.count("env") > 0); - //BOOST_REQUIRE(o.count("pre") > 0); + // create new "genesis" block" -// ImportTest importer; -// importer.importEnv(o["env"].get_obj()); -// importer.importState(o["pre"].get_obj(), m_statePre); + RLPStream rlpStream; + blockFromFields.streamRLP(rlpStream, WithNonce); -// State theState = importer.m_statePre; -// bytes output; + RLPStream block(3); + block.appendRaw(rlpStream.out()); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + //return block.out(); + cout << "my genesis hash: " << sha3(RLP(block.out())[0].data()) << endl; cout << "construct bc\n"; - CanonBlockChain bc(true); - cout << "construct state\n"; - State theState; + BlockChain bc(block.out(), std::string(), true); + cout << "pre difficulty: " << blockFromFields.difficulty << endl; try { + //cout << "sync state with pre block" << endl; + theState.sync(bc); cout << "sync bc and txs in state\n"; + cout << "balance of a94f5374fce5edbc8e2a8697c15331677e6ebf0b: " << theState.balance(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) << endl; + cout << "current state diff: " << theState.info().difficulty << endl; theState.sync(bc,txs); + cout << "current state diff: " << theState.info().difficulty << endl; // lock cout << "commit to mine\n"; theState.commitToMine(bc); // will call uncommitToMine if a repeat. + cout << "current state diff: " << theState.info().difficulty << endl; // unlock MineInfo info; cout << "mine...\n"; @@ -201,9 +227,11 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) cout << "done mining, completeMine\n"; // lock theState.completeMine(); + cout << "current state diff: " << theState.info().difficulty << endl; // unlock cout << "new block: " << theState.blockData() << endl << theState.info() << endl; + cout << "current diff: " << theState.info().difficulty << endl; } catch (Exception const& _e) { @@ -214,35 +242,35 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) cnote << "state sync did throw an exception: " << _e.what(); } - o["rlp"] = "0x" + toHex(theState.blockData()); - - // write block header - - mObject oBlockHeader; - BlockInfo current_BlockHeader = theState.info(); - oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); - oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); - oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); - oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot); - oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot); - oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot); - oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom); - oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty); - oBlockHeader["number"] = toString(current_BlockHeader.number); - oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit); - oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); - oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); - oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); - oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); - - o["blockHeader"] = oBlockHeader; - - // write uncle list - - mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. That might change. - o["uncleHeaders"] = aUncleList; - } - } + o["rlp"] = "0x" + toHex(theState.blockData()); + + // write block header + + mObject oBlockHeader; + BlockInfo current_BlockHeader = theState.info(); + oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); + oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); + oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); + oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot); + oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot); + oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot); + oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom); + oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty); + oBlockHeader["number"] = toString(current_BlockHeader.number); + oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit); + oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); + oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); + oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); + oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); + + o["blockHeader"] = oBlockHeader; + + // write uncle list + + mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. That will change. + o["uncleHeaders"] = aUncleList; + } + } } } }// Namespace Close @@ -250,9 +278,14 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_AUTO_TEST_SUITE(BlockTests) -BOOST_AUTO_TEST_CASE(blFirstTest) +//BOOST_AUTO_TEST_CASE(blFirstTest) +//{ +// dev::test::executeTests("blFirstTest", "/BlockTests", dev::test::doBlockTests); +//} + +BOOST_AUTO_TEST_CASE(blValidBlockTest) { - dev::test::executeTests("blFirstTest", "/BlockTests", dev::test::doBlockTests); + dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); } //BOOST_AUTO_TEST_CASE(ttCreateTest) From 3c5c3496cf379fd4e63b006c50678e0567f594e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 10:13:47 +0100 Subject: [PATCH 075/201] Helper function name fix --- libevmjit/Arith256.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 6ae62b9d3..17a8e6138 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -85,7 +85,7 @@ llvm::Function* Arith256::getMul512Func() { 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, "mul", getModule()); + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); auto x = &func->getArgumentList().front(); x->setName("x"); From 8b8d9d1df03e0ed3040779ecce94999b2e1e0762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 10:13:47 +0100 Subject: [PATCH 076/201] Helper function name fix --- evmjit/libevmjit/Arith256.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 6ae62b9d3..17a8e6138 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -85,7 +85,7 @@ llvm::Function* Arith256::getMul512Func() { 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, "mul", getModule()); + func = llvm::Function::Create(llvm::FunctionType::get(i512, argTypes, false), llvm::Function::PrivateLinkage, "mul512", getModule()); auto x = &func->getArgumentList().front(); x->setName("x"); From 375ea71e4c4b659c3766bf83b489ab55e22fb5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 14:58:51 +0100 Subject: [PATCH 077/201] Workaround for buggy LLVM shl operator for i512 --- libevmjit/Arith256.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 17a8e6138..21a2f83cb 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -8,6 +8,7 @@ #include "preprocessor/llvm_includes_end.h" #include +#include namespace dev { @@ -27,7 +28,7 @@ void Arith256::debug(llvm::Value* _value, char _c) 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, {_value, m_builder.getInt8(_c)}); + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); } llvm::Function* Arith256::getMulFunc() @@ -97,15 +98,15 @@ llvm::Function* Arith256::getMul512Func() m_builder.SetInsertPoint(bb); auto i128 = m_builder.getIntNTy(128); auto i256 = Type::Word; - auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); - auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); - auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); - auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + 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(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); - auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(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))); @@ -160,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) 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); @@ -325,7 +335,8 @@ llvm::Function* Arith256::getMulModFunc() auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); } return m_mulmod; } @@ -389,6 +400,7 @@ extern "C" { EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; + 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"; } } From 3aa2f066dd7df88a426ff41a9d9bdc06ae3af3a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 14:58:51 +0100 Subject: [PATCH 078/201] Workaround for buggy LLVM shl operator for i512 --- evmjit/libevmjit/Arith256.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 17a8e6138..21a2f83cb 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -8,6 +8,7 @@ #include "preprocessor/llvm_includes_end.h" #include +#include namespace dev { @@ -27,7 +28,7 @@ void Arith256::debug(llvm::Value* _value, char _c) 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, {_value, m_builder.getInt8(_c)}); + createCall(m_debug, {m_builder.CreateZExtOrTrunc(_value, Type::Word), m_builder.getInt8(_c)}); } llvm::Function* Arith256::getMulFunc() @@ -97,15 +98,15 @@ llvm::Function* Arith256::getMul512Func() m_builder.SetInsertPoint(bb); auto i128 = m_builder.getIntNTy(128); auto i256 = Type::Word; - auto x_lo = m_builder.CreateTrunc(x, i128, "x.lo"); - auto y_lo = m_builder.CreateTrunc(y, i128, "y.lo"); - auto x_hi = m_builder.CreateTrunc(m_builder.CreateLShr(x, Constant::get(128)), i128, "x.hi"); - auto y_hi = m_builder.CreateTrunc(m_builder.CreateLShr(y, Constant::get(128)), i128, "y.hi"); + 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(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t2 = createCall(getMulFunc(), {m_builder.CreateZExt(x_lo, i256), m_builder.CreateZExt(y_hi, i256)}); - auto t3 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(y_lo, i256)}); - auto t4 = createCall(getMulFunc(), {m_builder.CreateZExt(x_hi, i256), m_builder.CreateZExt(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))); @@ -160,6 +161,15 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) 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); @@ -325,7 +335,8 @@ llvm::Function* Arith256::getMulModFunc() auto m = m_builder.CreateZExt(mod, i512Ty, "m"); auto d = createCall(getDivFunc(i512Ty), {p, m}); auto r = m_builder.CreateExtractValue(d, 1, "r"); - m_builder.CreateRet(m_builder.CreateTrunc(r, Type::Word)); + r = m_builder.CreateTrunc(r, Type::Word); + m_builder.CreateRet(r); } return m_mulmod; } @@ -389,6 +400,7 @@ extern "C" { EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z) { - std::cerr << "DEBUG " << z << ": " << d << c << b << a << std::endl; + 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"; } } From a50a891cdb1fea6cc7544eac968cdee26ef58811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 16:14:06 +0100 Subject: [PATCH 079/201] Fix wrong prerelease version component parsing --- libevmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 330eaf3c8..7d9a9c8be 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -36,7 +36,7 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} GREATER 0) + if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) endif() endif() From 89db6f0696f0ed4b91ebeee4f206d6fc1ac075c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 16:14:06 +0100 Subject: [PATCH 080/201] Fix wrong prerelease version component parsing --- evmjit/libevmjit/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/libevmjit/CMakeLists.txt b/evmjit/libevmjit/CMakeLists.txt index 330eaf3c8..7d9a9c8be 100644 --- a/evmjit/libevmjit/CMakeLists.txt +++ b/evmjit/libevmjit/CMakeLists.txt @@ -36,7 +36,7 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} GREATER 0) + if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) endif() endif() From 1e79c05859f85a7b842983e50e2fc74af62906cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 10 Feb 2015 18:18:39 +0100 Subject: [PATCH 081/201] Better fix for wrong prerelease version component parsing --- libevmjit/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libevmjit/CMakeLists.txt b/libevmjit/CMakeLists.txt index 7d9a9c8be..943c64e42 100644 --- a/libevmjit/CMakeLists.txt +++ b/libevmjit/CMakeLists.txt @@ -36,8 +36,9 @@ if(${EVMJIT_VERSION_FULL} MATCHES "^v[0-9]+\\.[0-9]+") if(${NUM_VERSION_NUMBERS} GREATER 2) list(GET VERSION_NUMBERS 2 EVMJIT_VERSION_PATCH) # patch number is optional endif() - if(${NUM_VERSION_COMPONENTS} EQUAL 1 OR ${NUM_VERSION_COMPONENTS} EQUAL 3) # git describe add 2 or 0 components - list(GET VERSION_COMPONENTS 1 EVMJIT_VERSION_PRERELEASE) + 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() @@ -49,7 +50,7 @@ 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})") +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 From 7e9b20394deb5346e761024903d4611e81f46b01 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 11 Feb 2015 08:37:54 +0100 Subject: [PATCH 082/201] validate block (the not fill tests path) --- test/blValidBlockTestFiller.json | 27 +-- test/block.cpp | 315 +++++++++++++++++-------------- 2 files changed, 179 insertions(+), 163 deletions(-) diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index 8b951b179..75ad8452e 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -1,37 +1,21 @@ { - "validBlock" : { - "block" : { + "lowGasLimitBoundary" : { + "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "1024", + "difficulty" : "10000", "extraData" : "42", - "gasLimit" : "0x0dddb6", + "gasLimit" : "100000", "gasUsed" : "100", "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", "number" : "0", - "parentHash" : "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", "timestamp" : "0x54c98c81", "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" }, - "blockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0000000000000000000000000000000000000000", - "difficulty" : "130944", - "extraData" : "", - "gasLimit" : "999023", - "gasUsed" : "4803", - "nonce" : "62778f62183098b7cc8d221fc199654e613ca47b85696f940de3bd2bb6a2a54e", - "number" : "1", - "parentHash" : "c9cb614fddd89b3bc6e2f0ed1f8e58e8a0d826612a607a6151be6f39c991a941", - "receiptTrie" : "8fd35225dd530f30dc39719f9791583309b5889ad79bff0d31e9b1eb12f55000", - "stateRoot" : "b3ef9fe736086bdf1b3cd235f68097aab5f4c6e40d57f417d39c2cc6fb67f6c7", - "timestamp" : "1423490430", - "transactionsTrie" : "2cb4068eb8ccc9124426a7ed5c445b1353c997fc419031254ff7e2768c4dcd7f", - "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", @@ -40,7 +24,6 @@ "storage": {} } }, - "rlp" : "0xf9033bf9012fa0c9cb614fddd89b3bc6e2f0ed1f8e58e8a0d826612a607a6151be6f39c991a941a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0b3ef9fe736086bdf1b3cd235f68097aab5f4c6e40d57f417d39c2cc6fb67f6c7a02cb4068eb8ccc9124426a7ed5c445b1353c997fc419031254ff7e2768c4dcd7fa08fd35225dd530f30dc39719f9791583309b5889ad79bff0d31e9b1eb12f55000b840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008301ff8001830f3e6f8212c38454d8bd7e80a062778f62183098b7cc8d221fc199654e613ca47b85696f940de3bd2bb6a2a54ef90205f90202808609184e72a000830f3e6f8080b901ae60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b561ba0d4287e915ebac7a8af390560fa53c8f0b7f13802ba0393d7afa5823c2560ca89a0ae75db31a34f7e386ad459646de98ec3a1c88cc91b11620b4ffd86871f579942c0", "transactions" : [ { "data" : "", diff --git a/test/block.cpp b/test/block.cpp index 9b598bbca..f72e7001d 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -70,86 +70,174 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) if (_fillin == false) { - // TODO - - // BOOST_REQUIRE(o.count("rlp") > 0); - // const bytes rlpReaded = importByteArray(o["rlp"].get_str()); - // RLP myRLP(rlpReaded); - // BlockInfo blockFromRlp; - - // try - // { - // blockFromRlp.populateFromHeader(myRLP, false); - // //blockFromRlp.verifyInternals(rlpReaded); - // } - // catch(Exception const& _e) - // { - // cnote << "block construction did throw an exception: " << diagnostic_information(_e); - // BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - // BOOST_CHECK_MESSAGE(o.count("block") == 0, "A block object should not be defined because the block RLP is invalid!"); - // return; - // } - - // BOOST_REQUIRE(o.count("block") > 0); - - // mObject tObj = o["block"].get_obj(); - // BlockInfo blockFromFields; - // const bytes rlpreade2 = createBlockRLPFromFields(tObj); - // RLP mysecondRLP(rlpreade2); - // blockFromFields.populateFromHeader(mysecondRLP, false); - - // //Check the fields restored from RLP to original fields - // BOOST_CHECK_MESSAGE(blockFromFields.hash == blockFromRlp.hash, "hash in given RLP not matching the block hash!"); - // BOOST_CHECK_MESSAGE(blockFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); - // BOOST_CHECK_MESSAGE(blockFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); - // BOOST_CHECK_MESSAGE(blockFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - // BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); - // BOOST_CHECK_MESSAGE(blockFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); - // BOOST_CHECK_MESSAGE(blockFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); - // BOOST_CHECK_MESSAGE(blockFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); - // BOOST_CHECK_MESSAGE(blockFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); - // BOOST_CHECK_MESSAGE(blockFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); - // BOOST_CHECK_MESSAGE(blockFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); - // BOOST_CHECK_MESSAGE(blockFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); - // BOOST_CHECK_MESSAGE(blockFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); - // BOOST_CHECK_MESSAGE(blockFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); - - // BOOST_CHECK_MESSAGE(blockFromFields == blockFromRlp, "However, blockFromFields != blockFromRlp!"); + BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); + + // construct RLP of the genesis block + bytes blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); + RLP myRLP(blockRLP); + BlockInfo blockFromFields; + + try + { + blockFromFields.populateFromHeader(myRLP, false); + } + catch (Exception const& _e) + { + cnote << "block construction did throw an exception: " << diagnostic_information(_e); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + return; + } + catch (std::exception const& _e) + { + cnote << "block construction did throw an exception: " << _e.what(); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + return; + } + catch(...) + { + cnote << "block construction did throw an unknown exception\n"; + return; + } + + BOOST_REQUIRE(o.count("pre") > 0); + + ImportTest importer(o["pre"].get_obj()); + State theState(Address(), OverlayDB(), BaseState::Empty); + importer.importState(o["pre"].get_obj(), theState); + + // commit changes to DB + theState.commit(); + + BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == theState.rootHash(), "root hash do not match"); + cout << "root hash - no fill in : " << theState.rootHash() << endl; + cout << "root hash - no fill in - from block: " << blockFromFields.stateRoot << endl; + + // create new "genesis" block + RLPStream rlpStream; + blockFromFields.streamRLP(rlpStream, WithNonce); + + RLPStream block(3); + block.appendRaw(rlpStream.out()); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + + blockFromFields.verifyInternals(&block.out()); + + // construc blockchain + BlockChain bc(block.out(), string(), true); + + try + { + theState.sync(bc); + bytes blockRLP = importByteArray(o["rlp"].get_str()); + cout << "import block rlp\n"; + bc.import(blockRLP, theState.db()); + cout << "sync with the state\n"; + theState.sync(bc); + } + // if exception is thrown, RLP is invalid and not blockHeader, Transaction list, and Uncle list should be given + catch (Exception const& _e) + { + cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e); + BOOST_CHECK(o.count("blockHeader") == 0); + BOOST_CHECK(o.count("transactions") == 0); + BOOST_CHECK(o.count("uncleHeaders") == 0); + } + catch (std::exception const& _e) + { + cnote << "state sync or block import did throw an exception: " << _e.what(); + BOOST_CHECK(o.count("blockHeader") == 0); + BOOST_CHECK(o.count("transactions") == 0); + BOOST_CHECK(o.count("uncleHeaders") == 0); + } + catch(...) + { + cnote << "state sync or block import did throw an exception\n"; + BOOST_CHECK(o.count("blockHeader") == 0); + BOOST_CHECK(o.count("transactions") == 0); + BOOST_CHECK(o.count("uncleHeaders") == 0); + } + + + // if yes, check parameters in blockHeader + // check transaction list + // check uncle list + + BOOST_REQUIRE(o.count("blockHeader") > 0); + + mObject tObj = o["blockHeader"].get_obj(); + BlockInfo blockHeaderFromFields; + const bytes rlpBytesBlockHeader = createBlockRLPFromFields(tObj); + RLP blockHeaderRLP(rlpBytesBlockHeader); + blockHeaderFromFields.populateFromHeader(blockHeaderRLP, false); + + BlockInfo blockFromRlp = bc.info(); + + cout << "root hash - no fill in - from state : " << theState.rootHash() << endl; + cout << " hash - no fill in - from rlp : " << blockFromRlp.hash << endl; + cout << " hash - no fill in - from block: " << blockHeaderFromFields.hash << endl; + + //Check the fields restored from RLP to original fields + BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash() == blockFromRlp.headerHash(), "hash in given RLP not matching the block hash!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed, "gasUsed in given RLP not matching the block gasUsed!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.timestamp == blockFromRlp.timestamp, "timestamp in given RLP not matching the block timestamp!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.extraData == blockFromRlp.extraData, "extraData in given RLP not matching the block extraData!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.nonce == blockFromRlp.nonce, "nonce in given RLP not matching the block nonce!"); + + BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); } else { - BOOST_REQUIRE(o.count("block") > 0); + BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); - // construct Rlp of the given block - bytes blockRLP = createBlockRLPFromFields(o["block"].get_obj()); + // construct RLP of the genesis block + bytes blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); RLP myRLP(blockRLP); BlockInfo blockFromFields; - cout << "blockFromFields diff:" << blockFromFields.difficulty << endl; try { - blockFromFields.populateFromHeader(myRLP, false); - //blockFromFields.verifyInternals(blockRLP); } catch (Exception const& _e) { cnote << "block construction did throw an exception: " << diagnostic_information(_e); BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - o.erase(o.find("block")); + return; } catch (std::exception const& _e) { cnote << "block construction did throw an exception: " << _e.what(); BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - o.erase(o.find("block")); + return; } catch(...) { cnote << "block construction did throw an unknown exception\n"; - o.erase(o.find("block")); - } + return; + } + + BOOST_REQUIRE(o.count("pre") > 0); + + ImportTest importer(o["pre"].get_obj()); + State theState(Address(), OverlayDB(), BaseState::Empty); + importer.importState(o["pre"].get_obj(), theState); + + // commit changes to DB + theState.commit(); + + + // fillin specific --- start BOOST_REQUIRE(o.count("transactions") > 0); @@ -167,32 +255,27 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(tx.count("r") > 0); BOOST_REQUIRE(tx.count("s") > 0); BOOST_REQUIRE(tx.count("data") > 0); - cout << "attempt to import transaction\n"; - txs.attemptImport(createTransactionFromFields(tx)); - } - cout << "done importing txs\n"; - - BOOST_REQUIRE(o.count("pre") > 0); - // create state - ImportTest importer(o["pre"].get_obj()); - State theState(Address(), OverlayDB(), BaseState::Empty); - importer.importState(o["pre"].get_obj(), theState); + if (!txs.attemptImport(createTransactionFromFields(tx))) + cnote << "failed importing transaction\n"; + } - cout << "current state diff 1 : " << theState.info().difficulty << endl; - cout << "balance of a94f5374fce5edbc8e2a8697c15331677e6ebf0b: " << theState.balance(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) << endl; - theState.commit(); - cout << "balance of a94f5374fce5edbc8e2a8697c15331677e6ebf0b: " << theState.balance(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) << endl; + // update stateRootHash blockFromFields.stateRoot = theState.rootHash(); - cout << "stateRoot: " << blockFromFields.stateRoot << endl; + cout << "root hash1: " << theState.rootHash() << endl; - // find new nonce + // find new valid nonce ProofOfWork pow; MineInfo ret; tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, false); + //---stop - // create new "genesis" block" + //update genesis block in json file + o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot); + o["genesisBlockHeader"].get_obj()["nonce"] = toString(blockFromFields.nonce); + + // create new "genesis" block RLPStream rlpStream; blockFromFields.streamRLP(rlpStream, WithNonce); @@ -200,46 +283,35 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) block.appendRaw(rlpStream.out()); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); - //return block.out(); - cout << "my genesis hash: " << sha3(RLP(block.out())[0].data()) << endl; - cout << "construct bc\n"; - BlockChain bc(block.out(), std::string(), true); - cout << "pre difficulty: " << blockFromFields.difficulty << endl; + blockFromFields.verifyInternals(&block.out()); + + // construct blockchain + BlockChain bc(block.out(), string(), true); + + try { - //cout << "sync state with pre block" << endl; theState.sync(bc); - cout << "sync bc and txs in state\n"; - cout << "balance of a94f5374fce5edbc8e2a8697c15331677e6ebf0b: " << theState.balance(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) << endl; - cout << "current state diff: " << theState.info().difficulty << endl; + cout << "root hash2: " << theState.rootHash() << endl; theState.sync(bc,txs); - cout << "current state diff: " << theState.info().difficulty << endl; - // lock - cout << "commit to mine\n"; - theState.commitToMine(bc); // will call uncommitToMine if a repeat. - cout << "current state diff: " << theState.info().difficulty << endl; - // unlock + cout << "root hash3: " << theState.rootHash() << endl; + theState.commitToMine(bc); + cout << "root hash4: " << theState.rootHash() << endl; MineInfo info; - cout << "mine...\n"; for (info.completed = false; !info.completed; info = theState.mine()) {} - cout << "done mining, completeMine\n"; - // lock + cout << "root hash5: " << theState.rootHash() << endl; theState.completeMine(); - cout << "current state diff: " << theState.info().difficulty << endl; - // unlock - - cout << "new block: " << theState.blockData() << endl << theState.info() << endl; - cout << "current diff: " << theState.info().difficulty << endl; + cout << "root hash6: " << theState.rootHash() << endl; } catch (Exception const& _e) { - cnote << "state sync did throw an exception: " << diagnostic_information(_e); + cnote << "state sync or mining did throw an exception: " << diagnostic_information(_e); } catch (std::exception const& _e) { - cnote << "state sync did throw an exception: " << _e.what(); + cnote << "state sync or mining did throw an exception: " << _e.what(); } o["rlp"] = "0x" + toHex(theState.blockData()); @@ -267,7 +339,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // write uncle list - mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. That will change. + mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. o["uncleHeaders"] = aUncleList; } } @@ -278,53 +350,14 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_AUTO_TEST_SUITE(BlockTests) -//BOOST_AUTO_TEST_CASE(blFirstTest) -//{ -// dev::test::executeTests("blFirstTest", "/BlockTests", dev::test::doBlockTests); -//} - BOOST_AUTO_TEST_CASE(blValidBlockTest) { dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); } -//BOOST_AUTO_TEST_CASE(ttCreateTest) -//{ -// for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) -// { -// string arg = boost::unit_test::framework::master_test_suite().argv[i]; -// if (arg == "--createtest") -// { -// if (boost::unit_test::framework::master_test_suite().argc <= i + 2) -// { -// cnote << "usage: ./testeth --createtest \n"; -// return; -// } -// try -// { -// cnote << "Populating tests..."; -// json_spirit::mValue v; -// string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1])); -// BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty."); -// json_spirit::read_string(s, v); -// dev::test::doBlockTests(v, true); -// writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true))); -// } -// catch (Exception const& _e) -// { -// BOOST_ERROR("Failed block test with Exception: " << diagnostic_information(_e)); -// } -// catch (std::exception const& _e) -// { -// BOOST_ERROR("Failed block test with Exception: " << _e.what()); -// } -// } -// } -//} - -//BOOST_AUTO_TEST_CASE(userDefinedFileTT) -//{ -// dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); -//} +BOOST_AUTO_TEST_CASE(userDefinedFileBl) +{ + dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); +} BOOST_AUTO_TEST_SUITE_END() From 3ab33165f4fce2e3697d745d6183c2cb47c30022 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 11 Feb 2015 16:36:00 +0100 Subject: [PATCH 083/201] check transactions --- test/TestHelper.cpp | 59 +++++++++++++-------- test/TestHelper.h | 2 +- test/blValidBlockTestFiller.json | 2 +- test/block.cpp | 91 +++++++++++++++++++++++++------- test/transaction.cpp | 44 --------------- 5 files changed, 113 insertions(+), 85 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 43e6106da..ec284d480 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -504,31 +504,48 @@ void executeTests(const string& _name, const string& _testPathAppendix, std::fun } } -bytes createTransactionFromFields(json_spirit::mObject& _tObj) +RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj) { - BOOST_REQUIRE(_tObj.count("data") > 0); - BOOST_REQUIRE(_tObj.count("value") > 0); - BOOST_REQUIRE(_tObj.count("gasPrice") > 0); - BOOST_REQUIRE(_tObj.count("gasLimit") > 0); - BOOST_REQUIRE(_tObj.count("nonce")> 0); - BOOST_REQUIRE(_tObj.count("to") > 0); - - BOOST_REQUIRE(_tObj.count("v") > 0); - BOOST_REQUIRE(_tObj.count("r") > 0); - BOOST_REQUIRE(_tObj.count("s") > 0); - //Construct Rlp of the given transaction RLPStream rlpStream; - rlpStream.appendList(9); - rlpStream << bigint(_tObj["nonce"].get_str()) << bigint(_tObj["gasPrice"].get_str()) << bigint(_tObj["gasLimit"].get_str()); - if (_tObj["to"].get_str().empty()) - rlpStream << ""; - else - rlpStream << Address(_tObj["to"].get_str()); - rlpStream << bigint(_tObj["value"].get_str()) << importData(_tObj); - rlpStream << bigint(_tObj["v"].get_str()) << bigint(_tObj["r"].get_str()) << bigint(_tObj["s"].get_str()); + rlpStream.appendList(_tObj.size()); + + if (_tObj.count("nonce") > 0) + rlpStream << bigint(_tObj["nonce"].get_str()); + + if (_tObj.count("gasPrice") > 0) + rlpStream << bigint(_tObj["gasPrice"].get_str()); + + if (_tObj.count("gasLimit") > 0) + rlpStream << bigint(_tObj["gasLimit"].get_str()); + + if (_tObj.count("to") > 0) + { + if (_tObj["to"].get_str().empty()) + rlpStream << ""; + else + rlpStream << importByteArray(_tObj["to"].get_str()); + } + + if (_tObj.count("value") > 0) + rlpStream << bigint(_tObj["value"].get_str()); + + if (_tObj.count("data") > 0) + rlpStream << importData(_tObj); + + if (_tObj.count("v") > 0) + rlpStream << bigint(_tObj["v"].get_str()); + + if (_tObj.count("r") > 0) + rlpStream << bigint(_tObj["r"].get_str()); + + if (_tObj.count("s") > 0) + rlpStream << bigint(_tObj["s"].get_str()); + + if (_tObj.count("extrafield") > 0) + rlpStream << bigint(_tObj["extrafield"].get_str()); - return rlpStream.out(); + return rlpStream; } diff --git a/test/TestHelper.h b/test/TestHelper.h index 9ac1f0d4d..f7df3a2c0 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -80,7 +80,7 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function doTests); std::string getTestPath(); void userDefinedTest(std::string testTypeFlag, std::function doTests); -bytes createTransactionFromFields(json_spirit::mObject& _tObj); +RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj); void processCommandLineOptions(); eth::LastHashes lastHashes(u256 _currentBlockNumber); diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index 75ad8452e..99f1d32af 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -19,7 +19,7 @@ "pre" : { "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "10000000000", - "nonce" : 0, + "nonce" : "0", "code" : "", "storage": {} } diff --git a/test/block.cpp b/test/block.cpp index f72e7001d..5d9192a26 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -53,10 +53,11 @@ bytes createBlockRLPFromFields(mObject& _tObj) rlpStream.appendList(14); cout << "increate aha1\n"; rlpStream << h256(_tObj["parentHash"].get_str()) << h256(_tObj["uncleHash"].get_str()) << Address(_tObj["coinbase"].get_str()); - rlpStream << h256(_tObj["stateRoot"].get_str()) << h256(_tObj["transactionsTrie"].get_str()) << Address(_tObj["receiptTrie"].get_str()); + rlpStream << h256(_tObj["stateRoot"].get_str()) << h256(_tObj["transactionsTrie"].get_str()) << h256(_tObj["receiptTrie"].get_str()); rlpStream << LogBloom(_tObj["bloom"].get_str()) << u256(_tObj["difficulty"].get_str()) << u256(_tObj["number"].get_str()); rlpStream << u256(_tObj["gasLimit"].get_str()) << u256(_tObj["gasUsed"].get_str()) << u256(_tObj["timestamp"].get_str()); rlpStream << importByteArray(_tObj["extraData"].get_str()) << h256(_tObj["nonce"].get_str()); + cout << "done createBlockRLPFromFields" << endl; return rlpStream.out(); } @@ -105,12 +106,10 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) State theState(Address(), OverlayDB(), BaseState::Empty); importer.importState(o["pre"].get_obj(), theState); - // commit changes to DB + // commit changes to DB theState.commit(); BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == theState.rootHash(), "root hash do not match"); - cout << "root hash - no fill in : " << theState.rootHash() << endl; - cout << "root hash - no fill in - from block: " << blockFromFields.stateRoot << endl; // create new "genesis" block RLPStream rlpStream; @@ -123,17 +122,15 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) blockFromFields.verifyInternals(&block.out()); - // construc blockchain + // construct blockchain BlockChain bc(block.out(), string(), true); try { theState.sync(bc); - bytes blockRLP = importByteArray(o["rlp"].get_str()); - cout << "import block rlp\n"; + bytes blockRLP = importByteArray(o["rlp"].get_str()); bc.import(blockRLP, theState.db()); - cout << "sync with the state\n"; - theState.sync(bc); + theState.sync(bc); } // if exception is thrown, RLP is invalid and not blockHeader, Transaction list, and Uncle list should be given catch (Exception const& _e) @@ -173,18 +170,15 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BlockInfo blockFromRlp = bc.info(); - cout << "root hash - no fill in - from state : " << theState.rootHash() << endl; - cout << " hash - no fill in - from rlp : " << blockFromRlp.hash << endl; - cout << " hash - no fill in - from block: " << blockHeaderFromFields.hash << endl; - //Check the fields restored from RLP to original fields - BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash() == blockFromRlp.headerHash(), "hash in given RLP not matching the block hash!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); @@ -195,6 +189,65 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); + //Check transaction list + + Transactions txsFromField; + + for (auto const& txObj: o["transactions"].get_array()) + { + mObject tx = txObj.get_obj(); + BOOST_REQUIRE(tx.count("nonce") > 0); + BOOST_REQUIRE(tx.count("gasPrice") > 0); + BOOST_REQUIRE(tx.count("gasLimit") > 0); + BOOST_REQUIRE(tx.count("to") > 0); + BOOST_REQUIRE(tx.count("value") > 0); + BOOST_REQUIRE(tx.count("v") > 0); + BOOST_REQUIRE(tx.count("r") > 0); + BOOST_REQUIRE(tx.count("s") > 0); + BOOST_REQUIRE(tx.count("data") > 0); + + Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); + txsFromField.push_back(t); + } + + Transactions txsFromRlp; + bytes blockRLP2 = importByteArray(o["rlp"].get_str()); + RLP root(blockRLP2); + for (auto const& tr: root[1]) + { + Transaction tx(tr.data(), CheckSignature::Sender); + txsFromRlp.push_back(tx); + } + + cout << "size of pending transactions: " << txsFromRlp.size() << endl; + + BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); + + for (size_t i = 0; i < txsFromField.size(); ++i) + { + BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); + + BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "however, transactions in rlp and in field do not match"); + } + + // check uncle list + + BOOST_CHECK_MESSAGE(o["uncleList"].get_array().size() == 0, "Uncle list is not empty, but the genesis block can not have uncles"); + + + + + + + } else { @@ -256,7 +309,9 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(tx.count("s") > 0); BOOST_REQUIRE(tx.count("data") > 0); - if (!txs.attemptImport(createTransactionFromFields(tx))) + //Transaction txFromFields(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); + + if (!txs.attemptImport(&createRLPStreamFromTransactionFields(tx).out())) cnote << "failed importing transaction\n"; } @@ -339,8 +394,8 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // write uncle list - mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. - o["uncleHeaders"] = aUncleList; + mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. + o["uncleHeaders"] = aUncleList; } } } diff --git a/test/transaction.cpp b/test/transaction.cpp index 6a1aa0d84..7ced5a6f4 100644 --- a/test/transaction.cpp +++ b/test/transaction.cpp @@ -29,50 +29,6 @@ using namespace dev::eth; namespace dev { namespace test { -RLPStream createRLPStreamFromTransactionFields(mObject& _tObj) -{ - //Construct Rlp of the given transaction - RLPStream rlpStream; - rlpStream.appendList(_tObj.size()); - - if (_tObj.count("nonce") > 0) - rlpStream << bigint(_tObj["nonce"].get_str()); - - if (_tObj.count("gasPrice") > 0) - rlpStream << bigint(_tObj["gasPrice"].get_str()); - - if (_tObj.count("gasLimit") > 0) - rlpStream << bigint(_tObj["gasLimit"].get_str()); - - if (_tObj.count("to") > 0) - { - if (_tObj["to"].get_str().empty()) - rlpStream << ""; - else - rlpStream << importByteArray(_tObj["to"].get_str()); - } - - if (_tObj.count("value") > 0) - rlpStream << bigint(_tObj["value"].get_str()); - - if (_tObj.count("data") > 0) - rlpStream << importData(_tObj); - - if (_tObj.count("v") > 0) - rlpStream << bigint(_tObj["v"].get_str()); - - if (_tObj.count("r") > 0) - rlpStream << bigint(_tObj["r"].get_str()); - - if (_tObj.count("s") > 0) - rlpStream << bigint(_tObj["s"].get_str()); - - if (_tObj.count("extrafield") > 0) - rlpStream << bigint(_tObj["extrafield"].get_str()); - - return rlpStream; -} - void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { for (auto& i: _v.get_obj()) From f7fcc7c0290dc9196c13113ef43a1dc39a32df4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 11 Feb 2015 17:06:35 +0100 Subject: [PATCH 084/201] Cleanup ExecutionEngine creation --- libevmjit/Arith256.cpp | 1 - libevmjit/ExecutionEngine.cpp | 96 ++++++++++++++--------------------- libevmjit/Runtime.h | 1 - 3 files changed, 39 insertions(+), 59 deletions(-) diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 21a2f83cb..8e1ceb748 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -1,5 +1,4 @@ #include "Arith256.h" -#include "Runtime.h" #include "Type.h" #include "Endianness.h" diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index 30df7f26a..c4c03233c 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -68,81 +68,63 @@ bool showInfo() ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? 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; - static StatsCollector statsCollector; - std::unique_ptr listener{new ExecStats}; listener->stateChanged(ExecState::Started); - auto codeBegin = _data->code; - auto codeEnd = codeBegin + _data->codeSize; - assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(_data->codeHash); - EntryFuncPtr entryFuncPtr{}; - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) + 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 (!ee) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); } - else - { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - std::unique_ptr module; - if (objectCache) - module = Cache::getObject(mainFuncName); + + 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); - module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + 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(); - if (!ee) - { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); - builder.setVerifyModules(true); - - 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 (!ee) - return ReturnCode::LLVMConfigError; - - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - if (objectCache) - ee->setObjectCache(objectCache); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - else - { - if (!entryFuncPtr) - { - ee->addModule(module.get()); - module.release(); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - } + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } assert(entryFuncPtr); //TODO: Replace it with safe exception diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index a24d822e1..9ea3039a0 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -21,7 +21,6 @@ public: StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } - Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; From c95c1c81f43b42d536f15ec56ee53043e2701d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 11 Feb 2015 17:06:35 +0100 Subject: [PATCH 085/201] Cleanup ExecutionEngine creation --- evmjit/libevmjit/Arith256.cpp | 1 - evmjit/libevmjit/ExecutionEngine.cpp | 96 +++++++++++----------------- evmjit/libevmjit/Runtime.h | 1 - 3 files changed, 39 insertions(+), 59 deletions(-) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index 21a2f83cb..8e1ceb748 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -1,5 +1,4 @@ #include "Arith256.h" -#include "Runtime.h" #include "Type.h" #include "Endianness.h" diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index 30df7f26a..c4c03233c 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -68,81 +68,63 @@ bool showInfo() ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) { - static std::unique_ptr ee; // TODO: Use Managed Objects from LLVM? 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; - static StatsCollector statsCollector; - std::unique_ptr listener{new ExecStats}; listener->stateChanged(ExecState::Started); - auto codeBegin = _data->code; - auto codeEnd = codeBegin + _data->codeSize; - assert(codeBegin || !codeEnd); //TODO: Is it good idea to execute empty code? - auto mainFuncName = codeHash(_data->codeHash); - EntryFuncPtr entryFuncPtr{}; - Runtime runtime(_data, _env); // TODO: I don't know why but it must be created before getFunctionAddress() calls + auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - if (ee && (entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName))) + 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 (!ee) + return ReturnCode::LLVMConfigError; + module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module + ee->setObjectCache(objectCache); } - else - { - auto objectCache = objectCacheEnabled ? Cache::getObjectCache(listener.get()) : nullptr; - std::unique_ptr module; - if (objectCache) - module = Cache::getObject(mainFuncName); + + 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); - module = Compiler({}).compile(codeBegin, codeEnd, mainFuncName); + 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(); - if (!ee) - { - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - std::unique_ptr memoryManager(new llvm::SectionMemoryManager); - builder.setMCJITMemoryManager(memoryManager.get()); - builder.setOptLevel(llvm::CodeGenOpt::None); - builder.setVerifyModules(true); - - 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 (!ee) - return ReturnCode::LLVMConfigError; - - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module - memoryManager.release(); // and memory manager - - if (objectCache) - ee->setObjectCache(objectCache); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - else - { - if (!entryFuncPtr) - { - ee->addModule(module.get()); - module.release(); - listener->stateChanged(ExecState::CodeGen); - entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); - } - } + + ee->addModule(module.get()); + module.release(); + listener->stateChanged(ExecState::CodeGen); + entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } assert(entryFuncPtr); //TODO: Replace it with safe exception diff --git a/evmjit/libevmjit/Runtime.h b/evmjit/libevmjit/Runtime.h index a24d822e1..9ea3039a0 100644 --- a/evmjit/libevmjit/Runtime.h +++ b/evmjit/libevmjit/Runtime.h @@ -21,7 +21,6 @@ public: StackImpl& getStack() { return m_stack; } MemoryImpl& getMemory() { return m_memory; } - Env* getEnvPtr() { return &m_env; } bytes_ref getReturnData() const; From 7fb9e980cf41d1577d352fbfeaefbbc0bcb8c486 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 11 Feb 2015 18:17:01 +0100 Subject: [PATCH 086/201] avoid code doubling --- test/block.cpp | 514 +++++++++++++++++++++---------------------------- 1 file changed, 223 insertions(+), 291 deletions(-) diff --git a/test/block.cpp b/test/block.cpp index 5d9192a26..bfc7c01d6 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -69,96 +69,183 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) cerr << i.first << endl; mObject& o = i.second.get_obj(); - if (_fillin == false) - { - BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); - - // construct RLP of the genesis block - bytes blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); - RLP myRLP(blockRLP); - BlockInfo blockFromFields; - - try - { - blockFromFields.populateFromHeader(myRLP, false); - } - catch (Exception const& _e) - { - cnote << "block construction did throw an exception: " << diagnostic_information(_e); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - return; - } - catch (std::exception const& _e) - { - cnote << "block construction did throw an exception: " << _e.what(); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - return; - } - catch(...) - { - cnote << "block construction did throw an unknown exception\n"; - return; - } - - BOOST_REQUIRE(o.count("pre") > 0); - - ImportTest importer(o["pre"].get_obj()); - State theState(Address(), OverlayDB(), BaseState::Empty); - importer.importState(o["pre"].get_obj(), theState); - - // commit changes to DB - theState.commit(); - - BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == theState.rootHash(), "root hash do not match"); - - // create new "genesis" block - RLPStream rlpStream; - blockFromFields.streamRLP(rlpStream, WithNonce); - - RLPStream block(3); - block.appendRaw(rlpStream.out()); - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - - blockFromFields.verifyInternals(&block.out()); - - // construct blockchain - BlockChain bc(block.out(), string(), true); - - try - { - theState.sync(bc); - bytes blockRLP = importByteArray(o["rlp"].get_str()); + BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); + + // construct RLP of the genesis block + bytes blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); + RLP myRLP(blockRLP); + BlockInfo blockFromFields; + + try + { + blockFromFields.populateFromHeader(myRLP, false); + } + catch (Exception const& _e) + { + cnote << "block construction did throw an exception: " << diagnostic_information(_e); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + return; + } + catch (std::exception const& _e) + { + cnote << "block construction did throw an exception: " << _e.what(); + BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + return; + } + catch(...) + { + cnote << "block construction did throw an unknown exception\n"; + return; + } + + BOOST_REQUIRE(o.count("pre") > 0); + + ImportTest importer(o["pre"].get_obj()); + State theState(Address(), OverlayDB(), BaseState::Empty); + importer.importState(o["pre"].get_obj(), theState); + + // commit changes to DB + theState.commit(); + + if (_fillin) + blockFromFields.stateRoot = theState.rootHash(); + else + BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == theState.rootHash(), "root hash do not match"); + + if (_fillin) + { + // find new valid nonce + ProofOfWork pow; + MineInfo ret; + tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, false); + + //update genesis block in json file + o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot); + o["genesisBlockHeader"].get_obj()["nonce"] = toString(blockFromFields.nonce); + } + + // create new "genesis" block + RLPStream rlpStream; + blockFromFields.streamRLP(rlpStream, WithNonce); + + RLPStream block(3); + block.appendRaw(rlpStream.out()); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + + blockFromFields.verifyInternals(&block.out()); + + // construct blockchain + BlockChain bc(block.out(), string(), true); + + if (_fillin) + { + BOOST_REQUIRE(o.count("transactions") > 0); + + TransactionQueue txs; + + for (auto const& txObj: o["transactions"].get_array()) + { + mObject tx = txObj.get_obj(); + BOOST_REQUIRE(tx.count("nonce") > 0); + BOOST_REQUIRE(tx.count("gasPrice") > 0); + BOOST_REQUIRE(tx.count("gasLimit") > 0); + BOOST_REQUIRE(tx.count("to") > 0); + BOOST_REQUIRE(tx.count("value") > 0); + BOOST_REQUIRE(tx.count("v") > 0); + BOOST_REQUIRE(tx.count("r") > 0); + BOOST_REQUIRE(tx.count("s") > 0); + BOOST_REQUIRE(tx.count("data") > 0); + + //Transaction txFromFields(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); + + if (!txs.attemptImport(&createRLPStreamFromTransactionFields(tx).out())) + cnote << "failed importing transaction\n"; + } + + try + { + theState.sync(bc); + theState.sync(bc,txs); + theState.commitToMine(bc); + MineInfo info; + for (info.completed = false; !info.completed; info = theState.mine()) {} + theState.completeMine(); + } + catch (Exception const& _e) + { + cnote << "state sync or mining did throw an exception: " << diagnostic_information(_e); + } + catch (std::exception const& _e) + { + cnote << "state sync or mining did throw an exception: " << _e.what(); + } + + o["rlp"] = "0x" + toHex(theState.blockData()); + + // write block header + + mObject oBlockHeader; + BlockInfo current_BlockHeader = theState.info(); + oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); + oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); + oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); + oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot); + oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot); + oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot); + oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom); + oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty); + oBlockHeader["number"] = toString(current_BlockHeader.number); + oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit); + oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); + oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); + oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); + oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); + + o["blockHeader"] = oBlockHeader; + + // write uncle list + + mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. + o["uncleHeaders"] = aUncleList; + } + + else + { + try + { + theState.sync(bc); + bytes blockRLP = importByteArray(o["rlp"].get_str()); bc.import(blockRLP, theState.db()); - theState.sync(bc); - } + theState.sync(bc); + } // if exception is thrown, RLP is invalid and not blockHeader, Transaction list, and Uncle list should be given - catch (Exception const& _e) - { - cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e); + catch (Exception const& _e) + { + cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e); BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); - } - catch (std::exception const& _e) - { - cnote << "state sync or block import did throw an exception: " << _e.what(); + } + catch (std::exception const& _e) + { + cnote << "state sync or block import did throw an exception: " << _e.what(); BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); - } - catch(...) - { + } + catch(...) + { cnote << "state sync or block import did throw an exception\n"; - BOOST_CHECK(o.count("blockHeader") == 0); - BOOST_CHECK(o.count("transactions") == 0); - BOOST_CHECK(o.count("uncleHeaders") == 0); - } + BOOST_CHECK(o.count("blockHeader") == 0); + BOOST_CHECK(o.count("transactions") == 0); + BOOST_CHECK(o.count("uncleHeaders") == 0); + } - // if yes, check parameters in blockHeader - // check transaction list - // check uncle list + // if yes, check parameters in blockHeader + // check transaction list + // check uncle list BOOST_REQUIRE(o.count("blockHeader") > 0); @@ -171,14 +258,14 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BlockInfo blockFromRlp = bc.info(); //Check the fields restored from RLP to original fields - BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles, "sha3Uncles in given RLP not matching the block sha3Uncles!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress,"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot, "stateRoot in given RLP not matching the block stateRoot!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot, "transactionsRoot in given RLP not matching the block transactionsRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!"); - BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot, "receiptsRoot in given RLP not matching the block receiptsRoot!"); + BOOST_CHECK_MESSAGE(blockHeaderFromFields.logBloom == blockFromRlp.logBloom, "logBloom in given RLP not matching the block logBloom!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.difficulty == blockFromRlp.difficulty, "difficulty in given RLP not matching the block difficulty!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.number == blockFromRlp.number, "number in given RLP not matching the block number!"); BOOST_CHECK_MESSAGE(blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit,"gasLimit in given RLP not matching the block gasLimit!"); @@ -189,215 +276,60 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); - //Check transaction list - - Transactions txsFromField; - - for (auto const& txObj: o["transactions"].get_array()) - { - mObject tx = txObj.get_obj(); - BOOST_REQUIRE(tx.count("nonce") > 0); - BOOST_REQUIRE(tx.count("gasPrice") > 0); - BOOST_REQUIRE(tx.count("gasLimit") > 0); - BOOST_REQUIRE(tx.count("to") > 0); - BOOST_REQUIRE(tx.count("value") > 0); - BOOST_REQUIRE(tx.count("v") > 0); - BOOST_REQUIRE(tx.count("r") > 0); - BOOST_REQUIRE(tx.count("s") > 0); - BOOST_REQUIRE(tx.count("data") > 0); - - Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); - txsFromField.push_back(t); - } - - Transactions txsFromRlp; - bytes blockRLP2 = importByteArray(o["rlp"].get_str()); - RLP root(blockRLP2); - for (auto const& tr: root[1]) - { - Transaction tx(tr.data(), CheckSignature::Sender); - txsFromRlp.push_back(tx); - } - - cout << "size of pending transactions: " << txsFromRlp.size() << endl; - - BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); - - for (size_t i = 0; i < txsFromField.size(); ++i) - { - BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); - - BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "however, transactions in rlp and in field do not match"); - } - - // check uncle list - - BOOST_CHECK_MESSAGE(o["uncleList"].get_array().size() == 0, "Uncle list is not empty, but the genesis block can not have uncles"); - - - - - - - - } - else - { - BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); - - // construct RLP of the genesis block - bytes blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); - RLP myRLP(blockRLP); - BlockInfo blockFromFields; - - try - { - blockFromFields.populateFromHeader(myRLP, false); - } - catch (Exception const& _e) - { - cnote << "block construction did throw an exception: " << diagnostic_information(_e); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - return; - } - catch (std::exception const& _e) - { - cnote << "block construction did throw an exception: " << _e.what(); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); - return; - } - catch(...) - { - cnote << "block construction did throw an unknown exception\n"; - return; - } - - BOOST_REQUIRE(o.count("pre") > 0); - - ImportTest importer(o["pre"].get_obj()); - State theState(Address(), OverlayDB(), BaseState::Empty); - importer.importState(o["pre"].get_obj(), theState); - - // commit changes to DB - theState.commit(); - - - // fillin specific --- start - - BOOST_REQUIRE(o.count("transactions") > 0); - - TransactionQueue txs; - - for (auto const& txObj: o["transactions"].get_array()) - { - mObject tx = txObj.get_obj(); - BOOST_REQUIRE(tx.count("nonce") > 0); - BOOST_REQUIRE(tx.count("gasPrice") > 0); - BOOST_REQUIRE(tx.count("gasLimit") > 0); - BOOST_REQUIRE(tx.count("to") > 0); - BOOST_REQUIRE(tx.count("value") > 0); - BOOST_REQUIRE(tx.count("v") > 0); - BOOST_REQUIRE(tx.count("r") > 0); - BOOST_REQUIRE(tx.count("s") > 0); - BOOST_REQUIRE(tx.count("data") > 0); - - //Transaction txFromFields(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); - - if (!txs.attemptImport(&createRLPStreamFromTransactionFields(tx).out())) - cnote << "failed importing transaction\n"; - } - - // update stateRootHash - blockFromFields.stateRoot = theState.rootHash(); - cout << "root hash1: " << theState.rootHash() << endl; - - // find new valid nonce - ProofOfWork pow; - MineInfo ret; - tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, false); - //---stop - - //update genesis block in json file - o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot); - o["genesisBlockHeader"].get_obj()["nonce"] = toString(blockFromFields.nonce); - - - // create new "genesis" block - RLPStream rlpStream; - blockFromFields.streamRLP(rlpStream, WithNonce); - - RLPStream block(3); - block.appendRaw(rlpStream.out()); - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - - blockFromFields.verifyInternals(&block.out()); - - // construct blockchain - BlockChain bc(block.out(), string(), true); - - - - try - { - theState.sync(bc); - cout << "root hash2: " << theState.rootHash() << endl; - theState.sync(bc,txs); - cout << "root hash3: " << theState.rootHash() << endl; - theState.commitToMine(bc); - cout << "root hash4: " << theState.rootHash() << endl; - MineInfo info; - for (info.completed = false; !info.completed; info = theState.mine()) {} - cout << "root hash5: " << theState.rootHash() << endl; - theState.completeMine(); - cout << "root hash6: " << theState.rootHash() << endl; - } - catch (Exception const& _e) - { - cnote << "state sync or mining did throw an exception: " << diagnostic_information(_e); - } - catch (std::exception const& _e) - { - cnote << "state sync or mining did throw an exception: " << _e.what(); - } - - o["rlp"] = "0x" + toHex(theState.blockData()); - - // write block header - - mObject oBlockHeader; - BlockInfo current_BlockHeader = theState.info(); - oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); - oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); - oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); - oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot); - oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot); - oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot); - oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom); - oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty); - oBlockHeader["number"] = toString(current_BlockHeader.number); - oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit); - oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); - oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); - oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); - oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); - - o["blockHeader"] = oBlockHeader; - - // write uncle list - - mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. - o["uncleHeaders"] = aUncleList; - } - } + //Check transaction list + + Transactions txsFromField; + + for (auto const& txObj: o["transactions"].get_array()) + { + mObject tx = txObj.get_obj(); + BOOST_REQUIRE(tx.count("nonce") > 0); + BOOST_REQUIRE(tx.count("gasPrice") > 0); + BOOST_REQUIRE(tx.count("gasLimit") > 0); + BOOST_REQUIRE(tx.count("to") > 0); + BOOST_REQUIRE(tx.count("value") > 0); + BOOST_REQUIRE(tx.count("v") > 0); + BOOST_REQUIRE(tx.count("r") > 0); + BOOST_REQUIRE(tx.count("s") > 0); + BOOST_REQUIRE(tx.count("data") > 0); + + Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); + txsFromField.push_back(t); + } + + Transactions txsFromRlp; + bytes blockRLP2 = importByteArray(o["rlp"].get_str()); + RLP root(blockRLP2); + for (auto const& tr: root[1]) + { + Transaction tx(tr.data(), CheckSignature::Sender); + txsFromRlp.push_back(tx); + } + + cout << "size of pending transactions: " << txsFromRlp.size() << endl; + + BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); + + for (size_t i = 0; i < txsFromField.size(); ++i) + { + BOOST_CHECK_MESSAGE(txsFromField[i].data() == txsFromRlp[i].data(), "transaction data in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].gas() == txsFromRlp[i].gas(), "transaction gasLimit in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].gasPrice() == txsFromRlp[i].gasPrice(), "transaction gasPrice in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].nonce() == txsFromRlp[i].nonce(), "transaction nonce in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().r == txsFromRlp[i].signature().r, "transaction r in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().s == txsFromRlp[i].signature().s, "transaction s in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].signature().v == txsFromRlp[i].signature().v, "transaction v in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); + + BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "however, transactions in rlp and in field do not match"); + } + + // check uncle list + + BOOST_CHECK_MESSAGE((o["uncleList"].type() == json_spirit::null_type ? 0 : o["uncleList"].get_array().size()) == 0, "Uncle list is not empty, but the genesis block can not have uncles"); + } + } } } }// Namespace Close From de0b52ec696e2fbc30ebe04d3b17e4256c31bf47 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Wed, 11 Feb 2015 22:05:34 +0100 Subject: [PATCH 087/201] style --- test/block.cpp | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/test/block.cpp b/test/block.cpp index bfc7c01d6..88f7de634 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -48,16 +48,13 @@ bytes createBlockRLPFromFields(mObject& _tObj) BOOST_REQUIRE(_tObj.count("nonce") > 0); // construct RLP of the given block - cout << "done with require\n"; RLPStream rlpStream; rlpStream.appendList(14); - cout << "increate aha1\n"; rlpStream << h256(_tObj["parentHash"].get_str()) << h256(_tObj["uncleHash"].get_str()) << Address(_tObj["coinbase"].get_str()); rlpStream << h256(_tObj["stateRoot"].get_str()) << h256(_tObj["transactionsTrie"].get_str()) << h256(_tObj["receiptTrie"].get_str()); rlpStream << LogBloom(_tObj["bloom"].get_str()) << u256(_tObj["difficulty"].get_str()) << u256(_tObj["number"].get_str()); rlpStream << u256(_tObj["gasLimit"].get_str()) << u256(_tObj["gasUsed"].get_str()) << u256(_tObj["timestamp"].get_str()); rlpStream << importByteArray(_tObj["extraData"].get_str()) << h256(_tObj["nonce"].get_str()); - cout << "done createBlockRLPFromFields" << endl; return rlpStream.out(); } @@ -72,45 +69,44 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); // construct RLP of the genesis block - bytes blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); - RLP myRLP(blockRLP); + const bytes c_blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); + const RLP c_bRLP(c_blockRLP); BlockInfo blockFromFields; try { - blockFromFields.populateFromHeader(myRLP, false); + blockFromFields.populateFromHeader(c_bRLP, false); } catch (Exception const& _e) { - cnote << "block construction did throw an exception: " << diagnostic_information(_e); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + cnote << "block population did throw an exception: " << diagnostic_information(_e); + BOOST_ERROR("Failed block population with Exception: " << _e.what()); return; } catch (std::exception const& _e) { - cnote << "block construction did throw an exception: " << _e.what(); - BOOST_ERROR("Failed block construction Test with Exception: " << _e.what()); + BOOST_ERROR("Failed block population with Exception: " << _e.what()); return; } catch(...) { - cnote << "block construction did throw an unknown exception\n"; + cnote << "block population did throw an unknown exception\n"; return; } BOOST_REQUIRE(o.count("pre") > 0); ImportTest importer(o["pre"].get_obj()); - State theState(Address(), OverlayDB(), BaseState::Empty); - importer.importState(o["pre"].get_obj(), theState); + State state(Address(), OverlayDB(), BaseState::Empty); + importer.importState(o["pre"].get_obj(), state); // commit changes to DB - theState.commit(); + state.commit(); if (_fillin) - blockFromFields.stateRoot = theState.rootHash(); + blockFromFields.stateRoot = state.rootHash(); else - BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == theState.rootHash(), "root hash do not match"); + BOOST_CHECK_MESSAGE(blockFromFields.stateRoot == state.rootHash(), "root hash does not match"); if (_fillin) { @@ -165,12 +161,12 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) try { - theState.sync(bc); - theState.sync(bc,txs); - theState.commitToMine(bc); + state.sync(bc); + state.sync(bc,txs); + state.commitToMine(bc); MineInfo info; - for (info.completed = false; !info.completed; info = theState.mine()) {} - theState.completeMine(); + for (info.completed = false; !info.completed; info = state.mine()) {} + state.completeMine(); } catch (Exception const& _e) { @@ -181,12 +177,12 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) cnote << "state sync or mining did throw an exception: " << _e.what(); } - o["rlp"] = "0x" + toHex(theState.blockData()); + o["rlp"] = "0x" + toHex(state.blockData()); // write block header mObject oBlockHeader; - BlockInfo current_BlockHeader = theState.info(); + BlockInfo current_BlockHeader = state.info(); oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); @@ -214,10 +210,10 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) { try { - theState.sync(bc); + state.sync(bc); bytes blockRLP = importByteArray(o["rlp"].get_str()); - bc.import(blockRLP, theState.db()); - theState.sync(bc); + bc.import(blockRLP, state.db()); + state.sync(bc); } // if exception is thrown, RLP is invalid and not blockHeader, Transaction list, and Uncle list should be given catch (Exception const& _e) From 93cb4866fd4c5869e37f345c81fe7ab2a9720029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 10:26:11 +0100 Subject: [PATCH 088/201] Includes reordering, GCC conversion warnings enabled Includes order as described in Coding Standards of cpp-ethereum project. GCC warnings about lossy conversions enabled. --- CMakeLists.txt | 2 +- libevmjit/Arith256.cpp | 9 +- libevmjit/Arith256.h | 1 + libevmjit/BasicBlock.cpp | 5 +- libevmjit/BasicBlock.h | 4 +- libevmjit/Cache.cpp | 7 +- libevmjit/Cache.h | 4 +- libevmjit/Common.h | 1 + libevmjit/Compiler.cpp | 29 ++-- libevmjit/Compiler.h | 1 + libevmjit/CompilerHelper.cpp | 98 ++++++------ libevmjit/CompilerHelper.h | 154 +++++++++---------- libevmjit/Endianness.cpp | 77 +++++----- libevmjit/Endianness.h | 50 +++--- libevmjit/ExecStats.cpp | 1 + libevmjit/ExecStats.h | 4 +- libevmjit/ExecutionEngine.cpp | 17 +- libevmjit/ExecutionEngine.h | 4 +- libevmjit/Ext.cpp | 9 +- libevmjit/Ext.h | 4 +- libevmjit/GasMeter.cpp | 8 +- libevmjit/GasMeter.h | 1 + libevmjit/Instruction.h | 1 + libevmjit/Memory.cpp | 9 +- libevmjit/Memory.h | 1 + libevmjit/Runtime.cpp | 1 + libevmjit/Runtime.h | 79 +++++----- libevmjit/RuntimeData.h | 1 + libevmjit/RuntimeManager.h | 1 + libevmjit/Stack.cpp | 7 +- libevmjit/Stack.h | 1 + libevmjit/Type.h | 3 +- libevmjit/preprocessor/llvm_includes_end.h | 8 +- libevmjit/preprocessor/llvm_includes_start.h | 13 +- 34 files changed, 329 insertions(+), 286 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce05c422d..8f3a170d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/libevmjit/Arith256.cpp b/libevmjit/Arith256.cpp index 8e1ceb748..ddf06b463 100644 --- a/libevmjit/Arith256.cpp +++ b/libevmjit/Arith256.cpp @@ -1,13 +1,14 @@ #include "Arith256.h" -#include "Type.h" -#include "Endianness.h" + +#include +#include #include "preprocessor/llvm_includes_start.h" #include #include "preprocessor/llvm_includes_end.h" -#include -#include +#include "Type.h" +#include "Endianness.h" namespace dev { diff --git a/libevmjit/Arith256.h b/libevmjit/Arith256.h index 4b94652d8..2513ca568 100644 --- a/libevmjit/Arith256.h +++ b/libevmjit/Arith256.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/BasicBlock.cpp b/libevmjit/BasicBlock.cpp index 112e9d652..c9e71be9a 100644 --- a/libevmjit/BasicBlock.cpp +++ b/libevmjit/BasicBlock.cpp @@ -1,5 +1,6 @@ #include "BasicBlock.h" -#include "Type.h" + +#include #include "preprocessor/llvm_includes_start.h" #include @@ -9,7 +10,7 @@ #include #include "preprocessor/llvm_includes_end.h" -#include +#include "Type.h" namespace dev { diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index 0f639602a..7469b7b69 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -1,7 +1,9 @@ #pragma once + +#include + #include "Common.h" #include "Stack.h" -#include namespace dev { diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index 64015a820..d7d6f1bbb 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -1,5 +1,7 @@ #include "Cache.h" -#include "ExecutionEngine.h" + +#include +#include #include "preprocessor/llvm_includes_start.h" #include @@ -10,8 +12,7 @@ #include #include "preprocessor/llvm_includes_end.h" -#include -#include +#include "ExecutionEngine.h" namespace dev { diff --git a/libevmjit/Cache.h b/libevmjit/Cache.h index 18f9237f1..e8f01d38d 100644 --- a/libevmjit/Cache.h +++ b/libevmjit/Cache.h @@ -1,7 +1,9 @@ #pragma once -#include + #include +#include + namespace dev { namespace eth diff --git a/libevmjit/Common.h b/libevmjit/Common.h index cd7177e67..62731292f 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -1,4 +1,5 @@ #pragma once + #include #include #include diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 91831e966..de48e8ef9 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -1,14 +1,9 @@ #include "Compiler.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" + +#include +#include +#include +#include #include "preprocessor/llvm_includes_start.h" #include @@ -20,10 +15,16 @@ #include #include "preprocessor/llvm_includes_end.h" -#include -#include -#include -#include +#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 { diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 30130798c..c9795fb99 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -1,4 +1,5 @@ #pragma once + #include "Common.h" #include "BasicBlock.h" diff --git a/libevmjit/CompilerHelper.cpp b/libevmjit/CompilerHelper.cpp index bf2929429..5c8ee8574 100644 --- a/libevmjit/CompilerHelper.cpp +++ b/libevmjit/CompilerHelper.cpp @@ -1,47 +1,51 @@ -#include "CompilerHelper.h" -#include "RuntimeManager.h" -#include - -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) -{} - -} -} -} +#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/libevmjit/CompilerHelper.h b/libevmjit/CompilerHelper.h index 912f7e93f..cd6d09a58 100644 --- a/libevmjit/CompilerHelper.h +++ b/libevmjit/CompilerHelper.h @@ -1,79 +1,79 @@ -#pragma once +#pragma once -#include "preprocessor/llvm_includes_start.h" +#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; -}; - -} -} -} +#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/libevmjit/Endianness.cpp b/libevmjit/Endianness.cpp index f3ee4c783..38f71560c 100644 --- a/libevmjit/Endianness.cpp +++ b/libevmjit/Endianness.cpp @@ -1,38 +1,39 @@ -#include "Endianness.h" -#include "Type.h" - -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.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; -} - -} -} -} +#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/libevmjit/Endianness.h b/libevmjit/Endianness.h index 73224fb21..19fd8fc58 100644 --- a/libevmjit/Endianness.h +++ b/libevmjit/Endianness.h @@ -1,25 +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); -}; - -} -} -} +#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/libevmjit/ExecStats.cpp b/libevmjit/ExecStats.cpp index 97a3445b8..d8668f636 100644 --- a/libevmjit/ExecStats.cpp +++ b/libevmjit/ExecStats.cpp @@ -1,4 +1,5 @@ #include "ExecStats.h" + #include #include #include diff --git a/libevmjit/ExecStats.h b/libevmjit/ExecStats.h index 17f58ccac..498e21341 100644 --- a/libevmjit/ExecStats.h +++ b/libevmjit/ExecStats.h @@ -1,7 +1,9 @@ #pragma once -#include "ExecutionEngine.h" + #include +#include "ExecutionEngine.h" + namespace dev { namespace eth diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index c4c03233c..ff4c64cee 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -1,9 +1,8 @@ #include "ExecutionEngine.h" -#include "Runtime.h" -#include "Compiler.h" -#include "Cache.h" -#include "ExecStats.h" -#include "BuildInfo.gen.h" + +#include +#include // env options +#include #include "preprocessor/llvm_includes_start.h" #include @@ -15,9 +14,11 @@ #include #include "preprocessor/llvm_includes_end.h" -#include -#include // env options -#include +#include "Runtime.h" +#include "Compiler.h" +#include "Cache.h" +#include "ExecStats.h" +#include "BuildInfo.gen.h" namespace dev { diff --git a/libevmjit/ExecutionEngine.h b/libevmjit/ExecutionEngine.h index a31b6bf1e..4c2965e58 100644 --- a/libevmjit/ExecutionEngine.h +++ b/libevmjit/ExecutionEngine.h @@ -1,7 +1,9 @@ #pragma once -#include "RuntimeData.h" + #include +#include "RuntimeData.h" + namespace dev { namespace eth diff --git a/libevmjit/Ext.cpp b/libevmjit/Ext.cpp index c06d01f74..38deef214 100644 --- a/libevmjit/Ext.cpp +++ b/libevmjit/Ext.cpp @@ -1,13 +1,14 @@ #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" -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - namespace dev { namespace eth diff --git a/libevmjit/Ext.h b/libevmjit/Ext.h index 669797848..1c0c0fc56 100644 --- a/libevmjit/Ext.h +++ b/libevmjit/Ext.h @@ -1,7 +1,9 @@ #pragma once -#include "CompilerHelper.h" + #include +#include "CompilerHelper.h" + namespace dev { namespace eth diff --git a/libevmjit/GasMeter.cpp b/libevmjit/GasMeter.cpp index 9f73df7da..ca21714e0 100644 --- a/libevmjit/GasMeter.cpp +++ b/libevmjit/GasMeter.cpp @@ -1,11 +1,11 @@ #include "GasMeter.h" -#include "Ext.h" -#include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" +#include "Ext.h" +#include "RuntimeManager.h" namespace dev { diff --git a/libevmjit/GasMeter.h b/libevmjit/GasMeter.h index 4f29f5c29..4056cd64d 100644 --- a/libevmjit/GasMeter.h +++ b/libevmjit/GasMeter.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" #include "Instruction.h" diff --git a/libevmjit/Instruction.h b/libevmjit/Instruction.h index db18c934a..6785213d6 100644 --- a/libevmjit/Instruction.h +++ b/libevmjit/Instruction.h @@ -1,4 +1,5 @@ #pragma once + #include "Common.h" namespace llvm diff --git a/libevmjit/Memory.cpp b/libevmjit/Memory.cpp index e29bbcaba..647c5f26a 100644 --- a/libevmjit/Memory.cpp +++ b/libevmjit/Memory.cpp @@ -1,14 +1,15 @@ #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" -#include "preprocessor/llvm_includes_start.h" -#include -#include "preprocessor/llvm_includes_end.h" - namespace dev { namespace eth diff --git a/libevmjit/Memory.h b/libevmjit/Memory.h index 90c01c1ca..e8edce735 100644 --- a/libevmjit/Memory.h +++ b/libevmjit/Memory.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Runtime.cpp b/libevmjit/Runtime.cpp index b8466791a..69937368c 100644 --- a/libevmjit/Runtime.cpp +++ b/libevmjit/Runtime.cpp @@ -1,4 +1,5 @@ #include "Runtime.h" + #include namespace dev diff --git a/libevmjit/Runtime.h b/libevmjit/Runtime.h index 9ea3039a0..82be4a0c8 100644 --- a/libevmjit/Runtime.h +++ b/libevmjit/Runtime.h @@ -1,39 +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; -}; - -} -} -} +#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/libevmjit/RuntimeData.h b/libevmjit/RuntimeData.h index 50522f0bc..cc081cc58 100644 --- a/libevmjit/RuntimeData.h +++ b/libevmjit/RuntimeData.h @@ -1,4 +1,5 @@ #pragma once + #include "Common.h" namespace dev diff --git a/libevmjit/RuntimeManager.h b/libevmjit/RuntimeManager.h index 2fdad3fb5..30c69ec88 100644 --- a/libevmjit/RuntimeManager.h +++ b/libevmjit/RuntimeManager.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" #include "Type.h" #include "RuntimeData.h" diff --git a/libevmjit/Stack.cpp b/libevmjit/Stack.cpp index b63660aa9..81a954991 100644 --- a/libevmjit/Stack.cpp +++ b/libevmjit/Stack.cpp @@ -1,8 +1,11 @@ #include "Stack.h" -#include "RuntimeManager.h" -#include "Runtime.h" +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" + +#include "RuntimeManager.h" +#include "Runtime.h" namespace dev { diff --git a/libevmjit/Stack.h b/libevmjit/Stack.h index 0a549597f..4b6fa374f 100644 --- a/libevmjit/Stack.h +++ b/libevmjit/Stack.h @@ -1,4 +1,5 @@ #pragma once + #include "CompilerHelper.h" namespace dev diff --git a/libevmjit/Type.h b/libevmjit/Type.h index 46fd5c9b7..b8a4a09eb 100644 --- a/libevmjit/Type.h +++ b/libevmjit/Type.h @@ -1,11 +1,12 @@ #pragma once -#include "Common.h" #include "preprocessor/llvm_includes_start.h" #include #include #include "preprocessor/llvm_includes_end.h" +#include "Common.h" + namespace dev { namespace eth diff --git a/libevmjit/preprocessor/llvm_includes_end.h b/libevmjit/preprocessor/llvm_includes_end.h index 3a47dca15..023c8021e 100644 --- a/libevmjit/preprocessor/llvm_includes_end.h +++ b/libevmjit/preprocessor/llvm_includes_end.h @@ -1,3 +1,5 @@ - -#pragma warning(pop) -#pragma GCC diagnostic pop +#if defined(_MSC_VER) + #pragma warning(pop) +#else + #pragma GCC diagnostic pop +#endif diff --git a/libevmjit/preprocessor/llvm_includes_start.h b/libevmjit/preprocessor/llvm_includes_start.h index 264a6e1ef..bf34ade99 100644 --- a/libevmjit/preprocessor/llvm_includes_start.h +++ b/libevmjit/preprocessor/llvm_includes_start.h @@ -1,5 +1,8 @@ - -#pragma warning(push) -#pragma warning(disable: 4267 4244 4800) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" +#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 4d2dc802e8b2a69b72fd93eff21bc42651536a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 11:00:07 +0100 Subject: [PATCH 089/201] Introducing CHECK macro - an assert that always has a value --- libevmjit/Cache.cpp | 5 ++++- libevmjit/ExecutionEngine.cpp | 8 +++++--- libevmjit/Utils.h | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libevmjit/Cache.cpp b/libevmjit/Cache.cpp index d7d6f1bbb..fe226eefb 100644 --- a/libevmjit/Cache.cpp +++ b/libevmjit/Cache.cpp @@ -13,6 +13,7 @@ #include "preprocessor/llvm_includes_end.h" #include "ExecutionEngine.h" +#include "Utils.h" namespace dev { @@ -43,7 +44,9 @@ std::unique_ptr Cache::getObject(std::string const& id) g_listener->stateChanged(ExecState::CacheLoad); CACHE_LOG << id << ": search\n"; - assert(!g_lastObject); + 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); diff --git a/libevmjit/ExecutionEngine.cpp b/libevmjit/ExecutionEngine.cpp index ff4c64cee..1d2ff91b1 100644 --- a/libevmjit/ExecutionEngine.cpp +++ b/libevmjit/ExecutionEngine.cpp @@ -18,6 +18,7 @@ #include "Compiler.h" #include "Cache.h" #include "ExecStats.h" +#include "Utils.h" #include "BuildInfo.gen.h" namespace dev @@ -98,7 +99,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) module->setTargetTriple(triple.str()); ee.reset(builder.create()); - if (!ee) + if (!CHECK(ee)) return ReturnCode::LLVMConfigError; module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module ee->setObjectCache(objectCache); @@ -111,7 +112,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); if (!entryFuncPtr) - { + { auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr; if (!module) { @@ -127,7 +128,8 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); } - assert(entryFuncPtr); //TODO: Replace it with safe exception + if (!CHECK(entryFuncPtr)) + return ReturnCode::LLVMLinkError; listener->stateChanged(ExecState::Execution); auto returnCode = entryFuncPtr(&runtime); diff --git a/libevmjit/Utils.h b/libevmjit/Utils.h index 7e6133ced..aad975f5b 100644 --- a/libevmjit/Utils.h +++ b/libevmjit/Utils.h @@ -16,6 +16,9 @@ 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) + } } } From a61449359bbc3ecdd150fc59cdcecd1fa0355e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 11:18:29 +0100 Subject: [PATCH 090/201] Fix/disable warnings in CPP bridge --- evmjit/CMakeLists.txt | 2 +- evmjit/libevmjit-cpp/Env.cpp | 1 + evmjit/libevmjit-cpp/JitVM.cpp | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 8f3a170d6..14fca2cde 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_AUTOMOC OFF) if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") else() - set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion") + set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-unknown-pragmas") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index cdca56b99..ba1f4661e 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -1,4 +1,5 @@ +#pragma GCC diagnostic ignored "-Wconversion" #include #include #include diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 53282e3ae..55dcd94f8 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -1,4 +1,5 @@ +#pragma GCC diagnostic ignored "-Wconversion" #include "JitVM.h" #include #include From 833643ed776184fdf78c80e1103dbe76dd5779b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 11:33:15 +0100 Subject: [PATCH 091/201] Safe assert --- evmjit/libevmjit/ExecStats.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index d8668f636..18419d9e0 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -13,7 +13,9 @@ namespace jit void ExecStats::stateChanged(ExecState _state) { - assert(m_state != ExecState::Finished); + if (!CHECK(m_state != ExecState::Finished)) + return; + auto now = clock::now(); if (_state != ExecState::Started) { From f2f998f6fcb1e68d1fe04ada63c8ba3e18533da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 12 Feb 2015 12:00:32 +0100 Subject: [PATCH 092/201] Build fix --- evmjit/libevmjit/ExecStats.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evmjit/libevmjit/ExecStats.cpp b/evmjit/libevmjit/ExecStats.cpp index 18419d9e0..684f6d39a 100644 --- a/evmjit/libevmjit/ExecStats.cpp +++ b/evmjit/libevmjit/ExecStats.cpp @@ -4,6 +4,8 @@ #include #include +#include "Utils.h" + namespace dev { namespace eth From 4f17defa103ab63b2355b0b4285c41bcad5b6b01 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Thu, 12 Feb 2015 20:13:44 +0100 Subject: [PATCH 093/201] add valid tx output --- test/blFirstTestFiller.json | 32 ------ test/blValidBlockTestFiller.json | 187 ++++++++++++++++++++++++++++++- test/block.cpp | 122 +++++++++++++------- 3 files changed, 266 insertions(+), 75 deletions(-) delete mode 100644 test/blFirstTestFiller.json diff --git a/test/blFirstTestFiller.json b/test/blFirstTestFiller.json deleted file mode 100644 index d4e6d109f..000000000 --- a/test/blFirstTestFiller.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "firstBlockTest" : { - "block" : { - "parentHash": "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5", - "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "coinbase": "0x8888f1f195afa192cfee860698584c030f4c9db1", - "stateRoot": "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "difficulty": "023101", - "number": "62", - "gasLimit": "0x0dddb6", - "gasUsed": "100", - "timestamp": "0x54c98c81", - "extraData": "42", - "nonce": "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d" - }, - "pre" : {}, - "transactions": [{ - "nonce": "0", - "gasPrice": "0x09184e72a000", - "gasLimit": "0x0f3e6f", - "to": "", - "value": "", - "data": "0x60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b56", - "v": "0x1b", - "r": "0xd4287e915ebac7a8af390560fa53c8f0b7f13802ba0393d7afa5823c2560ca89", - "s": "0xae75db31a34f7e386ad459646de98ec3a1c88cc91b11620b4ffd86871f579942" - }] - } -} diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index 99f1d32af..da2625ea6 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -1,12 +1,54 @@ { - "lowGasLimitBoundary" : { + "diffTooLow" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", + "difficulty" : "1023", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "1", + "nonce" : "0", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "27", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "diff1024" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "1024", "extraData" : "42", "gasLimit" : "100000", - "gasUsed" : "100", + "gasUsed" : "0", "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", "number" : "0", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -39,6 +81,145 @@ ], "uncleHeaders" : [ ] + }, + + "gasPrice0" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "0", + "nonce" : "0", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "27", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "tx" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "0", + "nonce" : "0", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "27", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "txOrder" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "27", + "value" : "7000000000" + }, + + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "27", + "value" : "1000000000" + }, + + ], + "uncleHeaders" : [ + ] } } diff --git a/test/block.cpp b/test/block.cpp index 88f7de634..c701cb979 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -32,29 +32,50 @@ namespace dev { namespace test { bytes createBlockRLPFromFields(mObject& _tObj) { - BOOST_REQUIRE(_tObj.count("parentHash") > 0); - BOOST_REQUIRE(_tObj.count("uncleHash") > 0); - BOOST_REQUIRE(_tObj.count("coinbase") > 0); - BOOST_REQUIRE(_tObj.count("stateRoot") > 0); - BOOST_REQUIRE(_tObj.count("transactionsTrie")> 0); - BOOST_REQUIRE(_tObj.count("receiptTrie") > 0); - BOOST_REQUIRE(_tObj.count("bloom") > 0); - BOOST_REQUIRE(_tObj.count("difficulty") > 0); - BOOST_REQUIRE(_tObj.count("number") > 0); - BOOST_REQUIRE(_tObj.count("gasLimit")> 0); - BOOST_REQUIRE(_tObj.count("gasUsed") > 0); - BOOST_REQUIRE(_tObj.count("timestamp") > 0); - BOOST_REQUIRE(_tObj.count("extraData") > 0); - BOOST_REQUIRE(_tObj.count("nonce") > 0); - - // construct RLP of the given block RLPStream rlpStream; - rlpStream.appendList(14); - rlpStream << h256(_tObj["parentHash"].get_str()) << h256(_tObj["uncleHash"].get_str()) << Address(_tObj["coinbase"].get_str()); - rlpStream << h256(_tObj["stateRoot"].get_str()) << h256(_tObj["transactionsTrie"].get_str()) << h256(_tObj["receiptTrie"].get_str()); - rlpStream << LogBloom(_tObj["bloom"].get_str()) << u256(_tObj["difficulty"].get_str()) << u256(_tObj["number"].get_str()); - rlpStream << u256(_tObj["gasLimit"].get_str()) << u256(_tObj["gasUsed"].get_str()) << u256(_tObj["timestamp"].get_str()); - rlpStream << importByteArray(_tObj["extraData"].get_str()) << h256(_tObj["nonce"].get_str()); + rlpStream.appendList(_tObj.size()); + + if (_tObj.count("parentHash") > 0) + rlpStream << importByteArray(_tObj["parentHash"].get_str()); + + if (_tObj.count("uncleHash") > 0) + rlpStream << importByteArray(_tObj["uncleHash"].get_str()); + + if (_tObj.count("coinbase") > 0) + rlpStream << importByteArray(_tObj["coinbase"].get_str()); + + if (_tObj.count("stateRoot") > 0) + rlpStream << importByteArray(_tObj["stateRoot"].get_str()); + + if (_tObj.count("transactionsTrie") > 0) + rlpStream << importByteArray(_tObj["transactionsTrie"].get_str()); + + if (_tObj.count("receiptTrie") > 0) + rlpStream << importByteArray(_tObj["receiptTrie"].get_str()); + + if (_tObj.count("bloom") > 0) + rlpStream << importByteArray(_tObj["bloom"].get_str()); + + if (_tObj.count("difficulty") > 0) + rlpStream << bigint(_tObj["difficulty"].get_str()); + + if (_tObj.count("number") > 0) + rlpStream << bigint(_tObj["number"].get_str()); + + if (_tObj.count("gasLimit") > 0) + rlpStream << bigint(_tObj["gasLimit"].get_str()); + + if (_tObj.count("gasUsed") > 0) + rlpStream << bigint(_tObj["gasUsed"].get_str()); + + if (_tObj.count("timestamp") > 0) + rlpStream << bigint(_tObj["timestamp"].get_str()); + + if (_tObj.count("extraData") > 0) + rlpStream << importByteArray(_tObj["extraData"].get_str()); + + if (_tObj.count("nonce") > 0) + rlpStream << importByteArray(_tObj["nonce"].get_str()); return rlpStream.out(); } @@ -67,6 +88,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) mObject& o = i.second.get_obj(); BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); + cout << "construc genesis\n"; // construct RLP of the genesis block const bytes c_blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); @@ -95,6 +117,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) } BOOST_REQUIRE(o.count("pre") > 0); + cout << "read state\n"; ImportTest importer(o["pre"].get_obj()); State state(Address(), OverlayDB(), BaseState::Empty); @@ -137,6 +160,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) if (_fillin) { BOOST_REQUIRE(o.count("transactions") > 0); + cout << "read transactions\n"; TransactionQueue txs; @@ -152,17 +176,18 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(tx.count("r") > 0); BOOST_REQUIRE(tx.count("s") > 0); BOOST_REQUIRE(tx.count("data") > 0); - - //Transaction txFromFields(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); - + cout << "import tx\n"; if (!txs.attemptImport(&createRLPStreamFromTransactionFields(tx).out())) cnote << "failed importing transaction\n"; } try { - state.sync(bc); - state.sync(bc,txs); + cout << "sync state: " << state.sync(bc) << endl; + TransactionReceipts txReceipts = state.sync(bc,txs); + cout << "sync state done\n"; + //if (syncSuccess) + // throw Exception(); state.commitToMine(bc); MineInfo info; for (info.completed = false; !info.completed; info = state.mine()) {} @@ -171,12 +196,36 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) catch (Exception const& _e) { cnote << "state sync or mining did throw an exception: " << diagnostic_information(_e); + return; } catch (std::exception const& _e) { cnote << "state sync or mining did throw an exception: " << _e.what(); + return; + } + + // write valid txs + cout << "number of valid txs: " << txs.transactions().size(); + mArray txArray; + for (auto const& txi: txs.transactions()) + { + Transaction tx(txi.second, CheckSignature::Sender); + mObject txObject; + txObject["nonce"] = toString(tx.nonce()); + txObject["data"] = toHex(tx.data()); + txObject["gasLimit"] = toString(tx.gas()); + txObject["gasPrice"] = toString(tx.gasPrice()); + txObject["r"] = toString(tx.signature().r); + txObject["s"] = toString(tx.signature().s); + txObject["v"] = to_string(tx.signature().v + 27); + txObject["to"] = toString(tx.receiveAddress()); + txObject["value"] = toString(tx.value()); + + txArray.push_back(txObject); } + o["transactions"] = txArray; + o["rlp"] = "0x" + toHex(state.blockData()); // write block header @@ -215,7 +264,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) bc.import(blockRLP, state.db()); state.sync(bc); } - // if exception is thrown, RLP is invalid and not blockHeader, Transaction list, and Uncle list should be given + // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given catch (Exception const& _e) { cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e); @@ -238,18 +287,13 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK(o.count("uncleHeaders") == 0); } - - // if yes, check parameters in blockHeader - // check transaction list - // check uncle list - BOOST_REQUIRE(o.count("blockHeader") > 0); mObject tObj = o["blockHeader"].get_obj(); BlockInfo blockHeaderFromFields; - const bytes rlpBytesBlockHeader = createBlockRLPFromFields(tObj); - RLP blockHeaderRLP(rlpBytesBlockHeader); - blockHeaderFromFields.populateFromHeader(blockHeaderRLP, false); + const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj); + const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); + blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, false); BlockInfo blockFromRlp = bc.info(); @@ -294,16 +338,14 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) } Transactions txsFromRlp; - bytes blockRLP2 = importByteArray(o["rlp"].get_str()); - RLP root(blockRLP2); + bytes blockRLP = importByteArray(o["rlp"].get_str()); + RLP root(blockRLP); for (auto const& tr: root[1]) { Transaction tx(tr.data(), CheckSignature::Sender); txsFromRlp.push_back(tx); } - cout << "size of pending transactions: " << txsFromRlp.size() << endl; - BOOST_CHECK_MESSAGE(txsFromRlp.size() == txsFromField.size(), "transaction list size does not match"); for (size_t i = 0; i < txsFromField.size(); ++i) From 015cd8bba66246680dc435d51b1f93edeb231874 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 13 Feb 2015 10:59:47 +0100 Subject: [PATCH 094/201] fix import transaction --- test/block.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/test/block.cpp b/test/block.cpp index c701cb979..69c236606 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -157,6 +157,8 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // construct blockchain BlockChain bc(block.out(), string(), true); + cout << "constructed bc\n"; + if (_fillin) { BOOST_REQUIRE(o.count("transactions") > 0); @@ -260,9 +262,13 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) try { state.sync(bc); + cout << "synced bc\n"; bytes blockRLP = importByteArray(o["rlp"].get_str()); + cout << "imported rlp bc\n"; bc.import(blockRLP, state.db()); + cout << "imported rlp to bc bc\n"; state.sync(bc); + cout << "synced state bc\n"; } // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given catch (Exception const& _e) @@ -316,6 +322,8 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); + cout << "checked block header bc\n"; + //Check transaction list Transactions txsFromField; @@ -323,6 +331,9 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) for (auto const& txObj: o["transactions"].get_array()) { mObject tx = txObj.get_obj(); + + cout << "read single tx\n"; + BOOST_REQUIRE(tx.count("nonce") > 0); BOOST_REQUIRE(tx.count("gasPrice") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0); @@ -333,10 +344,25 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_REQUIRE(tx.count("s") > 0); BOOST_REQUIRE(tx.count("data") > 0); - Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); - txsFromField.push_back(t); + cout << "construct single tx\n"; + try + { + Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); + txsFromField.push_back(t); + } + catch (Exception const& _e) + { + BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e)); + + } + catch (exception const& _e) + { + cout << _e.what() << endl; + } } + cout << "read txs bc\n"; + Transactions txsFromRlp; bytes blockRLP = importByteArray(o["rlp"].get_str()); RLP root(blockRLP); @@ -362,6 +388,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "however, transactions in rlp and in field do not match"); } + cout << "checked txs bc\n"; // check uncle list From 8f0638fdfdb2b0beba5947daaa5ca4fab554e283 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 13 Feb 2015 11:24:20 +0100 Subject: [PATCH 095/201] fix tx output --- test/block.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/block.cpp b/test/block.cpp index 69c236606..3544a3f8e 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -217,8 +217,8 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) txObject["data"] = toHex(tx.data()); txObject["gasLimit"] = toString(tx.gas()); txObject["gasPrice"] = toString(tx.gasPrice()); - txObject["r"] = toString(tx.signature().r); - txObject["s"] = toString(tx.signature().s); + txObject["r"] = "0x" + toString(tx.signature().r); + txObject["s"] = "0x" + toString(tx.signature().s); txObject["v"] = to_string(tx.signature().v + 27); txObject["to"] = toString(tx.receiveAddress()); txObject["value"] = toString(tx.value()); From d8377e88424e37ae804d6e6e0788cb7324b5bc20 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 13 Feb 2015 12:38:38 +0100 Subject: [PATCH 096/201] switch to secretKey in fillers --- test/TestHelper.cpp | 1 - test/blValidBlockTestFiller.json | 82 +++++++++++++++++++++++--------- test/block.cpp | 24 ++-------- 3 files changed, 64 insertions(+), 43 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index ec284d480..907447aba 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -548,7 +548,6 @@ RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj) return rlpStream; } - void processCommandLineOptions() { auto argc = boost::unit_test::framework::master_test_suite().argc; diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index da2625ea6..d19c8104d 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -30,10 +30,8 @@ "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "27", "value" : "10" } ], @@ -72,10 +70,8 @@ "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "27", "value" : "10" } ], @@ -111,13 +107,11 @@ "transactions" : [ { "data" : "", - "gasLimit" : "500", + "gasLimit" : "850", "gasPrice" : "0", "nonce" : "0", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "27", "value" : "10" } ], @@ -154,12 +148,10 @@ { "data" : "", "gasLimit" : "500", - "gasPrice" : "0", + "gasPrice" : "10", "nonce" : "0", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "27", "value" : "10" } ], @@ -198,28 +190,74 @@ "gasLimit" : "500", "gasPrice" : "10", "nonce" : "0", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "27", "value" : "7000000000" }, + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "8000000000" + } + ], + "uncleHeaders" : [ + ] + }, + "txEqualValue" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ { "data" : "", "gasLimit" : "500", "gasPrice" : "10", "nonce" : "0", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "27", - "value" : "1000000000" + "value" : "5000000000" }, - + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "9", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } ], "uncleHeaders" : [ ] } + + + } diff --git a/test/block.cpp b/test/block.cpp index 3544a3f8e..2d44e8d71 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -169,27 +169,15 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) for (auto const& txObj: o["transactions"].get_array()) { mObject tx = txObj.get_obj(); - BOOST_REQUIRE(tx.count("nonce") > 0); - BOOST_REQUIRE(tx.count("gasPrice") > 0); - BOOST_REQUIRE(tx.count("gasLimit") > 0); - BOOST_REQUIRE(tx.count("to") > 0); - BOOST_REQUIRE(tx.count("value") > 0); - BOOST_REQUIRE(tx.count("v") > 0); - BOOST_REQUIRE(tx.count("r") > 0); - BOOST_REQUIRE(tx.count("s") > 0); - BOOST_REQUIRE(tx.count("data") > 0); - cout << "import tx\n"; - if (!txs.attemptImport(&createRLPStreamFromTransactionFields(tx).out())) + importer.importTransaction(tx); + if (!txs.attemptImport(importer.m_transaction.rlp())) cnote << "failed importing transaction\n"; } try { - cout << "sync state: " << state.sync(bc) << endl; - TransactionReceipts txReceipts = state.sync(bc,txs); - cout << "sync state done\n"; - //if (syncSuccess) - // throw Exception(); + state.sync(bc); + state.sync(bc,txs); state.commitToMine(bc); MineInfo info; for (info.completed = false; !info.completed; info = state.mine()) {} @@ -262,13 +250,9 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) try { state.sync(bc); - cout << "synced bc\n"; bytes blockRLP = importByteArray(o["rlp"].get_str()); - cout << "imported rlp bc\n"; bc.import(blockRLP, state.db()); - cout << "imported rlp to bc bc\n"; state.sync(bc); - cout << "synced state bc\n"; } // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given catch (Exception const& _e) From 34ada783f10437c137b3ed0347731de1729ca3a8 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 13 Feb 2015 14:49:32 +0300 Subject: [PATCH 097/201] 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 031c1392c6811d0696fd779690413c196aa10cc2 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Fri, 13 Feb 2015 18:25:47 +0100 Subject: [PATCH 098/201] add possibility to create bad blocks in fillers --- test/blValidBlockTestFiller.json | 228 +----------------------- test/block.cpp | 231 +++++++++++++++++++------ test/stSystemOperationsTestFiller.json | 4 +- 3 files changed, 186 insertions(+), 277 deletions(-) diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index d19c8104d..db7138b5b 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -1,85 +1,8 @@ { - "diffTooLow" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "1023", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "850", - "gasPrice" : "1", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, - - "diff1024" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "1024", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "850", - "gasPrice" : "1", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, - - "gasPrice0" : { + "log1" : { + "blockHeader" : { + "number" : "2" + }, "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", @@ -102,162 +25,27 @@ "nonce" : "0", "code" : "", "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "850", - "gasPrice" : "0", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, - - "tx" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, - - "txOrder" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "7000000000" }, - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "10", + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "8000000000" - } - ], - "uncleHeaders" : [ - ] - }, - - "txEqualValue" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", "storage": {} } }, "transactions" : [ { "data" : "", - "gasLimit" : "500", + "gasLimit" : "5000", "gasPrice" : "10", "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "5000000000" - }, - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "9", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" } ], "uncleHeaders" : [ ] } - - - } diff --git a/test/block.cpp b/test/block.cpp index 2d44e8d71..4d1f5accc 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file block.cpp * @author Christoph Jentzsch @@ -32,60 +32,60 @@ namespace dev { namespace test { bytes createBlockRLPFromFields(mObject& _tObj) { - RLPStream rlpStream; - rlpStream.appendList(_tObj.size()); + RLPStream rlpStream; + rlpStream.appendList(_tObj.size()); - if (_tObj.count("parentHash") > 0) - rlpStream << importByteArray(_tObj["parentHash"].get_str()); + if (_tObj.count("parentHash") > 0) + rlpStream << importByteArray(_tObj["parentHash"].get_str()); - if (_tObj.count("uncleHash") > 0) - rlpStream << importByteArray(_tObj["uncleHash"].get_str()); + if (_tObj.count("uncleHash") > 0) + rlpStream << importByteArray(_tObj["uncleHash"].get_str()); - if (_tObj.count("coinbase") > 0) - rlpStream << importByteArray(_tObj["coinbase"].get_str()); + if (_tObj.count("coinbase") > 0) + rlpStream << importByteArray(_tObj["coinbase"].get_str()); - if (_tObj.count("stateRoot") > 0) - rlpStream << importByteArray(_tObj["stateRoot"].get_str()); + if (_tObj.count("stateRoot") > 0) + rlpStream << importByteArray(_tObj["stateRoot"].get_str()); - if (_tObj.count("transactionsTrie") > 0) - rlpStream << importByteArray(_tObj["transactionsTrie"].get_str()); + if (_tObj.count("transactionsTrie") > 0) + rlpStream << importByteArray(_tObj["transactionsTrie"].get_str()); - if (_tObj.count("receiptTrie") > 0) - rlpStream << importByteArray(_tObj["receiptTrie"].get_str()); + if (_tObj.count("receiptTrie") > 0) + rlpStream << importByteArray(_tObj["receiptTrie"].get_str()); - if (_tObj.count("bloom") > 0) - rlpStream << importByteArray(_tObj["bloom"].get_str()); + if (_tObj.count("bloom") > 0) + rlpStream << importByteArray(_tObj["bloom"].get_str()); - if (_tObj.count("difficulty") > 0) - rlpStream << bigint(_tObj["difficulty"].get_str()); + if (_tObj.count("difficulty") > 0) + rlpStream << bigint(_tObj["difficulty"].get_str()); - if (_tObj.count("number") > 0) - rlpStream << bigint(_tObj["number"].get_str()); + if (_tObj.count("number") > 0) + rlpStream << bigint(_tObj["number"].get_str()); - if (_tObj.count("gasLimit") > 0) - rlpStream << bigint(_tObj["gasLimit"].get_str()); + if (_tObj.count("gasLimit") > 0) + rlpStream << bigint(_tObj["gasLimit"].get_str()); - if (_tObj.count("gasUsed") > 0) - rlpStream << bigint(_tObj["gasUsed"].get_str()); + if (_tObj.count("gasUsed") > 0) + rlpStream << bigint(_tObj["gasUsed"].get_str()); - if (_tObj.count("timestamp") > 0) - rlpStream << bigint(_tObj["timestamp"].get_str()); + if (_tObj.count("timestamp") > 0) + rlpStream << bigint(_tObj["timestamp"].get_str()); - if (_tObj.count("extraData") > 0) - rlpStream << importByteArray(_tObj["extraData"].get_str()); + if (_tObj.count("extraData") > 0) + rlpStream << importByteArray(_tObj["extraData"].get_str()); - if (_tObj.count("nonce") > 0) - rlpStream << importByteArray(_tObj["nonce"].get_str()); + if (_tObj.count("nonce") > 0) + rlpStream << importByteArray(_tObj["nonce"].get_str()); - return rlpStream.out(); + return rlpStream.out(); } void doBlockTests(json_spirit::mValue& _v, bool _fillin) { - for (auto& i: _v.get_obj()) - { - cerr << i.first << endl; - mObject& o = i.second.get_obj(); + for (auto& i: _v.get_obj()) + { + cerr << i.first << endl; + mObject& o = i.second.get_obj(); BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); cout << "construc genesis\n"; @@ -197,9 +197,12 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // write valid txs cout << "number of valid txs: " << txs.transactions().size(); mArray txArray; + Transactions txList; for (auto const& txi: txs.transactions()) { + cout << "AHA0" << endl; Transaction tx(txi.second, CheckSignature::Sender); + txList.push_back(tx); mObject txObject; txObject["nonce"] = toString(tx.nonce()); txObject["data"] = toHex(tx.data()); @@ -210,10 +213,11 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) txObject["v"] = to_string(tx.signature().v + 27); txObject["to"] = toString(tx.receiveAddress()); txObject["value"] = toString(tx.value()); + cout << "AHA0.5" << endl; txArray.push_back(txObject); } - + cout << "AHA1" << endl; o["transactions"] = txArray; o["rlp"] = "0x" + toHex(state.blockData()); @@ -237,12 +241,125 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); - o["blockHeader"] = oBlockHeader; - // write uncle list - mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. - o["uncleHeaders"] = aUncleList; + // overwrite (wrong) data from blockheader in filler" << endl; + + if (o.count("blockHeader") > 0) + { + if (o["blockHeader"].get_obj().size() != 14) + { + + BlockInfo tmp = current_BlockHeader; + + if (o["blockHeader"].get_obj().count("parentHash") > 0) + tmp.parentHash = h256(o["blockHeader"].get_obj()["parentHash"].get_str()); + + if (o["blockHeader"].get_obj().count("sha3Uncles") > 0) + tmp.sha3Uncles = h256(o["blockHeader"].get_obj()["uncleHash"].get_str()); + + if (o["blockHeader"].get_obj().count("coinbase") > 0) + tmp.coinbaseAddress = Address(o["blockHeader"].get_obj()["coinbase"].get_str()); + + if (o["blockHeader"].get_obj().count("stateRoot") > 0) + tmp.stateRoot = h256(o["blockHeader"].get_obj()["stateRoot"].get_str()); + + if (o["blockHeader"].get_obj().count("transactionsTrie") > 0) + tmp.transactionsRoot = h256(o["blockHeader"].get_obj()["transactionsTrie"].get_str()); + + if (o["blockHeader"].get_obj().count("receiptTrie") > 0) + tmp.receiptsRoot = h256(o["blockHeader"].get_obj()["receiptTrie"].get_str()); + + if (o["blockHeader"].get_obj().count("bloom") > 0) + tmp.logBloom = LogBloom(o["blockHeader"].get_obj()["bloom"].get_str()); + + if (o["blockHeader"].get_obj().count("difficulty") > 0) + tmp.difficulty = toInt(o["blockHeader"].get_obj()["difficulty"]); + + if (o["blockHeader"].get_obj().count("number") > 0) + tmp.number = toInt(o["blockHeader"].get_obj()["number"]); + + if (o["blockHeader"].get_obj().count("gasLimit") > 0) + tmp.gasLimit = toInt(o["blockHeader"].get_obj()["gasLimit"]); + + if (o["blockHeader"].get_obj().count("gasUsed") > 0) + tmp.gasUsed = toInt(o["blockHeader"].get_obj()["gasUsed"]); + + if (o["blockHeader"].get_obj().count("timestamp") > 0) + tmp.timestamp = toInt(o["blockHeader"].get_obj()["timestamp"]); + + if (o["blockHeader"].get_obj().count("extraData") > 0) + tmp.extraData = importByteArray(o["blockHeader"].get_obj()["extraData"].get_str()); + + // find new valid nonce + + if (tmp != current_BlockHeader) + { + current_BlockHeader = tmp; + cout << "new header!\n"; + ProofOfWork pow; + MineInfo ret; + while (!ProofOfWork::verify(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.nonce, current_BlockHeader.difficulty)) + tie(ret, current_BlockHeader.nonce) = pow.mine(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.difficulty, 10000, true, true); + oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); + } + } + else + { + // take the blockheader as is + const bytes c_blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); + const RLP c_bRLP(c_blockRLP); + current_BlockHeader.populateFromHeader(c_bRLP, false); + } + } + + //txs: + + RLPStream txStream; + txStream.appendList(txList.size()); + for (unsigned i = 0; i < txList.size(); ++i) + { + RLPStream txrlp; + txList[i].streamRLP(txrlp); + txStream.appendRaw(txrlp.out()); + } + + cout << "create block:" << endl; + + RLPStream rlpStream2; + current_BlockHeader.streamRLP(rlpStream2, WithNonce); + + RLPStream block2(3); + block2.appendRaw(rlpStream2.out()); + block2.appendRaw(txStream.out()); + block2.appendRaw(RLPEmptyList); + + if (sha3(RLP(state.blockData())[0].data()) != sha3(RLP(block2.out())[0].data())) + cout << "block 0 wrong" << endl; + + if (sha3(RLP(state.blockData())[1].data()) != sha3(RLP(block2.out())[1].data())) + cout << "block 1 wrong" << endl; + + if (sha3(RLP(state.blockData())[2].data()) != sha3(RLP(block2.out())[2].data())) + cout << "block 2 wrong" << endl; + + + if (sha3(state.blockData()) != sha3(block2.out())) + { + cout << "blocks do not match!" << endl; + o["rlp"] = "0x" + toHex(block2.out()); + o.erase(o.find("blockHeader")); + o.erase(o.find("uncleHeaders")); + o.erase(o.find("transactions")); + } + else + { + o["blockHeader"] = oBlockHeader; + + // write uncle list + mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. + o["uncleHeaders"] = aUncleList; + } } else @@ -254,13 +371,14 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) bc.import(blockRLP, state.db()); state.sync(bc); } - // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given + // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given catch (Exception const& _e) { cnote << "state sync or block import did throw an exception: " << diagnostic_information(_e); BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); + return; } catch (std::exception const& _e) { @@ -268,6 +386,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); + return; } catch(...) { @@ -275,8 +394,10 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); + return; } - + cout << "valid block header\n"; + //cout << "block number: " << BOOST_REQUIRE(o.count("blockHeader") > 0); mObject tObj = o["blockHeader"].get_obj(); @@ -388,12 +509,12 @@ BOOST_AUTO_TEST_SUITE(BlockTests) BOOST_AUTO_TEST_CASE(blValidBlockTest) { - dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); + dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); } BOOST_AUTO_TEST_CASE(userDefinedFileBl) { - dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); + dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/stSystemOperationsTestFiller.json b/test/stSystemOperationsTestFiller.json index eae393645..9f47b2fef 100644 --- a/test/stSystemOperationsTestFiller.json +++ b/test/stSystemOperationsTestFiller.json @@ -81,13 +81,13 @@ "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000000000000000", - "nonce" : 0, + "nonce" : "0", "code" : "0x444242424245434253f0", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "balance" : "1000000000000000000", - "nonce" : 0, + "nonce" : "0", "code" : "", "storage": {} } From d35da25b19cd0f82799e7aac5f70bb567bc57467 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 16 Feb 2015 11:04:05 +0100 Subject: [PATCH 099/201] extra data fix --- test/TestHelper.cpp | 20 +-- test/blInvalidHeaderTestFiller.json | 0 test/block.cpp | 232 +++++++++++++--------------- 3 files changed, 120 insertions(+), 132 deletions(-) create mode 100644 test/blInvalidHeaderTestFiller.json diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 1e6b97f07..ff6939a5f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -510,16 +510,16 @@ RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj) RLPStream rlpStream; rlpStream.appendList(_tObj.size()); - if (_tObj.count("nonce") > 0) + if (_tObj.count("nonce")) rlpStream << bigint(_tObj["nonce"].get_str()); - if (_tObj.count("gasPrice") > 0) + if (_tObj.count("gasPrice")) rlpStream << bigint(_tObj["gasPrice"].get_str()); - if (_tObj.count("gasLimit") > 0) + if (_tObj.count("gasLimit")) rlpStream << bigint(_tObj["gasLimit"].get_str()); - if (_tObj.count("to") > 0) + if (_tObj.count("to")) { if (_tObj["to"].get_str().empty()) rlpStream << ""; @@ -527,22 +527,22 @@ RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj) rlpStream << importByteArray(_tObj["to"].get_str()); } - if (_tObj.count("value") > 0) + if (_tObj.count("value")) rlpStream << bigint(_tObj["value"].get_str()); - if (_tObj.count("data") > 0) + if (_tObj.count("data")) rlpStream << importData(_tObj); - if (_tObj.count("v") > 0) + if (_tObj.count("v")) rlpStream << bigint(_tObj["v"].get_str()); - if (_tObj.count("r") > 0) + if (_tObj.count("r")) rlpStream << bigint(_tObj["r"].get_str()); - if (_tObj.count("s") > 0) + if (_tObj.count("s")) rlpStream << bigint(_tObj["s"].get_str()); - if (_tObj.count("extrafield") > 0) + if (_tObj.count("extrafield")) rlpStream << bigint(_tObj["extrafield"].get_str()); return rlpStream; diff --git a/test/blInvalidHeaderTestFiller.json b/test/blInvalidHeaderTestFiller.json new file mode 100644 index 000000000..e69de29bb diff --git a/test/block.cpp b/test/block.cpp index 4d1f5accc..891d89931 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -35,46 +35,46 @@ bytes createBlockRLPFromFields(mObject& _tObj) RLPStream rlpStream; rlpStream.appendList(_tObj.size()); - if (_tObj.count("parentHash") > 0) + if (_tObj.count("parentHash")) rlpStream << importByteArray(_tObj["parentHash"].get_str()); - if (_tObj.count("uncleHash") > 0) + if (_tObj.count("uncleHash")) rlpStream << importByteArray(_tObj["uncleHash"].get_str()); - if (_tObj.count("coinbase") > 0) + if (_tObj.count("coinbase")) rlpStream << importByteArray(_tObj["coinbase"].get_str()); - if (_tObj.count("stateRoot") > 0) + if (_tObj.count("stateRoot")) rlpStream << importByteArray(_tObj["stateRoot"].get_str()); - if (_tObj.count("transactionsTrie") > 0) + if (_tObj.count("transactionsTrie")) rlpStream << importByteArray(_tObj["transactionsTrie"].get_str()); - if (_tObj.count("receiptTrie") > 0) + if (_tObj.count("receiptTrie")) rlpStream << importByteArray(_tObj["receiptTrie"].get_str()); - if (_tObj.count("bloom") > 0) + if (_tObj.count("bloom")) rlpStream << importByteArray(_tObj["bloom"].get_str()); - if (_tObj.count("difficulty") > 0) + if (_tObj.count("difficulty")) rlpStream << bigint(_tObj["difficulty"].get_str()); - if (_tObj.count("number") > 0) + if (_tObj.count("number")) rlpStream << bigint(_tObj["number"].get_str()); - if (_tObj.count("gasLimit") > 0) + if (_tObj.count("gasLimit")) rlpStream << bigint(_tObj["gasLimit"].get_str()); - if (_tObj.count("gasUsed") > 0) + if (_tObj.count("gasUsed")) rlpStream << bigint(_tObj["gasUsed"].get_str()); - if (_tObj.count("timestamp") > 0) + if (_tObj.count("timestamp")) rlpStream << bigint(_tObj["timestamp"].get_str()); - if (_tObj.count("extraData") > 0) + if (_tObj.count("extraData")) rlpStream << importByteArray(_tObj["extraData"].get_str()); - if (_tObj.count("nonce") > 0) + if (_tObj.count("nonce")) rlpStream << importByteArray(_tObj["nonce"].get_str()); return rlpStream.out(); @@ -87,43 +87,37 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) cerr << i.first << endl; mObject& o = i.second.get_obj(); - BOOST_REQUIRE(o.count("genesisBlockHeader") > 0); - cout << "construc genesis\n"; - - // construct RLP of the genesis block - const bytes c_blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); - const RLP c_bRLP(c_blockRLP); + BOOST_REQUIRE(o.count("genesisBlockHeader")); BlockInfo blockFromFields; - try { + // construct genesis block + const bytes c_blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); + const RLP c_bRLP(c_blockRLP); blockFromFields.populateFromHeader(c_bRLP, false); } catch (Exception const& _e) { cnote << "block population did throw an exception: " << diagnostic_information(_e); BOOST_ERROR("Failed block population with Exception: " << _e.what()); - return; + continue; } catch (std::exception const& _e) { BOOST_ERROR("Failed block population with Exception: " << _e.what()); - return; + continue; } catch(...) { cnote << "block population did throw an unknown exception\n"; - return; + continue; } - BOOST_REQUIRE(o.count("pre") > 0); - cout << "read state\n"; + BOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); State state(Address(), OverlayDB(), BaseState::Empty); importer.importState(o["pre"].get_obj(), state); - - // commit changes to DB state.commit(); if (_fillin) @@ -136,7 +130,8 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // find new valid nonce ProofOfWork pow; MineInfo ret; - tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, false); + while (!ProofOfWork::verify(blockFromFields.headerHash(WithoutNonce), blockFromFields.nonce, blockFromFields.difficulty)) + tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, true); //update genesis block in json file o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot); @@ -157,12 +152,9 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // construct blockchain BlockChain bc(block.out(), string(), true); - cout << "constructed bc\n"; - if (_fillin) { - BOOST_REQUIRE(o.count("transactions") > 0); - cout << "read transactions\n"; + BOOST_REQUIRE(o.count("transactions")); TransactionQueue txs; @@ -195,12 +187,10 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) } // write valid txs - cout << "number of valid txs: " << txs.transactions().size(); mArray txArray; Transactions txList; for (auto const& txi: txs.transactions()) { - cout << "AHA0" << endl; Transaction tx(txi.second, CheckSignature::Sender); txList.push_back(tx); mObject txObject; @@ -213,82 +203,61 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) txObject["v"] = to_string(tx.signature().v + 27); txObject["to"] = toString(tx.receiveAddress()); txObject["value"] = toString(tx.value()); - cout << "AHA0.5" << endl; txArray.push_back(txObject); } - cout << "AHA1" << endl; - o["transactions"] = txArray; + o["transactions"] = txArray; o["rlp"] = "0x" + toHex(state.blockData()); - // write block header - - mObject oBlockHeader; BlockInfo current_BlockHeader = state.info(); - oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); - oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); - oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); - oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot); - oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot); - oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot); - oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom); - oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty); - oBlockHeader["number"] = toString(current_BlockHeader.number); - oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit); - oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); - oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); - oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); - oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); - - - // overwrite (wrong) data from blockheader in filler" << endl; + // overwrite blockheader with (possible wrong) data from "blockheader" in filler; - if (o.count("blockHeader") > 0) + if (o.count("blockHeader")) { if (o["blockHeader"].get_obj().size() != 14) { BlockInfo tmp = current_BlockHeader; - if (o["blockHeader"].get_obj().count("parentHash") > 0) + if (o["blockHeader"].get_obj().count("parentHash")) tmp.parentHash = h256(o["blockHeader"].get_obj()["parentHash"].get_str()); - if (o["blockHeader"].get_obj().count("sha3Uncles") > 0) + if (o["blockHeader"].get_obj().count("sha3Uncles")) tmp.sha3Uncles = h256(o["blockHeader"].get_obj()["uncleHash"].get_str()); - if (o["blockHeader"].get_obj().count("coinbase") > 0) + if (o["blockHeader"].get_obj().count("coinbase")) tmp.coinbaseAddress = Address(o["blockHeader"].get_obj()["coinbase"].get_str()); - if (o["blockHeader"].get_obj().count("stateRoot") > 0) + if (o["blockHeader"].get_obj().count("stateRoot")) tmp.stateRoot = h256(o["blockHeader"].get_obj()["stateRoot"].get_str()); - if (o["blockHeader"].get_obj().count("transactionsTrie") > 0) + if (o["blockHeader"].get_obj().count("transactionsTrie")) tmp.transactionsRoot = h256(o["blockHeader"].get_obj()["transactionsTrie"].get_str()); - if (o["blockHeader"].get_obj().count("receiptTrie") > 0) + if (o["blockHeader"].get_obj().count("receiptTrie")) tmp.receiptsRoot = h256(o["blockHeader"].get_obj()["receiptTrie"].get_str()); - if (o["blockHeader"].get_obj().count("bloom") > 0) + if (o["blockHeader"].get_obj().count("bloom")) tmp.logBloom = LogBloom(o["blockHeader"].get_obj()["bloom"].get_str()); - if (o["blockHeader"].get_obj().count("difficulty") > 0) + if (o["blockHeader"].get_obj().count("difficulty")) tmp.difficulty = toInt(o["blockHeader"].get_obj()["difficulty"]); - if (o["blockHeader"].get_obj().count("number") > 0) + if (o["blockHeader"].get_obj().count("number")) tmp.number = toInt(o["blockHeader"].get_obj()["number"]); - if (o["blockHeader"].get_obj().count("gasLimit") > 0) + if (o["blockHeader"].get_obj().count("gasLimit")) tmp.gasLimit = toInt(o["blockHeader"].get_obj()["gasLimit"]); - if (o["blockHeader"].get_obj().count("gasUsed") > 0) + if (o["blockHeader"].get_obj().count("gasUsed")) tmp.gasUsed = toInt(o["blockHeader"].get_obj()["gasUsed"]); - if (o["blockHeader"].get_obj().count("timestamp") > 0) + if (o["blockHeader"].get_obj().count("timestamp")) tmp.timestamp = toInt(o["blockHeader"].get_obj()["timestamp"]); - if (o["blockHeader"].get_obj().count("extraData") > 0) + if (o["blockHeader"].get_obj().count("extraData")) tmp.extraData = importByteArray(o["blockHeader"].get_obj()["extraData"].get_str()); // find new valid nonce @@ -301,18 +270,41 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) MineInfo ret; while (!ProofOfWork::verify(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.nonce, current_BlockHeader.difficulty)) tie(ret, current_BlockHeader.nonce) = pow.mine(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.difficulty, 10000, true, true); - oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); } } else { // take the blockheader as is - const bytes c_blockRLP = createBlockRLPFromFields(o["genesisBlockHeader"].get_obj()); + const bytes c_blockRLP = createBlockRLPFromFields(o["blockHeader"].get_obj()); const RLP c_bRLP(c_blockRLP); current_BlockHeader.populateFromHeader(c_bRLP, false); } } + // write block header + + mObject oBlockHeader; + oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash); + oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles); + oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress); + oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot); + oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot); + oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot); + oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom); + oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty); + oBlockHeader["number"] = toString(current_BlockHeader.number); + oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit); + oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed); + oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp); + oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData); + oBlockHeader["nonce"] = toString(current_BlockHeader.nonce); + + o["blockHeader"] = oBlockHeader; + + // write uncle list + mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. + o["uncleHeaders"] = aUncleList; + //txs: RLPStream txStream; @@ -324,8 +316,6 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) txStream.appendRaw(txrlp.out()); } - cout << "create block:" << endl; - RLPStream rlpStream2; current_BlockHeader.streamRLP(rlpStream2, WithNonce); @@ -334,40 +324,45 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) block2.appendRaw(txStream.out()); block2.appendRaw(RLPEmptyList); + o["rlp"] = "0x" + toHex(block2.out()); + if (sha3(RLP(state.blockData())[0].data()) != sha3(RLP(block2.out())[0].data())) - cout << "block 0 wrong" << endl; + cnote << "block header mismatch\n"; if (sha3(RLP(state.blockData())[1].data()) != sha3(RLP(block2.out())[1].data())) - cout << "block 1 wrong" << endl; + cnote << "txs mismatch\n"; if (sha3(RLP(state.blockData())[2].data()) != sha3(RLP(block2.out())[2].data())) - cout << "block 2 wrong" << endl; + cnote << "uncle list mismatch\n"; - - if (sha3(state.blockData()) != sha3(block2.out())) + try { - cout << "blocks do not match!" << endl; - o["rlp"] = "0x" + toHex(block2.out()); + ImportTest importerTmp(o["pre"].get_obj()); + State stateTmp(Address(), OverlayDB(), BaseState::Empty); + importerTmp.importState(o["pre"].get_obj(), stateTmp); + stateTmp.commit(); + BlockChain bcTmp(block.out(), "/tmp/", true); + stateTmp.sync(bcTmp); + bc.import(block2.out(), stateTmp.db()); + stateTmp.sync(bcTmp); + } + // if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given + catch (...) + { + cnote << "block is invalid!\n"; o.erase(o.find("blockHeader")); o.erase(o.find("uncleHeaders")); o.erase(o.find("transactions")); } - else - { - o["blockHeader"] = oBlockHeader; - - // write uncle list - mArray aUncleList; // as of now, our parent is always the genesis block, so we can not have uncles. - o["uncleHeaders"] = aUncleList; - } } else { + bytes blockRLP; try { state.sync(bc); - bytes blockRLP = importByteArray(o["rlp"].get_str()); + blockRLP = importByteArray(o["rlp"].get_str()); bc.import(blockRLP, state.db()); state.sync(bc); } @@ -378,7 +373,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); - return; + continue; } catch (std::exception const& _e) { @@ -386,7 +381,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); - return; + continue; } catch(...) { @@ -394,11 +389,10 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK(o.count("blockHeader") == 0); BOOST_CHECK(o.count("transactions") == 0); BOOST_CHECK(o.count("uncleHeaders") == 0); - return; + continue; } - cout << "valid block header\n"; - //cout << "block number: " << - BOOST_REQUIRE(o.count("blockHeader") > 0); + + BOOST_REQUIRE(o.count("blockHeader")); mObject tObj = o["blockHeader"].get_obj(); BlockInfo blockHeaderFromFields; @@ -427,8 +421,6 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(blockHeaderFromFields == blockFromRlp, "However, blockHeaderFromFields != blockFromRlp!"); - cout << "checked block header bc\n"; - //Check transaction list Transactions txsFromField; @@ -437,19 +429,16 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) { mObject tx = txObj.get_obj(); - cout << "read single tx\n"; - - BOOST_REQUIRE(tx.count("nonce") > 0); - BOOST_REQUIRE(tx.count("gasPrice") > 0); - BOOST_REQUIRE(tx.count("gasLimit") > 0); - BOOST_REQUIRE(tx.count("to") > 0); - BOOST_REQUIRE(tx.count("value") > 0); - BOOST_REQUIRE(tx.count("v") > 0); - BOOST_REQUIRE(tx.count("r") > 0); - BOOST_REQUIRE(tx.count("s") > 0); - BOOST_REQUIRE(tx.count("data") > 0); + BOOST_REQUIRE(tx.count("nonce")); + BOOST_REQUIRE(tx.count("gasPrice")); + BOOST_REQUIRE(tx.count("gasLimit")); + BOOST_REQUIRE(tx.count("to")); + BOOST_REQUIRE(tx.count("value")); + BOOST_REQUIRE(tx.count("v")); + BOOST_REQUIRE(tx.count("r")); + BOOST_REQUIRE(tx.count("s")); + BOOST_REQUIRE(tx.count("data")); - cout << "construct single tx\n"; try { Transaction t(createRLPStreamFromTransactionFields(tx).out(), CheckSignature::Sender); @@ -458,18 +447,14 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) catch (Exception const& _e) { BOOST_ERROR("Failed transaction constructor with Exception: " << diagnostic_information(_e)); - } catch (exception const& _e) { - cout << _e.what() << endl; + cnote << _e.what(); } } - cout << "read txs bc\n"; - Transactions txsFromRlp; - bytes blockRLP = importByteArray(o["rlp"].get_str()); RLP root(blockRLP); for (auto const& tr: root[1]) { @@ -491,12 +476,10 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_CHECK_MESSAGE(txsFromField[i].receiveAddress() == txsFromRlp[i].receiveAddress(), "transaction receiveAddress in rlp and in field do not match"); BOOST_CHECK_MESSAGE(txsFromField[i].value() == txsFromRlp[i].value(), "transaction receiveAddress in rlp and in field do not match"); - BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "however, transactions in rlp and in field do not match"); + BOOST_CHECK_MESSAGE(txsFromField[i] == txsFromRlp[i], "transactions in rlp and in transaction field do not match"); } - cout << "checked txs bc\n"; // check uncle list - BOOST_CHECK_MESSAGE((o["uncleList"].type() == json_spirit::null_type ? 0 : o["uncleList"].get_array().size()) == 0, "Uncle list is not empty, but the genesis block can not have uncles"); } } @@ -507,9 +490,14 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_AUTO_TEST_SUITE(BlockTests) -BOOST_AUTO_TEST_CASE(blValidBlockTest) +//BOOST_AUTO_TEST_CASE(blValidBlockTest) +//{ +// dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); +//} + +BOOST_AUTO_TEST_CASE(blInvalidHeaderTest) { - dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); + dev::test::executeTests("blInvalidHeaderTest", "/BlockTests", dev::test::doBlockTests); } BOOST_AUTO_TEST_CASE(userDefinedFileBl) From 6c3f9ba5024f5aaef1855089601ecd2a2f79c9ff Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 16 Feb 2015 11:06:22 +0100 Subject: [PATCH 100/201] add invalid block header tests --- test/blInvalidHeaderTestFiller.json | 736 ++++++++++++++++++++++++++++ test/blValidBlockTestFiller.json | 391 +++++++++++++-- test/block.cpp | 8 +- 3 files changed, 1083 insertions(+), 52 deletions(-) diff --git a/test/blInvalidHeaderTestFiller.json b/test/blInvalidHeaderTestFiller.json index e69de29bb..0a8000d0f 100644 --- a/test/blInvalidHeaderTestFiller.json +++ b/test/blInvalidHeaderTestFiller.json @@ -0,0 +1,736 @@ +{ + "log1_wrongBlockNumber" : { + "blockHeader" : { + "number" : "2" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "log1_wrongBloom" : { + "blockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongCoinbase" : { + "blockHeader" : { + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongDifficulty" : { + "blockHeader" : { + "difficulty" : "10000" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongExtraData" : { + "blockHeader" : { + "extraData" : "42" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongGasLimit" : { + "blockHeader" : { + "gasLimit" : "100000" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongGasUsed" : { + "blockHeader" : { + "gasUsed" : "0" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongNonce" : { + "blockHeader" : { + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongNumber" : { + "blockHeader" : { + "number" : "0" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongParentHash" : { + "blockHeader" : { + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongReceiptTrie" : { + "blockHeader" : { + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongStateRoot" : { + "blockHeader" : { + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongTimestamp" : { + "blockHeader" : { + "timestamp" : "0x54c98c80" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongTransactionsTrie" : { + "blockHeader" : { + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "wrongUncleHash" : { + "blockHeader" : { + "uncleHash" : "0x0dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + } +} diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index db7138b5b..b84573789 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -1,51 +1,346 @@ { - "log1" : { - "blockHeader" : { - "number" : "2" - }, - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - }, - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "100", - "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "5000", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" - } - ], - "uncleHeaders" : [ - ] - } + "diffTooLowToChange" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "1023", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "diff1024" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "1024", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "gasPrice0" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "0", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "gasLimitTooHigh" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "1000000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "0", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "SimpleTx" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + + "txOrder" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "7000000000" + }, + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "8000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "txEqualValue" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + }, + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "9", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, + + "log1_correct" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + } } diff --git a/test/block.cpp b/test/block.cpp index 891d89931..aa1790f71 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -490,10 +490,10 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) BOOST_AUTO_TEST_SUITE(BlockTests) -//BOOST_AUTO_TEST_CASE(blValidBlockTest) -//{ -// dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); -//} +BOOST_AUTO_TEST_CASE(blValidBlockTest) +{ + dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); +} BOOST_AUTO_TEST_CASE(blInvalidHeaderTest) { From 4de92be65b87220194d5e99cc418137e075afe01 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 16 Feb 2015 11:49:15 +0100 Subject: [PATCH 101/201] fix typo --- test/blInvalidHeaderTestFiller.json | 51 +---------------------------- test/block.cpp | 2 +- 2 files changed, 2 insertions(+), 51 deletions(-) diff --git a/test/blInvalidHeaderTestFiller.json b/test/blInvalidHeaderTestFiller.json index 0a8000d0f..482eafc56 100644 --- a/test/blInvalidHeaderTestFiller.json +++ b/test/blInvalidHeaderTestFiller.json @@ -195,7 +195,7 @@ ] }, - "wrongExtraData" : { + "DifferentExtraData" : { "blockHeader" : { "extraData" : "42" }, @@ -342,55 +342,6 @@ ] }, - "wrongNonce" : { - "blockHeader" : { - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d" - }, - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - }, - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "100", - "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "5000", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" - } - ], - "uncleHeaders" : [ - ] - }, - "wrongNumber" : { "blockHeader" : { "number" : "0" diff --git a/test/block.cpp b/test/block.cpp index aa1790f71..19dcdf84b 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -224,7 +224,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) if (o["blockHeader"].get_obj().count("parentHash")) tmp.parentHash = h256(o["blockHeader"].get_obj()["parentHash"].get_str()); - if (o["blockHeader"].get_obj().count("sha3Uncles")) + if (o["blockHeader"].get_obj().count("uncleHash")) tmp.sha3Uncles = h256(o["blockHeader"].get_obj()["uncleHash"].get_str()); if (o["blockHeader"].get_obj().count("coinbase")) From 792b47deba0f41b3cde8e05ba15642729f5e5184 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 16 Feb 2015 12:00:33 +0100 Subject: [PATCH 102/201] fix GasUsed bug --- libethcore/BlockInfo.cpp | 4 ++-- libethcore/Exceptions.h | 1 + libethereum/State.cpp | 7 +++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 3d1bcaa2a..194837818 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -157,8 +157,8 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const { bytes k = rlp(i); t.insert(&k, tr.data()); - u256 gp = tr[1].toInt(); - mgp = min(mgp, gp); + u256 gasprice = tr[1].toInt(); + mgp = min(mgp, gasprice); // the minimum gas price is not used for anything //TODO delete? ++i; } if (transactionsRoot != t.root()) diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 6127a3d00..3fd62afbd 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -51,6 +51,7 @@ struct UncleTooOld: virtual dev::Exception {}; class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; }; struct DuplicateUncleNonce: virtual dev::Exception {}; struct InvalidStateRoot: virtual dev::Exception {}; +struct InvalidGasUsed: virtual dev::Exception {}; class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; }; struct InvalidTransaction: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {}; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index beab32abb..5b9da0cdd 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -600,6 +600,13 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) BOOST_THROW_EXCEPTION(InvalidStateRoot()); } + if (m_currentBlock.gasUsed != gasUsed()) + { + // Rollback the trie. + m_db.rollback(); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + } + return tdIncrease; } From bc54b1e5ba333bc5429c50940f24169ae1e5b453 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 16 Feb 2015 12:23:08 +0100 Subject: [PATCH 103/201] remove unnecessary function --- test/TestHelper.h | 1 - 1 file changed, 1 deletion(-) diff --git a/test/TestHelper.h b/test/TestHelper.h index f7df3a2c0..c4dde1a60 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -53,7 +53,6 @@ public: void importState(json_spirit::mObject& _o, eth::State& _state); void importTransaction(json_spirit::mObject& _o); void exportTest(bytes _output, eth::State& _statePost); - std::map getStateMap(eth::State& _state){return _state.m_cache;} eth::State m_statePre; eth::State m_statePost; From 7097255ec57083242cfad9d6376254324e7bbdb6 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 16 Feb 2015 13:04:28 +0100 Subject: [PATCH 104/201] OS independency by using file system --- test/blValidBlockTestFiller.json | 707 ++++++++++++++++--------------- test/block.cpp | 3 +- 2 files changed, 373 insertions(+), 337 deletions(-) diff --git a/test/blValidBlockTestFiller.json b/test/blValidBlockTestFiller.json index b84573789..8099c0dd6 100644 --- a/test/blValidBlockTestFiller.json +++ b/test/blValidBlockTestFiller.json @@ -1,346 +1,381 @@ { - "diffTooLowToChange" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "1023", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "850", - "gasPrice" : "1", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, + "diffTooLowToChange" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "1023", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, - "diff1024" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "1024", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "850", - "gasPrice" : "1", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, + "diff1024" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "1024", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, - "gasPrice0" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "850", - "gasPrice" : "0", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, + "gasPrice0" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "0", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, - "gasLimitTooHigh" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "1000000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "850", - "gasPrice" : "0", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, + "gasLimitTooHigh" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "1000000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "850", + "gasPrice" : "0", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, - "SimpleTx" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } - ], - "uncleHeaders" : [ - ] - }, + "SimpleTx" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, - "txOrder" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "7000000000" - }, - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "8000000000" - } - ], - "uncleHeaders" : [ - ] - }, + "txOrder" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "7000000000" + }, + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "8000000000" + } + ], + "uncleHeaders" : [ + ] + }, - "txEqualValue" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" - }, - { - "data" : "", - "gasLimit" : "500", - "gasPrice" : "9", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" - } - ], - "uncleHeaders" : [ - ] - }, + "txEqualValue" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + }, + { + "data" : "", + "gasLimit" : "500", + "gasPrice" : "9", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ] + }, - "log1_correct" : { - "genesisBlockHeader" : { - "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty" : "10000", - "extraData" : "42", - "gasLimit" : "100000", - "gasUsed" : "0", - "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", - "number" : "0", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", - "timestamp" : "0x54c98c81", - "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" - }, - "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "10000000000", - "nonce" : "0", - "code" : "", - "storage": {} - }, - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "100", - "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", - "storage": {} - } - }, - "transactions" : [ - { - "data" : "", - "gasLimit" : "5000", - "gasPrice" : "10", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "5000000000" - } - ], - "uncleHeaders" : [ - ] - } + "log1_correct" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "10000", + "extraData" : "42", + "gasLimit" : "100000", + "gasUsed" : "0", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000", + "nonce" : "0", + "code" : "", + "storage": {} + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "100", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (LOG1 0 32 0) }", + "storage": {} + } + }, + "transactions" : [ + { + "data" : "", + "gasLimit" : "5000", + "gasPrice" : "10", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "5000000000" + } + ], + "uncleHeaders" : [ + ], + + "firstBlockTest" : { + "block" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "023101", + "extraData" : "42", + "gasLimit" : "0x0dddb6", + "gasUsed" : "100", + "nonce" : "0x498e88f5c14b0b60d6e14ce9c6cc958cbe16a1df8dd90210e50d2d77562a348d", + "number" : "62", + "parentHash" : "0xefb4db878627027c81b3bb1c7dd3a18dae3914a49cdd24a3e40ab3bbfbb240c5", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "pre" : { + }, + "transactions" : [ + { + "data" : "0x60056013565b6101918061001d6000396000f35b3360008190555056006001600060e060020a6000350480630a874df61461003a57806341c0e1b514610058578063a02b161e14610066578063dbbdf0831461007757005b610045600435610149565b80600160a060020a031660005260206000f35b610060610161565b60006000f35b6100716004356100d4565b60006000f35b61008560043560243561008b565b60006000f35b600054600160a060020a031632600160a060020a031614156100ac576100b1565b6100d0565b8060018360005260205260406000208190555081600060005260206000a15b5050565b600054600160a060020a031633600160a060020a031614158015610118575033600160a060020a0316600182600052602052604060002054600160a060020a031614155b61012157610126565b610146565b600060018260005260205260406000208190555080600060005260206000a15b50565b60006001826000526020526040600020549050919050565b600054600160a060020a031633600160a060020a0316146101815761018f565b600054600160a060020a0316ff5b56", + "gasLimit" : "0x0f3e6f", + "gasPrice" : "0x09184e72a000", + "nonce" : "0", + "r" : "0xd4287e915ebac7a8af390560fa53c8f0b7f13802ba0393d7afa5823c2560ca89", + "s" : "0xae75db31a34f7e386ad459646de98ec3a1c88cc91b11620b4ffd86871f579942", + "to" : "", + "v" : "0x1b", + "value" : "" + } + ], + } + + } } diff --git a/test/block.cpp b/test/block.cpp index 19dcdf84b..ce165bc42 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -20,6 +20,7 @@ * block test functions. */ +#include #include #include "TestHelper.h" @@ -341,7 +342,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) State stateTmp(Address(), OverlayDB(), BaseState::Empty); importerTmp.importState(o["pre"].get_obj(), stateTmp); stateTmp.commit(); - BlockChain bcTmp(block.out(), "/tmp/", true); + BlockChain bcTmp(block.out(), getDataDir() + "/tmpBlockChain.bc", true); stateTmp.sync(bcTmp); bc.import(block2.out(), stateTmp.db()); stateTmp.sync(bcTmp); From dd0744e8a341e0c29ae395348c0d8dae84bfb33e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 16 Feb 2015 13:48:25 +0100 Subject: [PATCH 105/201] fixed #1022 --- alethzero/CMakeLists.txt | 2 +- eth/CMakeLists.txt | 2 +- exp/CMakeLists.txt | 2 +- libdevcore/CMakeLists.txt | 2 +- libdevcrypto/CMakeLists.txt | 2 +- libethcore/CMakeLists.txt | 2 +- libethereum/CMakeLists.txt | 2 +- libethereumx/CMakeLists.txt | 3 ++- libevm/CMakeLists.txt | 2 +- libevmcore/CMakeLists.txt | 2 +- liblll/CMakeLists.txt | 2 +- libnatspec/CMakeLists.txt | 2 +- libp2p/CMakeLists.txt | 2 +- libserpent/CMakeLists.txt | 2 +- libsolidity/CMakeLists.txt | 2 +- libweb3jsonrpc/CMakeLists.txt | 4 ++-- libwebthree/CMakeLists.txt | 2 +- libwhisper/CMakeLists.txt | 2 +- lllc/CMakeLists.txt | 2 +- mix/CMakeLists.txt | 2 +- neth/CMakeLists.txt | 2 +- sc/CMakeLists.txt | 2 +- solc/CMakeLists.txt | 2 +- test/CMakeLists.txt | 2 +- third/CMakeLists.txt | 2 +- 25 files changed, 27 insertions(+), 26 deletions(-) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 9e41260fe..008721518 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -10,8 +10,8 @@ endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. SRC_LIST) -include_directories(..) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) qt5_wrap_ui(ui_Main.h Main.ui) diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index 31aa8df96..ed65862a4 100644 --- a/eth/CMakeLists.txt +++ b/eth/CMakeLists.txt @@ -3,9 +3,9 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE eth) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index d0aadc8ae..548f48da8 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${LEVELDB_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE exp) diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt index 40aa7ce24..e3851b7ce 100644 --- a/libdevcore/CMakeLists.txt +++ b/libdevcore/CMakeLists.txt @@ -12,8 +12,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE devcore) diff --git a/libdevcrypto/CMakeLists.txt b/libdevcrypto/CMakeLists.txt index 4cd6daf21..e3c3a1677 100644 --- a/libdevcrypto/CMakeLists.txt +++ b/libdevcrypto/CMakeLists.txt @@ -9,10 +9,10 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE devcrypto) diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 984aa3ce5..920f9f652 100644 --- a/libethcore/CMakeLists.txt +++ b/libethcore/CMakeLists.txt @@ -9,8 +9,8 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE ethcore) diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 3906074fd..86157fdc2 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${LEVELDB_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE ethereum) diff --git a/libethereumx/CMakeLists.txt b/libethereumx/CMakeLists.txt index 4a3cdcda7..373ff8d71 100644 --- a/libethereumx/CMakeLists.txt +++ b/libethereumx/CMakeLists.txt @@ -4,7 +4,8 @@ set(CMAKE_AUTOMOC OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -include_directories(..) + +include_directories(BEFORE ..) set(EXECUTABLE ethereumx) diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt index 4af5eb175..b04df70ea 100644 --- a/libevm/CMakeLists.txt +++ b/libevm/CMakeLists.txt @@ -13,8 +13,8 @@ aux_source_directory(. SRC_LIST) # we may not use it in libevm, but one of our dependecies is including boost in header file # and windows is failing to build without that +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE evm) diff --git a/libevmcore/CMakeLists.txt b/libevmcore/CMakeLists.txt index 9727ee1c9..0f8494804 100644 --- a/libevmcore/CMakeLists.txt +++ b/libevmcore/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE evmcore) diff --git a/liblll/CMakeLists.txt b/liblll/CMakeLists.txt index fb79d5873..3b9dc6030 100644 --- a/liblll/CMakeLists.txt +++ b/liblll/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE lll) diff --git a/libnatspec/CMakeLists.txt b/libnatspec/CMakeLists.txt index b5bd7903e..af15d56a9 100644 --- a/libnatspec/CMakeLists.txt +++ b/libnatspec/CMakeLists.txt @@ -13,7 +13,7 @@ set(CMAKE_AUTOMOC OFF) set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. SRC_LIST) -include_directories(..) +include_directories(BEFORE ..) set(EXECUTABLE natspec) diff --git a/libp2p/CMakeLists.txt b/libp2p/CMakeLists.txt index 6f3f6b712..83309be78 100644 --- a/libp2p/CMakeLists.txt +++ b/libp2p/CMakeLists.txt @@ -11,6 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) # we may not use it in libp2p, but one of our dependecies is including leveldb in header file # and windows is failing to build without that include_directories(${LEVELDB_INCLUDE_DIRS}) @@ -18,7 +19,6 @@ include_directories(${LEVELDB_INCLUDE_DIRS}) if (MINIUPNPC_FOUND) include_directories(${MINIUPNPC_INCLUDE_DIRS}) endif() -include_directories(..) set(EXECUTABLE p2p) diff --git a/libserpent/CMakeLists.txt b/libserpent/CMakeLists.txt index 1c5b8e147..45dfa339d 100644 --- a/libserpent/CMakeLists.txt +++ b/libserpent/CMakeLists.txt @@ -11,7 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -include_directories(..) +include_directories(BEFORE ..) set(EXECUTABLE serpent) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index cccc5e165..2b1059c69 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -include_directories(..) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE solidity) diff --git a/libweb3jsonrpc/CMakeLists.txt b/libweb3jsonrpc/CMakeLists.txt index 34df1633a..867dd7e7e 100644 --- a/libweb3jsonrpc/CMakeLists.txt +++ b/libweb3jsonrpc/CMakeLists.txt @@ -9,8 +9,8 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) -include_directories(..) -include_directories(${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) include_directories(${MHD_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS}) diff --git a/libwebthree/CMakeLists.txt b/libwebthree/CMakeLists.txt index 1d8f23918..f22d4f94f 100644 --- a/libwebthree/CMakeLists.txt +++ b/libwebthree/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${LEVELDB_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE webthree) diff --git a/libwhisper/CMakeLists.txt b/libwhisper/CMakeLists.txt index 79879922e..160347484 100644 --- a/libwhisper/CMakeLists.txt +++ b/libwhisper/CMakeLists.txt @@ -11,7 +11,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -include_directories(..) +include_directories(BEFORE ..) include_directories(${LEVELDB_INCLUDE_DIRS}) set(EXECUTABLE whisper) diff --git a/lllc/CMakeLists.txt b/lllc/CMakeLists.txt index 2157fea74..4fdbdb85f 100644 --- a/lllc/CMakeLists.txt +++ b/lllc/CMakeLists.txt @@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) -include_directories(..) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE lllc) diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 4390a4eb0..24f111909 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -11,8 +11,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. SRC_LIST) -include_directories(..) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) find_package (Qt5WebEngine QUIET) qt5_add_resources(UI_RESOURCES res.qrc) diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt index 4db3d2cf4..caf7d2f97 100644 --- a/neth/CMakeLists.txt +++ b/neth/CMakeLists.txt @@ -2,9 +2,9 @@ cmake_policy(SET CMP0015 NEW) aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS}) -include_directories(..) set(EXECUTABLE neth) diff --git a/sc/CMakeLists.txt b/sc/CMakeLists.txt index ee638bb52..313a47fab 100644 --- a/sc/CMakeLists.txt +++ b/sc/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_policy(SET CMP0015 NEW) aux_source_directory(. SRC_LIST) -include_directories(..) +include_directories(BEFORE ..) set(EXECUTABLE sc) diff --git a/solc/CMakeLists.txt b/solc/CMakeLists.txt index 747effad0..d3a39dbc8 100644 --- a/solc/CMakeLists.txt +++ b/solc/CMakeLists.txt @@ -3,8 +3,8 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) -include_directories(..) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE solc) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6ba07f280..bc14918b8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,8 +4,8 @@ aux_source_directory(. SRC_LIST) list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp") list(REMOVE_ITEM SRC_LIST "./checkRandomTest.cpp") -include_directories(..) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index 3f4981e29..bde47988b 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -10,8 +10,8 @@ endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. SRC_LIST) +include_directories(BEFORE ..) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -include_directories(..) qt5_wrap_ui(ui_Main.h Main.ui) From 7aa3f18bce36e6bbf385f67bbdb9253e21e2b34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 16 Feb 2015 15:26:54 +0100 Subject: [PATCH 106/201] ManyFunctions performance test: ~200 functions in a contract, half of them are called randomly --- test/ManyFunctions.sol | 1485 +++++++++++++++++++++++++++++ test/ManyFunctionsGenerator.py | 24 + test/vmPerformanceTestFiller.json | 29 + 3 files changed, 1538 insertions(+) create mode 100644 test/ManyFunctions.sol create mode 100644 test/ManyFunctionsGenerator.py diff --git a/test/ManyFunctions.sol b/test/ManyFunctions.sol new file mode 100644 index 000000000..60dc61c42 --- /dev/null +++ b/test/ManyFunctions.sol @@ -0,0 +1,1485 @@ + + function right1(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^79) + return right2(r); + return left2(r); + } + + function left1(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^79) + return left2(r); + return right2(r); + } + + + function right2(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^80) + return right3(r); + return left3(r); + } + + function left2(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^80) + return left3(r); + return right3(r); + } + + + function right3(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^81) + return right4(r); + return left4(r); + } + + function left3(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^81) + return left4(r); + return right4(r); + } + + + function right4(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^82) + return right5(r); + return left5(r); + } + + function left4(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^82) + return left5(r); + return right5(r); + } + + + function right5(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^83) + return right6(r); + return left6(r); + } + + function left5(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^83) + return left6(r); + return right6(r); + } + + + function right6(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^84) + return right7(r); + return left7(r); + } + + function left6(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^84) + return left7(r); + return right7(r); + } + + + function right7(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^85) + return right8(r); + return left8(r); + } + + function left7(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^85) + return left8(r); + return right8(r); + } + + + function right8(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^86) + return right9(r); + return left9(r); + } + + function left8(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^86) + return left9(r); + return right9(r); + } + + + function right9(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^87) + return right10(r); + return left10(r); + } + + function left9(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^87) + return left10(r); + return right10(r); + } + + + function right10(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^88) + return right11(r); + return left11(r); + } + + function left10(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^88) + return left11(r); + return right11(r); + } + + + function right11(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^89) + return right12(r); + return left12(r); + } + + function left11(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^89) + return left12(r); + return right12(r); + } + + + function right12(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^90) + return right13(r); + return left13(r); + } + + function left12(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^90) + return left13(r); + return right13(r); + } + + + function right13(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^91) + return right14(r); + return left14(r); + } + + function left13(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^91) + return left14(r); + return right14(r); + } + + + function right14(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^92) + return right15(r); + return left15(r); + } + + function left14(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^92) + return left15(r); + return right15(r); + } + + + function right15(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^93) + return right16(r); + return left16(r); + } + + function left15(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^93) + return left16(r); + return right16(r); + } + + + function right16(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^94) + return right17(r); + return left17(r); + } + + function left16(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^94) + return left17(r); + return right17(r); + } + + + function right17(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^95) + return right18(r); + return left18(r); + } + + function left17(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^95) + return left18(r); + return right18(r); + } + + + function right18(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^96) + return right19(r); + return left19(r); + } + + function left18(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^96) + return left19(r); + return right19(r); + } + + + function right19(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^97) + return right20(r); + return left20(r); + } + + function left19(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^97) + return left20(r); + return right20(r); + } + + + function right20(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^98) + return right21(r); + return left21(r); + } + + function left20(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^98) + return left21(r); + return right21(r); + } + + + function right21(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^99) + return right22(r); + return left22(r); + } + + function left21(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^99) + return left22(r); + return right22(r); + } + + + function right22(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^100) + return right23(r); + return left23(r); + } + + function left22(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^100) + return left23(r); + return right23(r); + } + + + function right23(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^101) + return right24(r); + return left24(r); + } + + function left23(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^101) + return left24(r); + return right24(r); + } + + + function right24(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^102) + return right25(r); + return left25(r); + } + + function left24(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^102) + return left25(r); + return right25(r); + } + + + function right25(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^103) + return right26(r); + return left26(r); + } + + function left25(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^103) + return left26(r); + return right26(r); + } + + + function right26(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^104) + return right27(r); + return left27(r); + } + + function left26(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^104) + return left27(r); + return right27(r); + } + + + function right27(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^105) + return right28(r); + return left28(r); + } + + function left27(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^105) + return left28(r); + return right28(r); + } + + + function right28(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^106) + return right29(r); + return left29(r); + } + + function left28(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^106) + return left29(r); + return right29(r); + } + + + function right29(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^107) + return right30(r); + return left30(r); + } + + function left29(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^107) + return left30(r); + return right30(r); + } + + + function right30(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^108) + return right31(r); + return left31(r); + } + + function left30(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^108) + return left31(r); + return right31(r); + } + + + function right31(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^109) + return right32(r); + return left32(r); + } + + function left31(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^109) + return left32(r); + return right32(r); + } + + + function right32(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^110) + return right33(r); + return left33(r); + } + + function left32(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^110) + return left33(r); + return right33(r); + } + + + function right33(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^111) + return right34(r); + return left34(r); + } + + function left33(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^111) + return left34(r); + return right34(r); + } + + + function right34(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^112) + return right35(r); + return left35(r); + } + + function left34(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^112) + return left35(r); + return right35(r); + } + + + function right35(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^113) + return right36(r); + return left36(r); + } + + function left35(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^113) + return left36(r); + return right36(r); + } + + + function right36(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^114) + return right37(r); + return left37(r); + } + + function left36(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^114) + return left37(r); + return right37(r); + } + + + function right37(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^115) + return right38(r); + return left38(r); + } + + function left37(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^115) + return left38(r); + return right38(r); + } + + + function right38(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^116) + return right39(r); + return left39(r); + } + + function left38(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^116) + return left39(r); + return right39(r); + } + + + function right39(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^117) + return right40(r); + return left40(r); + } + + function left39(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^117) + return left40(r); + return right40(r); + } + + + function right40(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^118) + return right41(r); + return left41(r); + } + + function left40(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^118) + return left41(r); + return right41(r); + } + + + function right41(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^119) + return right42(r); + return left42(r); + } + + function left41(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^119) + return left42(r); + return right42(r); + } + + + function right42(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^120) + return right43(r); + return left43(r); + } + + function left42(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^120) + return left43(r); + return right43(r); + } + + + function right43(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^121) + return right44(r); + return left44(r); + } + + function left43(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^121) + return left44(r); + return right44(r); + } + + + function right44(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^122) + return right45(r); + return left45(r); + } + + function left44(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^122) + return left45(r); + return right45(r); + } + + + function right45(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^123) + return right46(r); + return left46(r); + } + + function left45(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^123) + return left46(r); + return right46(r); + } + + + function right46(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^124) + return right47(r); + return left47(r); + } + + function left46(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^124) + return left47(r); + return right47(r); + } + + + function right47(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^125) + return right48(r); + return left48(r); + } + + function left47(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^125) + return left48(r); + return right48(r); + } + + + function right48(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^126) + return right49(r); + return left49(r); + } + + function left48(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^126) + return left49(r); + return right49(r); + } + + + function right49(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^127) + return right50(r); + return left50(r); + } + + function left49(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^127) + return left50(r); + return right50(r); + } + + + function right50(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^128) + return right51(r); + return left51(r); + } + + function left50(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^128) + return left51(r); + return right51(r); + } + + + function right51(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^129) + return right52(r); + return left52(r); + } + + function left51(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^129) + return left52(r); + return right52(r); + } + + + function right52(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^130) + return right53(r); + return left53(r); + } + + function left52(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^130) + return left53(r); + return right53(r); + } + + + function right53(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^131) + return right54(r); + return left54(r); + } + + function left53(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^131) + return left54(r); + return right54(r); + } + + + function right54(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^132) + return right55(r); + return left55(r); + } + + function left54(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^132) + return left55(r); + return right55(r); + } + + + function right55(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^133) + return right56(r); + return left56(r); + } + + function left55(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^133) + return left56(r); + return right56(r); + } + + + function right56(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^134) + return right57(r); + return left57(r); + } + + function left56(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^134) + return left57(r); + return right57(r); + } + + + function right57(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^135) + return right58(r); + return left58(r); + } + + function left57(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^135) + return left58(r); + return right58(r); + } + + + function right58(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^136) + return right59(r); + return left59(r); + } + + function left58(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^136) + return left59(r); + return right59(r); + } + + + function right59(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^137) + return right60(r); + return left60(r); + } + + function left59(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^137) + return left60(r); + return right60(r); + } + + + function right60(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^138) + return right61(r); + return left61(r); + } + + function left60(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^138) + return left61(r); + return right61(r); + } + + + function right61(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^139) + return right62(r); + return left62(r); + } + + function left61(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^139) + return left62(r); + return right62(r); + } + + + function right62(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^140) + return right63(r); + return left63(r); + } + + function left62(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^140) + return left63(r); + return right63(r); + } + + + function right63(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^141) + return right64(r); + return left64(r); + } + + function left63(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^141) + return left64(r); + return right64(r); + } + + + function right64(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^142) + return right65(r); + return left65(r); + } + + function left64(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^142) + return left65(r); + return right65(r); + } + + + function right65(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^143) + return right66(r); + return left66(r); + } + + function left65(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^143) + return left66(r); + return right66(r); + } + + + function right66(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^144) + return right67(r); + return left67(r); + } + + function left66(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^144) + return left67(r); + return right67(r); + } + + + function right67(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^145) + return right68(r); + return left68(r); + } + + function left67(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^145) + return left68(r); + return right68(r); + } + + + function right68(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^146) + return right69(r); + return left69(r); + } + + function left68(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^146) + return left69(r); + return right69(r); + } + + + function right69(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^147) + return right70(r); + return left70(r); + } + + function left69(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^147) + return left70(r); + return right70(r); + } + + + function right70(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^148) + return right71(r); + return left71(r); + } + + function left70(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^148) + return left71(r); + return right71(r); + } + + + function right71(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^149) + return right72(r); + return left72(r); + } + + function left71(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^149) + return left72(r); + return right72(r); + } + + + function right72(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^150) + return right73(r); + return left73(r); + } + + function left72(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^150) + return left73(r); + return right73(r); + } + + + function right73(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^151) + return right74(r); + return left74(r); + } + + function left73(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^151) + return left74(r); + return right74(r); + } + + + function right74(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^152) + return right75(r); + return left75(r); + } + + function left74(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^152) + return left75(r); + return right75(r); + } + + + function right75(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^153) + return right76(r); + return left76(r); + } + + function left75(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^153) + return left76(r); + return right76(r); + } + + + function right76(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^154) + return right77(r); + return left77(r); + } + + function left76(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^154) + return left77(r); + return right77(r); + } + + + function right77(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^155) + return right78(r); + return left78(r); + } + + function left77(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^155) + return left78(r); + return right78(r); + } + + + function right78(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^156) + return right79(r); + return left79(r); + } + + function left78(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^156) + return left79(r); + return right79(r); + } + + + function right79(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^157) + return right80(r); + return left80(r); + } + + function left79(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^157) + return left80(r); + return right80(r); + } + + + function right80(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^158) + return right81(r); + return left81(r); + } + + function left80(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^158) + return left81(r); + return right81(r); + } + + + function right81(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^159) + return right82(r); + return left82(r); + } + + function left81(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^159) + return left82(r); + return right82(r); + } + + + function right82(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^160) + return right83(r); + return left83(r); + } + + function left82(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^160) + return left83(r); + return right83(r); + } + + + function right83(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^161) + return right84(r); + return left84(r); + } + + function left83(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^161) + return left84(r); + return right84(r); + } + + + function right84(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^162) + return right85(r); + return left85(r); + } + + function left84(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^162) + return left85(r); + return right85(r); + } + + + function right85(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^163) + return right86(r); + return left86(r); + } + + function left85(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^163) + return left86(r); + return right86(r); + } + + + function right86(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^164) + return right87(r); + return left87(r); + } + + function left86(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^164) + return left87(r); + return right87(r); + } + + + function right87(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^165) + return right88(r); + return left88(r); + } + + function left87(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^165) + return left88(r); + return right88(r); + } + + + function right88(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^166) + return right89(r); + return left89(r); + } + + function left88(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^166) + return left89(r); + return right89(r); + } + + + function right89(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^167) + return right90(r); + return left90(r); + } + + function left89(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^167) + return left90(r); + return right90(r); + } + + + function right90(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^168) + return right91(r); + return left91(r); + } + + function left90(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^168) + return left91(r); + return right91(r); + } + + + function right91(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^169) + return right92(r); + return left92(r); + } + + function left91(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^169) + return left92(r); + return right92(r); + } + + + function right92(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^170) + return right93(r); + return left93(r); + } + + function left92(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^170) + return left93(r); + return right93(r); + } + + + function right93(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^171) + return right94(r); + return left94(r); + } + + function left93(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^171) + return left94(r); + return right94(r); + } + + + function right94(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^172) + return right95(r); + return left95(r); + } + + function left94(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^172) + return left95(r); + return right95(r); + } + + + function right95(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^173) + return right96(r); + return left96(r); + } + + function left95(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^173) + return left96(r); + return right96(r); + } + + + function right96(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^174) + return right97(r); + return left97(r); + } + + function left96(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^174) + return left97(r); + return right97(r); + } + + + function right97(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^175) + return right98(r); + return left98(r); + } + + function left97(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^175) + return left98(r); + return right98(r); + } + + + function right98(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^176) + return right99(r); + return left99(r); + } + + function left98(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^176) + return left99(r); + return right99(r); + } + + + function right99(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2^177) + return right100(r); + return left100(r); + } + + function left99(uint seed) returns (uint) { + var r = nextRand(nextRand(seed)); + if (r >= 2^177) + return left100(r); + return right100(r); + } + diff --git a/test/ManyFunctionsGenerator.py b/test/ManyFunctionsGenerator.py new file mode 100644 index 000000000..93eef784c --- /dev/null +++ b/test/ManyFunctionsGenerator.py @@ -0,0 +1,24 @@ + +n = 100 + +splitNumBegin = 128 - (n / 2) +i = 1 + +template = """ + function right{0}(uint seed) returns (uint) {{ + var r = nextRand(seed); + if (r >= 2^{2}) + return right{1}(r); + return left{1}(r); + }} + + function left{0}(uint seed) returns (uint) {{ + var r = nextRand(nextRand(seed)); + if (r >= 2^{2}) + return left{1}(r); + return right{1}(r); + }} +""" + +for i in range(1, n): + print template.format(i, i + 1, i + splitNumBegin) \ No newline at end of file diff --git a/test/vmPerformanceTestFiller.json b/test/vmPerformanceTestFiller.json index 3292916ec..eab8a2240 100644 --- a/test/vmPerformanceTestFiller.json +++ b/test/vmPerformanceTestFiller.json @@ -1,4 +1,33 @@ { + "manyFunctions100": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "100000000000", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "//" : "ManyFunctions.sol", + "code" : "0x60e060020a60003504806301f99ad7146108c3578063023a624a146108d857806303bdecf5146108ed57806305fe035f14610902578063082d8f4914610917578063090bf3b71461092c5780630bd9c534146109415780630c4bfa94146109565780630e20ebe21461096b5780630f76de0d1461098057806310cfcc191461099557806313ce15a9146109aa578063140dcec4146109bf57806314d07a3e146109d45780631687f112146109e957806316eb6603146109fe578063172cf71714610a135780631bd6f59614610a285780631cdb857114610a3d5780631cf74ece14610a525780631d09ba2c14610a675780631f69aa5114610a7c578063223dcc7414610a9157806325e524d314610aa6578063261de7c414610abb5780632632924d14610ad05780632909cc5d14610ae55780632981699814610afa5780632a85a45d14610b0f5780632ca36da014610b245780632cbf1f0d14610b395780632d0f557314610b4e5780632d97867814610b6357806331db9efd14610b7857806332064db714610b8d57806332931fbb14610ba2578063355f51a014610bb7578063361bb34014610bcc578063364ddb0e14610be15780633792a01814610bf657806338c68f8f14610c0b57806338e586fd14610c20578063392d42ae14610c3557806339a87bd914610c4a5780633a95a33214610c5f5780633b8ecdf914610c745780633cf0659a14610c895780633eaf992314610c9e5780633fe97ead14610cb35780633ff11c8b14610cc8578063404efc5314610cdd578063407fce7b14610cf257806340c3b18714610d07578063440208c314610d1c57806344e86b2f14610d31578063455df57914610d465780634689ab4d14610d5b57806346be2e0c14610d70578063487cd86f14610d8557806348e6178214610d9a57806349d4a34414610daf5780634a0f597414610dc45780634bc24ec514610dd95780634c2fe45614610dee5780634cc885d414610e035780634eaaad7b14610e185780634eb166af14610e2d5780635050093414610e42578063506bff1114610e57578063508762c114610e6c578063526938f814610e8157806354400c6014610e96578063559510d814610eab57806355a5f70214610ec057806356ca528f14610ed5578063570a2a1614610eea5780635dab2e0f14610eff5780635dca53d314610f1457806362017ebc14610f29578063621a25f814610f3e578063626d4a3614610f5357806362b6a28214610f6857806364faf22c14610f7d57806366d7ffde14610f9257806367b886e814610fa757806367e902c714610fbc57806369d7774014610fd15780636b7ae8e614610fe65780636c3b659114610ffb5780636e54181e146110105780636e978d91146110255780636f63d2ec1461103a578063706332d11461104f57806370ac4bb9146110645780637138ef521461107957806371dd46a91461108e57806372a7c229146110a35780637376fc8d146110b8578063738a2679146110cd57806374552650146110e2578063746fc8d0146110f757806379254bb81461110c5780637adaa3f8146111215780637e4eb35b14611136578063885ec18e1461114b5780638b9ff6b6146111605780638ce113dc146111755780638defbc5e1461118a5780638f4613d51461119f5780638fdc24ba146111b45780639002dba4146111c957806391d15735146111de57806391d43b23146111f357806393b14daa1461120857806394d63afd1461121d57806395805dad1461123257806396f68782146112475780639740e4a21461125c578063981290131461127157806399a3f0e8146112865780639acb1ad41461129b5780639be07908146112b05780639c15be0b146112c55780639d451c4d146112da5780639d8ee943146112ef5780639ef6ca0f14611304578063a0db0a2214611319578063a18e2eb91461132e578063a408384914611343578063a57544da14611358578063a5a83e4d1461136d578063a6843f3414611382578063a6dacdd714611397578063a8c4c8bc146113ac578063aa058a73146113c1578063aad62da2146113d6578063aaf3e4f4146113eb578063ab81e77314611400578063abc93aee14611415578063abde33f71461142a578063b114b96c1461143f578063b3df873714611454578063b4174cb014611469578063b5d02a561461147e578063b731e84814611493578063b7b96723146114a8578063bbcded7a146114bd578063bbececa9146114d2578063beca7440146114e7578063bf8981c0146114fc578063c028c67414611511578063c2385fa614611526578063c319a02c1461153b578063c569bae014611550578063c6715f8114611565578063c7b98dec1461157a578063c9acab841461158f578063ca9efc73146115a4578063cad80024146115b9578063cdadb0fa146115ce578063cdbdf391146115e3578063cf460fa5146115f8578063cf69318a1461160d578063d1835b8c14611622578063d353a1cb14611637578063d3e141e01461164c578063d5ec7e1d14611661578063d7ead1de14611676578063d90b02aa1461168b578063d959e244146116a0578063d9e68b44146116b5578063daacb24f146116ca578063dc12a805146116df578063dd946033146116f4578063dda5142414611709578063de6612171461171e578063dfb9560c14611733578063e03827d214611748578063e21720001461175d578063e2c718d814611772578063e3da539914611787578063e48e603f1461179c578063e5f9ec29146117b1578063e6c0459a146117c6578063e70addec146117db578063e7a01215146117f0578063ea7f4d2714611805578063ebb6c59f1461181a578063ed6302be1461182f578063ed64b36b14611844578063eecd278914611859578063f0ed14e01461186e578063f0f2134414611883578063f1e328f914611898578063f1e6f4cd146118ad578063f32fe995146118c2578063f75165c6146118d7578063f7ed71d0146118ec578063f80f44f314611901578063f8bc050514611916578063fbd3c51a1461192b578063fd72009014611940578063fed3a3001461195557005b6108ce600435611e83565b8060005260206000f35b6108e3600435611f50565b8060005260206000f35b6108f8600435613deb565b8060005260206000f35b61090d6004356119e8565b8060005260206000f35b610922600435612f82565b8060005260206000f35b6109376004356128fb565b8060005260206000f35b61094c60043561304f565b8060005260206000f35b61096160043561209b565b8060005260206000f35b610976600435614c0d565b8060005260206000f35b61098b60043561319a565b8060005260206000f35b6109a06004356122b3565b8060005260206000f35b6109b5600435613d1e565b8060005260206000f35b6109ca600435612598565b8060005260206000f35b6109df600435612875565b8060005260206000f35b6109f4600435613650565b8060005260206000f35b610a096004356133f9565b8060005260206000f35b610a1e6004356136d6565b8060005260206000f35b610a3360043561371d565b8060005260206000f35b610a48600435611ad9565b8060005260206000f35b610a5d60043561375c565b8060005260206000f35b610a72600435612168565b8060005260206000f35b610a8760043561425a565b8060005260206000f35b610a9c600435612121565b8060005260206000f35b610ab1600435611dbe565b8060005260206000f35b610ac6600435612b13565b8060005260206000f35b610adb600435612981565b8060005260206000f35b610af060043561222d565b8060005260206000f35b610b05600435613ac7565b8060005260206000f35b610b1a600435612db1565b8060005260206000f35b610b2f600435612e76565b8060005260206000f35b610b44600435613a80565b8060005260206000f35b610b59600435612c1f565b8060005260206000f35b610b6e6004356125d7565b8060005260206000f35b610b836004356147dd565b8060005260206000f35b610b98600435612445565b8060005260206000f35b610bad600435611a53565b8060005260206000f35b610bc2600435613373565b8060005260206000f35b610bd760043561332c565b8060005260206000f35b610bec600435613544565b8060005260206000f35b610c01600435611dfd565b8060005260206000f35b610c166004356145c5565b8060005260206000f35b610c2b600435611c2c565b8060005260206000f35b610c40600435612df0565b8060005260206000f35b610c55600435612a46565b8060005260206000f35b610c6a6004356137e2565b8060005260206000f35b610c7f600435611b20565b8060005260206000f35b610c946004356126a4565b8060005260206000f35b610ca9600435613d65565b8060005260206000f35b610cbe6004356133b2565b8060005260206000f35b610cd360043561464b565b8060005260206000f35b610ce8600435612769565b8060005260206000f35b610cfd600435612015565b8060005260206000f35b610d12600435612d6a565b8060005260206000f35b610d27600435611fd6565b8060005260206000f35b610d3c600435613f36565b8060005260206000f35b610d51600435614604565b8060005260206000f35b610d6660043561248c565b8060005260206000f35b610d7b600435612acc565b8060005260206000f35b610d90600435612b99565b8060005260206000f35b610da5600435611be5565b8060005260206000f35b610dba6004356129c8565b8060005260206000f35b610dcf6004356127ef565b8060005260206000f35b610de46004356139bb565b8060005260206000f35b610df9600435614b01565b8060005260206000f35b610e0e600435613bd3565b8060005260206000f35b610e23600435613fbc565b8060005260206000f35b610e38600435614003565b8060005260206000f35b610e4d600435612836565b8060005260206000f35b610e62600435611d77565b8060005260206000f35b610e77600435611eca565b8060005260206000f35b610e8c600435612c5e565b8060005260206000f35b610ea1600435612380565b8060005260206000f35b610eb66004356135ca565b8060005260206000f35b610ecb60043561315b565b8060005260206000f35b610ee06004356122fa565b8060005260206000f35b610ef560043561358b565b8060005260206000f35b610f0a6004356144f8565b8060005260206000f35b610f1f600435612942565b8060005260206000f35b610f34600435613220565b8060005260206000f35b610f49600435613c59565b8060005260206000f35b610f5e600435613697565b8060005260206000f35b610f73600435613008565b8060005260206000f35b610f88600435612339565b8060005260206000f35b610f9d60043561265d565b8060005260206000f35b610fb2600435614cd2565b8060005260206000f35b610fc76004356149f5565b8060005260206000f35b610fdc600435614a34565b8060005260206000f35b610ff16004356140c8565b8060005260206000f35b61100660043561453f565b8060005260206000f35b61101b60043561410f565b8060005260206000f35b6110306004356148e9565b8060005260206000f35b611045600435613c98565b8060005260206000f35b61105a6004356131e1565b8060005260206000f35b61106f600435612a8d565b8060005260206000f35b611084600435611e44565b8060005260206000f35b6110996004356123bf565b8060005260206000f35b6110ae600435612f43565b8060005260206000f35b6110c3600435613cdf565b8060005260206000f35b6110d860043561468a565b8060005260206000f35b6110ed600435614bc6565b8060005260206000f35b611102600435613267565b8060005260206000f35b6111176004356128bc565b8060005260206000f35b61112c600435612e37565b8060005260206000f35b61114160043561308e565b8060005260206000f35b611156600435611cf1565b8060005260206000f35b61116b6004356149ae565b8060005260206000f35b611180600435613935565b8060005260206000f35b611195600435612a07565b8060005260206000f35b6111aa600435611f09565b8060005260206000f35b6111bf600435614b40565b8060005260206000f35b6111d4600435612274565b8060005260206000f35b6111e9600435611f8f565b8060005260206000f35b6111fe600435614195565b8060005260206000f35b6112136004356120e2565b8060005260206000f35b611228600435611b5f565b8060005260206000f35b61123d60043561196a565b8060005260206000f35b611252600435613a41565b8060005260206000f35b611267600435614796565b8060005260206000f35b61127c6004356132a6565b8060005260206000f35b611291600435613e71565b8060005260206000f35b6112a6600435612d2b565b8060005260206000f35b6112bb600435614366565b8060005260206000f35b6112d0600435613c12565b8060005260206000f35b6112e560043561421b565b8060005260206000f35b6112fa600435613ef7565b8060005260206000f35b61130f600435612b52565b8060005260206000f35b611324600435611ba6565b8060005260206000f35b611339600435613e2a565b8060005260206000f35b61134e6004356130d5565b8060005260206000f35b611363600435612ca5565b8060005260206000f35b61137860043561496f565b8060005260206000f35b61138d6004356132ed565b8060005260206000f35b6113a26004356138af565b8060005260206000f35b6113b7600435613b4d565b8060005260206000f35b6113cc600435611cb2565b8060005260206000f35b6113e16004356148a2565b8060005260206000f35b6113f660043561481c565b8060005260206000f35b61140b6004356139fa565b8060005260206000f35b611420600435613b8c565b8060005260206000f35b61143560043561272a565b8060005260206000f35b61144a600435614d9f565b8060005260206000f35b61145f600435613438565b8060005260206000f35b61147460043561347f565b8060005260206000f35b6114896004356119b3565b8060005260206000f35b61149e600435614aba565b8060005260206000f35b6114b3600435611d38565b8060005260206000f35b6114c8600435614042565b8060005260206000f35b6114dd6004356142e0565b8060005260206000f35b6114f2600435613505565b8060005260206000f35b611507600435612ce4565b8060005260206000f35b61151c6004356144b9565b8060005260206000f35b6115316004356142a1565b8060005260206000f35b611546600435614d19565b8060005260206000f35b61155b600435614a7b565b8060005260206000f35b611570600435613114565b8060005260206000f35b611585600435611a14565b8060005260206000f35b61159a6004356138ee565b8060005260206000f35b6115af600435614472565b8060005260206000f35b6115c4600435613868565b8060005260206000f35b6115d9600435613829565b8060005260206000f35b6115ee600435612bd8565b8060005260206000f35b6116036004356121ee565b8060005260206000f35b611618600435613974565b8060005260206000f35b61162d6004356124cb565b8060005260206000f35b6116426004356119a9565b8060005260206000f35b611657600435611c6b565b8060005260206000f35b61166c600435612551565b8060005260206000f35b611681600435614089565b8060005260206000f35b6116966004356143ec565b8060005260206000f35b6116ab6004356126e3565b8060005260206000f35b6116c06004356119fa565b8060005260206000f35b6116d5600435612fc9565b8060005260206000f35b6116ea6004356137a3565b8060005260206000f35b6116ff600435614433565b8060005260206000f35b6117146004356143ad565b8060005260206000f35b61172960043561414e565b8060005260206000f35b61173e60043561261e565b8060005260206000f35b611753600435613eb0565b8060005260206000f35b611768600435613b06565b8060005260206000f35b61177d600435612406565b8060005260206000f35b611792600435614928565b8060005260206000f35b6117a7600435613611565b8060005260206000f35b6117bc6004356134be565b8060005260206000f35b6117d1600435614327565b8060005260206000f35b6117e6600435614757565b8060005260206000f35b6117fb600435611a9a565b8060005260206000f35b61181060043561205c565b8060005260206000f35b611825600435613f7d565b8060005260206000f35b61183a600435614d58565b8060005260206000f35b61184f6004356121a7565b8060005260206000f35b611864600435614710565b8060005260206000f35b611879600435614b87565b8060005260206000f35b61188e6004356127b0565b8060005260206000f35b6118a3600435613da4565b8060005260206000f35b6118b8600435612ebd565b8060005260206000f35b6118cd600435614c4c565b8060005260206000f35b6118e2600435612512565b8060005260206000f35b6118f7600435612efc565b8060005260206000f35b61190c600435614c93565b8060005260206000f35b6119216004356141d4565b8060005260206000f35b61193660043561457e565b8060005260206000f35b61194b6004356146d1565b8060005260206000f35b611960600435614863565b8060005260206000f35b60006000611977836119b3565b9050604c81101561198757611997565b61199081611a53565b91506119a3565b6119a081611a14565b91505b50919050565b6000819050919050565b600060007f5851f42d4c957f2c0000000000000000000000000000000000000000000000019050828102600101915050919050565b60006119f3826119a9565b9050919050565b6000611a0d611a08836119b3565b6119a9565b9050919050565b60006000611a21836119b3565b9050604d811015611a3157611a41565b611a3a81611a9a565b9150611a4d565b611a4a81611ad9565b91505b50919050565b60006000611a68611a63846119b3565b6119b3565b9050604d811015611a7857611a88565b611a8181611ad9565b9150611a94565b611a9181611a9a565b91505b50919050565b60006000611aa7836119b3565b90506052811015611ab757611ac7565b611ac081611b20565b9150611ad3565b611ad081611b5f565b91505b50919050565b60006000611aee611ae9846119b3565b6119b3565b90506052811015611afe57611b0e565b611b0781611b5f565b9150611b1a565b611b1781611b20565b91505b50919050565b60006000611b2d836119b3565b90506053811015611b3d57611b4d565b611b4681611ba6565b9150611b59565b611b5681611be5565b91505b50919050565b60006000611b74611b6f846119b3565b6119b3565b90506053811015611b8457611b94565b611b8d81611be5565b9150611ba0565b611b9d81611ba6565b91505b50919050565b60006000611bb3836119b3565b90506050811015611bc357611bd3565b611bcc81611c2c565b9150611bdf565b611bdc81611c6b565b91505b50919050565b60006000611bfa611bf5846119b3565b6119b3565b90506050811015611c0a57611c1a565b611c1381611c6b565b9150611c26565b611c2381611c2c565b91505b50919050565b60006000611c39836119b3565b90506051811015611c4957611c59565b611c5281611cb2565b9150611c65565b611c6281611cf1565b91505b50919050565b60006000611c80611c7b846119b3565b6119b3565b90506051811015611c9057611ca0565b611c9981611cf1565b9150611cac565b611ca981611cb2565b91505b50919050565b60006000611cbf836119b3565b90506056811015611ccf57611cdf565b611cd881611d38565b9150611ceb565b611ce881611d77565b91505b50919050565b60006000611d06611d01846119b3565b6119b3565b90506056811015611d1657611d26565b611d1f81611d77565b9150611d32565b611d2f81611d38565b91505b50919050565b60006000611d45836119b3565b90506057811015611d5557611d65565b611d5e81611dbe565b9150611d71565b611d6e81611dfd565b91505b50919050565b60006000611d8c611d87846119b3565b6119b3565b90506057811015611d9c57611dac565b611da581611dfd565b9150611db8565b611db581611dbe565b91505b50919050565b60006000611dcb836119b3565b90506054811015611ddb57611deb565b611de481611e44565b9150611df7565b611df481611e83565b91505b50919050565b60006000611e12611e0d846119b3565b6119b3565b90506054811015611e2257611e32565b611e2b81611e83565b9150611e3e565b611e3b81611e44565b91505b50919050565b60006000611e51836119b3565b90506055811015611e6157611e71565b611e6a81611eca565b9150611e7d565b611e7a81611f09565b91505b50919050565b60006000611e98611e93846119b3565b6119b3565b90506055811015611ea857611eb8565b611eb181611f09565b9150611ec4565b611ec181611eca565b91505b50919050565b60006000611ed7836119b3565b9050605a811015611ee757611ef7565b611ef081611f50565b9150611f03565b611f0081611f8f565b91505b50919050565b60006000611f1e611f19846119b3565b6119b3565b9050605a811015611f2e57611f3e565b611f3781611f8f565b9150611f4a565b611f4781611f50565b91505b50919050565b60006000611f5d836119b3565b9050605b811015611f6d57611f7d565b611f7681611fd6565b9150611f89565b611f8681612015565b91505b50919050565b60006000611fa4611f9f846119b3565b6119b3565b9050605b811015611fb457611fc4565b611fbd81612015565b9150611fd0565b611fcd81611fd6565b91505b50919050565b60006000611fe3836119b3565b90506058811015611ff357612003565b611ffc8161205c565b915061200f565b61200c8161209b565b91505b50919050565b6000600061202a612025846119b3565b6119b3565b9050605881101561203a5761204a565b6120438161209b565b9150612056565b6120538161205c565b91505b50919050565b60006000612069836119b3565b9050605981101561207957612089565b612082816120e2565b9150612095565b61209281612121565b91505b50919050565b600060006120b06120ab846119b3565b6119b3565b905060598110156120c0576120d0565b6120c981612121565b91506120dc565b6120d9816120e2565b91505b50919050565b600060006120ef836119b3565b9050605e8110156120ff5761210f565b61210881612168565b915061211b565b612118816121a7565b91505b50919050565b60006000612136612131846119b3565b6119b3565b9050605e81101561214657612156565b61214f816121a7565b9150612162565b61215f81612168565b91505b50919050565b60006000612175836119b3565b9050605f81101561218557612195565b61218e816121ee565b91506121a1565b61219e8161222d565b91505b50919050565b600060006121bc6121b7846119b3565b6119b3565b9050605f8110156121cc576121dc565b6121d58161222d565b91506121e8565b6121e5816121ee565b91505b50919050565b600060006121fb836119b3565b9050605c81101561220b5761221b565b61221481612274565b9150612227565b612224816122b3565b91505b50919050565b6000600061224261223d846119b3565b6119b3565b9050605c81101561225257612262565b61225b816122b3565b915061226e565b61226b81612274565b91505b50919050565b60006000612281836119b3565b9050605d811015612291576122a1565b61229a816122fa565b91506122ad565b6122aa81612339565b91505b50919050565b600060006122c86122c3846119b3565b6119b3565b9050605d8110156122d8576122e8565b6122e181612339565b91506122f4565b6122f1816122fa565b91505b50919050565b60006000612307836119b3565b9050606281101561231757612327565b61232081612380565b9150612333565b612330816123bf565b91505b50919050565b6000600061234e612349846119b3565b6119b3565b9050606281101561235e5761236e565b612367816123bf565b915061237a565b61237781612380565b91505b50919050565b6000600061238d836119b3565b9050606381101561239d576123ad565b6123a681612406565b91506123b9565b6123b681612445565b91505b50919050565b600060006123d46123cf846119b3565b6119b3565b905060638110156123e4576123f4565b6123ed81612445565b9150612400565b6123fd81612406565b91505b50919050565b60006000612413836119b3565b9050606081101561242357612433565b61242c8161248c565b915061243f565b61243c816124cb565b91505b50919050565b6000600061245a612455846119b3565b6119b3565b9050606081101561246a5761247a565b612473816124cb565b9150612486565b6124838161248c565b91505b50919050565b60006000612499836119b3565b905060618110156124a9576124b9565b6124b281612512565b91506124c5565b6124c281612551565b91505b50919050565b600060006124e06124db846119b3565b6119b3565b905060618110156124f057612500565b6124f981612551565b915061250c565b61250981612512565b91505b50919050565b6000600061251f836119b3565b9050606681101561252f5761253f565b61253881612598565b915061254b565b612548816125d7565b91505b50919050565b60006000612566612561846119b3565b6119b3565b9050606681101561257657612586565b61257f816125d7565b9150612592565b61258f81612598565b91505b50919050565b600060006125a5836119b3565b905060678110156125b5576125c5565b6125be8161261e565b91506125d1565b6125ce8161265d565b91505b50919050565b600060006125ec6125e7846119b3565b6119b3565b905060678110156125fc5761260c565b6126058161265d565b9150612618565b6126158161261e565b91505b50919050565b6000600061262b836119b3565b9050606481101561263b5761264b565b612644816126a4565b9150612657565b612654816126e3565b91505b50919050565b6000600061267261266d846119b3565b6119b3565b9050606481101561268257612692565b61268b816126e3565b915061269e565b61269b816126a4565b91505b50919050565b600060006126b1836119b3565b905060658110156126c1576126d1565b6126ca8161272a565b91506126dd565b6126da81612769565b91505b50919050565b600060006126f86126f3846119b3565b6119b3565b9050606581101561270857612718565b61271181612769565b9150612724565b6127218161272a565b91505b50919050565b60006000612737836119b3565b9050606a81101561274757612757565b612750816127b0565b9150612763565b612760816127ef565b91505b50919050565b6000600061277e612779846119b3565b6119b3565b9050606a81101561278e5761279e565b612797816127ef565b91506127aa565b6127a7816127b0565b91505b50919050565b600060006127bd836119b3565b9050606b8110156127cd576127dd565b6127d681612836565b91506127e9565b6127e681612875565b91505b50919050565b600060006128046127ff846119b3565b6119b3565b9050606b81101561281457612824565b61281d81612875565b9150612830565b61282d81612836565b91505b50919050565b60006000612843836119b3565b9050606881101561285357612863565b61285c816128bc565b915061286f565b61286c816128fb565b91505b50919050565b6000600061288a612885846119b3565b6119b3565b9050606881101561289a576128aa565b6128a3816128fb565b91506128b6565b6128b3816128bc565b91505b50919050565b600060006128c9836119b3565b905060698110156128d9576128e9565b6128e281612942565b91506128f5565b6128f281612981565b91505b50919050565b6000600061291061290b846119b3565b6119b3565b9050606981101561292057612930565b61292981612981565b915061293c565b61293981612942565b91505b50919050565b6000600061294f836119b3565b9050606e81101561295f5761296f565b61296881612a07565b915061297b565b61297881612a46565b91505b50919050565b60006000612996612991846119b3565b6119b3565b9050606e8110156129a6576129b6565b6129af81612a46565b91506129c2565b6129bf81612a07565b91505b50919050565b600060006129d5836119b3565b905060b38110156129e5576129f5565b6129ee816119e8565b9150612a01565b6129fe816119fa565b91505b50919050565b60006000612a14836119b3565b9050606f811015612a2457612a34565b612a2d81612a8d565b9150612a40565b612a3d81612acc565b91505b50919050565b60006000612a5b612a56846119b3565b6119b3565b9050606f811015612a6b57612a7b565b612a7481612acc565b9150612a87565b612a8481612a8d565b91505b50919050565b60006000612a9a836119b3565b9050606c811015612aaa57612aba565b612ab381612b13565b9150612ac6565b612ac381612b52565b91505b50919050565b60006000612ae1612adc846119b3565b6119b3565b9050606c811015612af157612b01565b612afa81612b52565b9150612b0d565b612b0a81612b13565b91505b50919050565b60006000612b20836119b3565b9050606d811015612b3057612b40565b612b3981612b99565b9150612b4c565b612b4981612bd8565b91505b50919050565b60006000612b67612b62846119b3565b6119b3565b9050606d811015612b7757612b87565b612b8081612bd8565b9150612b93565b612b9081612b99565b91505b50919050565b60006000612ba6836119b3565b90506072811015612bb657612bc6565b612bbf81612c1f565b9150612bd2565b612bcf81612c5e565b91505b50919050565b60006000612bed612be8846119b3565b6119b3565b90506072811015612bfd57612c0d565b612c0681612c5e565b9150612c19565b612c1681612c1f565b91505b50919050565b60006000612c2c836119b3565b90506073811015612c3c57612c4c565b612c4581612ca5565b9150612c58565b612c5581612ce4565b91505b50919050565b60006000612c73612c6e846119b3565b6119b3565b90506073811015612c8357612c93565b612c8c81612ce4565b9150612c9f565b612c9c81612ca5565b91505b50919050565b60006000612cb2836119b3565b90506070811015612cc257612cd2565b612ccb81612d2b565b9150612cde565b612cdb81612d6a565b91505b50919050565b60006000612cf9612cf4846119b3565b6119b3565b90506070811015612d0957612d19565b612d1281612d6a565b9150612d25565b612d2281612d2b565b91505b50919050565b60006000612d38836119b3565b90506071811015612d4857612d58565b612d5181612db1565b9150612d64565b612d6181612df0565b91505b50919050565b60006000612d7f612d7a846119b3565b6119b3565b90506071811015612d8f57612d9f565b612d9881612df0565b9150612dab565b612da881612db1565b91505b50919050565b60006000612dbe836119b3565b90506076811015612dce57612dde565b612dd781612e37565b9150612dea565b612de781612e76565b91505b50919050565b60006000612e05612e00846119b3565b6119b3565b90506076811015612e1557612e25565b612e1e81612e76565b9150612e31565b612e2e81612e37565b91505b50919050565b60006000612e44836119b3565b90506077811015612e5457612e64565b612e5d81612ebd565b9150612e70565b612e6d81612efc565b91505b50919050565b60006000612e8b612e86846119b3565b6119b3565b90506077811015612e9b57612eab565b612ea481612efc565b9150612eb7565b612eb481612ebd565b91505b50919050565b60006000612eca836119b3565b90506074811015612eda57612eea565b612ee381612f43565b9150612ef6565b612ef381612f82565b91505b50919050565b60006000612f11612f0c846119b3565b6119b3565b90506074811015612f2157612f31565b612f2a81612f82565b9150612f3d565b612f3a81612f43565b91505b50919050565b60006000612f50836119b3565b90506075811015612f6057612f70565b612f6981612fc9565b9150612f7c565b612f7981613008565b91505b50919050565b60006000612f97612f92846119b3565b6119b3565b90506075811015612fa757612fb7565b612fb081613008565b9150612fc3565b612fc081612fc9565b91505b50919050565b60006000612fd6836119b3565b9050607a811015612fe657612ff6565b612fef8161304f565b9150613002565b612fff8161308e565b91505b50919050565b6000600061301d613018846119b3565b6119b3565b9050607a81101561302d5761303d565b6130368161308e565b9150613049565b6130468161304f565b91505b50919050565b6000600061305c836119b3565b9050607b81101561306c5761307c565b613075816130d5565b9150613088565b61308581613114565b91505b50919050565b600060006130a361309e846119b3565b6119b3565b9050607b8110156130b3576130c3565b6130bc81613114565b91506130cf565b6130cc816130d5565b91505b50919050565b600060006130e2836119b3565b905060788110156130f257613102565b6130fb8161315b565b915061310e565b61310b8161319a565b91505b50919050565b60006000613129613124846119b3565b6119b3565b9050607881101561313957613149565b6131428161319a565b9150613155565b6131528161315b565b91505b50919050565b60006000613168836119b3565b9050607981101561317857613188565b613181816131e1565b9150613194565b61319181613220565b91505b50919050565b600060006131af6131aa846119b3565b6119b3565b905060798110156131bf576131cf565b6131c881613220565b91506131db565b6131d8816131e1565b91505b50919050565b600060006131ee836119b3565b9050607e8110156131fe5761320e565b61320781613267565b915061321a565b613217816132a6565b91505b50919050565b60006000613235613230846119b3565b6119b3565b9050607e81101561324557613255565b61324e816132a6565b9150613261565b61325e81613267565b91505b50919050565b60006000613274836119b3565b9050607f81101561328457613294565b61328d816132ed565b91506132a0565b61329d8161332c565b91505b50919050565b600060006132bb6132b6846119b3565b6119b3565b9050607f8110156132cb576132db565b6132d48161332c565b91506132e7565b6132e4816132ed565b91505b50919050565b600060006132fa836119b3565b9050607c81101561330a5761331a565b61331381613373565b9150613326565b613323816133b2565b91505b50919050565b6000600061334161333c846119b3565b6119b3565b9050607c81101561335157613361565b61335a816133b2565b915061336d565b61336a81613373565b91505b50919050565b60006000613380836119b3565b9050607d811015613390576133a0565b613399816133f9565b91506133ac565b6133a981613438565b91505b50919050565b600060006133c76133c2846119b3565b6119b3565b9050607d8110156133d7576133e7565b6133e081613438565b91506133f3565b6133f0816133f9565b91505b50919050565b60006000613406836119b3565b9050608281101561341657613426565b61341f8161347f565b9150613432565b61342f816134be565b91505b50919050565b6000600061344d613448846119b3565b6119b3565b9050608281101561345d5761346d565b613466816134be565b9150613479565b6134768161347f565b91505b50919050565b6000600061348c836119b3565b9050608381101561349c576134ac565b6134a581613505565b91506134b8565b6134b581613544565b91505b50919050565b600060006134d36134ce846119b3565b6119b3565b905060838110156134e3576134f3565b6134ec81613544565b91506134ff565b6134fc81613505565b91505b50919050565b60006000613512836119b3565b9050608081101561352257613532565b61352b8161358b565b915061353e565b61353b816135ca565b91505b50919050565b60006000613559613554846119b3565b6119b3565b9050608081101561356957613579565b613572816135ca565b9150613585565b6135828161358b565b91505b50919050565b60006000613598836119b3565b905060818110156135a8576135b8565b6135b181613611565b91506135c4565b6135c181613650565b91505b50919050565b600060006135df6135da846119b3565b6119b3565b905060818110156135ef576135ff565b6135f881613650565b915061360b565b61360881613611565b91505b50919050565b6000600061361e836119b3565b9050608681101561362e5761363e565b61363781613697565b915061364a565b613647816136d6565b91505b50919050565b60006000613665613660846119b3565b6119b3565b9050608681101561367557613685565b61367e816136d6565b9150613691565b61368e81613697565b91505b50919050565b600060006136a4836119b3565b905060878110156136b4576136c4565b6136bd8161371d565b91506136d0565b6136cd8161375c565b91505b50919050565b600060006136eb6136e6846119b3565b6119b3565b905060878110156136fb5761370b565b6137048161375c565b9150613717565b6137148161371d565b91505b50919050565b6000600061372a836119b3565b9050608481101561373a5761374a565b613743816137a3565b9150613756565b613753816137e2565b91505b50919050565b6000600061377161376c846119b3565b6119b3565b9050608481101561378157613791565b61378a816137e2565b915061379d565b61379a816137a3565b91505b50919050565b600060006137b0836119b3565b905060858110156137c0576137d0565b6137c981613829565b91506137dc565b6137d981613868565b91505b50919050565b600060006137f76137f2846119b3565b6119b3565b9050608581101561380757613817565b61381081613868565b9150613823565b61382081613829565b91505b50919050565b60006000613836836119b3565b9050608a81101561384657613856565b61384f816138af565b9150613862565b61385f816138ee565b91505b50919050565b6000600061387d613878846119b3565b6119b3565b9050608a81101561388d5761389d565b613896816138ee565b91506138a9565b6138a6816138af565b91505b50919050565b600060006138bc836119b3565b9050608b8110156138cc576138dc565b6138d581613935565b91506138e8565b6138e581613974565b91505b50919050565b600060006139036138fe846119b3565b6119b3565b9050608b81101561391357613923565b61391c81613974565b915061392f565b61392c81613935565b91505b50919050565b60006000613942836119b3565b9050608881101561395257613962565b61395b816139bb565b915061396e565b61396b816139fa565b91505b50919050565b60006000613989613984846119b3565b6119b3565b90506088811015613999576139a9565b6139a2816139fa565b91506139b5565b6139b2816139bb565b91505b50919050565b600060006139c8836119b3565b905060898110156139d8576139e8565b6139e181613a41565b91506139f4565b6139f181613a80565b91505b50919050565b60006000613a0f613a0a846119b3565b6119b3565b90506089811015613a1f57613a2f565b613a2881613a80565b9150613a3b565b613a3881613a41565b91505b50919050565b60006000613a4e836119b3565b9050608e811015613a5e57613a6e565b613a6781613ac7565b9150613a7a565b613a7781613b06565b91505b50919050565b60006000613a95613a90846119b3565b6119b3565b9050608e811015613aa557613ab5565b613aae81613b06565b9150613ac1565b613abe81613ac7565b91505b50919050565b60006000613ad4836119b3565b9050608f811015613ae457613af4565b613aed81613b4d565b9150613b00565b613afd81613b8c565b91505b50919050565b60006000613b1b613b16846119b3565b6119b3565b9050608f811015613b2b57613b3b565b613b3481613b8c565b9150613b47565b613b4481613b4d565b91505b50919050565b60006000613b5a836119b3565b9050608c811015613b6a57613b7a565b613b7381613bd3565b9150613b86565b613b8381613c12565b91505b50919050565b60006000613ba1613b9c846119b3565b6119b3565b9050608c811015613bb157613bc1565b613bba81613c12565b9150613bcd565b613bca81613bd3565b91505b50919050565b60006000613be0836119b3565b9050608d811015613bf057613c00565b613bf981613c59565b9150613c0c565b613c0981613c98565b91505b50919050565b60006000613c27613c22846119b3565b6119b3565b9050608d811015613c3757613c47565b613c4081613c98565b9150613c53565b613c5081613c59565b91505b50919050565b60006000613c66836119b3565b90506092811015613c7657613c86565b613c7f81613cdf565b9150613c92565b613c8f81613d1e565b91505b50919050565b60006000613cad613ca8846119b3565b6119b3565b90506092811015613cbd57613ccd565b613cc681613d1e565b9150613cd9565b613cd681613cdf565b91505b50919050565b60006000613cec836119b3565b90506093811015613cfc57613d0c565b613d0581613d65565b9150613d18565b613d1581613da4565b91505b50919050565b60006000613d33613d2e846119b3565b6119b3565b90506093811015613d4357613d53565b613d4c81613da4565b9150613d5f565b613d5c81613d65565b91505b50919050565b60006000613d72836119b3565b90506090811015613d8257613d92565b613d8b81613deb565b9150613d9e565b613d9b81613e2a565b91505b50919050565b60006000613db9613db4846119b3565b6119b3565b90506090811015613dc957613dd9565b613dd281613e2a565b9150613de5565b613de281613deb565b91505b50919050565b60006000613df8836119b3565b90506091811015613e0857613e18565b613e1181613e71565b9150613e24565b613e2181613eb0565b91505b50919050565b60006000613e3f613e3a846119b3565b6119b3565b90506091811015613e4f57613e5f565b613e5881613eb0565b9150613e6b565b613e6881613e71565b91505b50919050565b60006000613e7e836119b3565b90506096811015613e8e57613e9e565b613e9781613ef7565b9150613eaa565b613ea781613f36565b91505b50919050565b60006000613ec5613ec0846119b3565b6119b3565b90506096811015613ed557613ee5565b613ede81613f36565b9150613ef1565b613eee81613ef7565b91505b50919050565b60006000613f04836119b3565b90506097811015613f1457613f24565b613f1d81613f7d565b9150613f30565b613f2d81613fbc565b91505b50919050565b60006000613f4b613f46846119b3565b6119b3565b90506097811015613f5b57613f6b565b613f6481613fbc565b9150613f77565b613f7481613f7d565b91505b50919050565b60006000613f8a836119b3565b90506094811015613f9a57613faa565b613fa381614003565b9150613fb6565b613fb381614042565b91505b50919050565b60006000613fd1613fcc846119b3565b6119b3565b90506094811015613fe157613ff1565b613fea81614042565b9150613ffd565b613ffa81614003565b91505b50919050565b60006000614010836119b3565b9050609581101561402057614030565b61402981614089565b915061403c565b614039816140c8565b91505b50919050565b60006000614057614052846119b3565b6119b3565b9050609581101561406757614077565b614070816140c8565b9150614083565b61408081614089565b91505b50919050565b60006000614096836119b3565b9050609a8110156140a6576140b6565b6140af8161410f565b91506140c2565b6140bf8161414e565b91505b50919050565b600060006140dd6140d8846119b3565b6119b3565b9050609a8110156140ed576140fd565b6140f68161414e565b9150614109565b6141068161410f565b91505b50919050565b6000600061411c836119b3565b9050609b81101561412c5761413c565b61413581614195565b9150614148565b614145816141d4565b91505b50919050565b6000600061416361415e846119b3565b6119b3565b9050609b81101561417357614183565b61417c816141d4565b915061418f565b61418c81614195565b91505b50919050565b600060006141a2836119b3565b905060988110156141b2576141c2565b6141bb8161421b565b91506141ce565b6141cb8161425a565b91505b50919050565b600060006141e96141e4846119b3565b6119b3565b905060988110156141f957614209565b6142028161425a565b9150614215565b6142128161421b565b91505b50919050565b60006000614228836119b3565b9050609981101561423857614248565b614241816142a1565b9150614254565b614251816142e0565b91505b50919050565b6000600061426f61426a846119b3565b6119b3565b9050609981101561427f5761428f565b614288816142e0565b915061429b565b614298816142a1565b91505b50919050565b600060006142ae836119b3565b9050609e8110156142be576142ce565b6142c781614327565b91506142da565b6142d781614366565b91505b50919050565b600060006142f56142f0846119b3565b6119b3565b9050609e81101561430557614315565b61430e81614366565b9150614321565b61431e81614327565b91505b50919050565b60006000614334836119b3565b9050609f81101561434457614354565b61434d816143ad565b9150614360565b61435d816143ec565b91505b50919050565b6000600061437b614376846119b3565b6119b3565b9050609f81101561438b5761439b565b614394816143ec565b91506143a7565b6143a4816143ad565b91505b50919050565b600060006143ba836119b3565b9050609c8110156143ca576143da565b6143d381614433565b91506143e6565b6143e381614472565b91505b50919050565b600060006144016143fc846119b3565b6119b3565b9050609c81101561441157614421565b61441a81614472565b915061442d565b61442a81614433565b91505b50919050565b60006000614440836119b3565b9050609d81101561445057614460565b614459816144b9565b915061446c565b614469816144f8565b91505b50919050565b60006000614487614482846119b3565b6119b3565b9050609d811015614497576144a7565b6144a0816144f8565b91506144b3565b6144b0816144b9565b91505b50919050565b600060006144c6836119b3565b905060a28110156144d6576144e6565b6144df8161453f565b91506144f2565b6144ef8161457e565b91505b50919050565b6000600061450d614508846119b3565b6119b3565b905060a281101561451d5761452d565b6145268161457e565b9150614539565b6145368161453f565b91505b50919050565b6000600061454c836119b3565b905060a381101561455c5761456c565b614565816145c5565b9150614578565b61457581614604565b91505b50919050565b6000600061459361458e846119b3565b6119b3565b905060a38110156145a3576145b3565b6145ac81614604565b91506145bf565b6145bc816145c5565b91505b50919050565b600060006145d2836119b3565b905060a08110156145e2576145f2565b6145eb8161464b565b91506145fe565b6145fb8161468a565b91505b50919050565b60006000614619614614846119b3565b6119b3565b905060a081101561462957614639565b6146328161468a565b9150614645565b6146428161464b565b91505b50919050565b60006000614658836119b3565b905060a181101561466857614678565b614671816146d1565b9150614684565b61468181614710565b91505b50919050565b6000600061469f61469a846119b3565b6119b3565b905060a18110156146af576146bf565b6146b881614710565b91506146cb565b6146c8816146d1565b91505b50919050565b600060006146de836119b3565b905060a68110156146ee576146fe565b6146f781614757565b915061470a565b61470781614796565b91505b50919050565b60006000614725614720846119b3565b6119b3565b905060a681101561473557614745565b61473e81614796565b9150614751565b61474e81614757565b91505b50919050565b60006000614764836119b3565b905060a781101561477457614784565b61477d816147dd565b9150614790565b61478d8161481c565b91505b50919050565b600060006147ab6147a6846119b3565b6119b3565b905060a78110156147bb576147cb565b6147c48161481c565b91506147d7565b6147d4816147dd565b91505b50919050565b600060006147ea836119b3565b905060a48110156147fa5761480a565b61480381614863565b9150614816565b614813816148a2565b91505b50919050565b6000600061483161482c846119b3565b6119b3565b905060a481101561484157614851565b61484a816148a2565b915061485d565b61485a81614863565b91505b50919050565b60006000614870836119b3565b905060a581101561488057614890565b614889816148e9565b915061489c565b61489981614928565b91505b50919050565b600060006148b76148b2846119b3565b6119b3565b905060a58110156148c7576148d7565b6148d081614928565b91506148e3565b6148e0816148e9565b91505b50919050565b600060006148f6836119b3565b905060aa81101561490657614916565b61490f8161496f565b9150614922565b61491f816149ae565b91505b50919050565b6000600061493d614938846119b3565b6119b3565b905060aa81101561494d5761495d565b614956816149ae565b9150614969565b6149668161496f565b91505b50919050565b6000600061497c836119b3565b905060ab81101561498c5761499c565b614995816149f5565b91506149a8565b6149a581614a34565b91505b50919050565b600060006149c36149be846119b3565b6119b3565b905060ab8110156149d3576149e3565b6149dc81614a34565b91506149ef565b6149ec816149f5565b91505b50919050565b60006000614a02836119b3565b905060a8811015614a1257614a22565b614a1b81614a7b565b9150614a2e565b614a2b81614aba565b91505b50919050565b60006000614a49614a44846119b3565b6119b3565b905060a8811015614a5957614a69565b614a6281614aba565b9150614a75565b614a7281614a7b565b91505b50919050565b60006000614a88836119b3565b905060a9811015614a9857614aa8565b614aa181614b01565b9150614ab4565b614ab181614b40565b91505b50919050565b60006000614acf614aca846119b3565b6119b3565b905060a9811015614adf57614aef565b614ae881614b40565b9150614afb565b614af881614b01565b91505b50919050565b60006000614b0e836119b3565b905060ae811015614b1e57614b2e565b614b2781614b87565b9150614b3a565b614b3781614bc6565b91505b50919050565b60006000614b55614b50846119b3565b6119b3565b905060ae811015614b6557614b75565b614b6e81614bc6565b9150614b81565b614b7e81614b87565b91505b50919050565b60006000614b94836119b3565b905060af811015614ba457614bb4565b614bad81614c0d565b9150614bc0565b614bbd81614c4c565b91505b50919050565b60006000614bdb614bd6846119b3565b6119b3565b905060af811015614beb57614bfb565b614bf481614c4c565b9150614c07565b614c0481614c0d565b91505b50919050565b60006000614c1a836119b3565b905060ac811015614c2a57614c3a565b614c3381614c93565b9150614c46565b614c4381614cd2565b91505b50919050565b60006000614c61614c5c846119b3565b6119b3565b905060ac811015614c7157614c81565b614c7a81614cd2565b9150614c8d565b614c8a81614c93565b91505b50919050565b60006000614ca0836119b3565b905060ad811015614cb057614cc0565b614cb981614d19565b9150614ccc565b614cc981614d58565b91505b50919050565b60006000614ce7614ce2846119b3565b6119b3565b905060ad811015614cf757614d07565b614d0081614d58565b9150614d13565b614d1081614d19565b91505b50919050565b60006000614d26836119b3565b905060b2811015614d3657614d46565b614d3f816129c8565b9150614d52565b614d4f81614d9f565b91505b50919050565b60006000614d6d614d68846119b3565b6119b3565b905060b2811015614d7d57614d8d565b614d8681614d9f565b9150614d99565b614d96816129c8565b91505b50919050565b60006000614db4614daf846119b3565b6119b3565b905060b3811015614dc457614dd4565b614dcd816119fa565b9150614de0565b614ddd816119e8565b91505b5091905056", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "//" : "ManyFunctions.start(1)", + "data" : "0x95805DAD0000000000000000000000000000000000000000000000000000000000000001", + "gasPrice" : "100000000000000", + "gas" : "10000" + } + }, "ackermann31": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", From 5b48aad97dafd3602d10e617d962238355e00e9e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 16 Feb 2015 17:15:04 +0100 Subject: [PATCH 107/201] Removing events from Solidity Interface --- libsolidity/InterfaceHandler.cpp | 9 --------- test/SolidityInterface.cpp | 28 ++-------------------------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 7ecde8029..99a7db96e 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -108,16 +108,7 @@ unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition ret.pop_back(); ret += "{}"; } - for (auto const& it: _contractDef.getInterfaceEvents()) - { - std::string params; - for (auto const& p: it->getParameters()) - params += (params.empty() ? "(" : ",") + p->getType()->toString() + (p->isIndexed() ? " indexed " : " ") + p->getName(); - if (!params.empty()) - params += ")"; - ret += "event " + it->getName() + params + ";"; - } return unique_ptr(new string(ret + "}")); } diff --git a/test/SolidityInterface.cpp b/test/SolidityInterface.cpp index 78de2356a..a73c118bb 100644 --- a/test/SolidityInterface.cpp +++ b/test/SolidityInterface.cpp @@ -111,24 +111,6 @@ BOOST_AUTO_TEST_CASE(exclude_fallback_function) BOOST_CHECK_EQUAL(getSourcePart(contract), "contract test{}"); } -BOOST_AUTO_TEST_CASE(event) -{ - ContractDefinition const& contract = checkInterface( - "contract test { event Event; }"); - BOOST_REQUIRE_EQUAL(1, contract.getEvents().size()); - BOOST_CHECK_EQUAL(getSourcePart(*contract.getEvents().front()), - "event Event;"); -} - -BOOST_AUTO_TEST_CASE(event_arguments) -{ - ContractDefinition const& contract = checkInterface( - "contract test { event Event(uint a, uint indexed b); }"); - BOOST_REQUIRE_EQUAL(1, contract.getEvents().size()); - BOOST_CHECK_EQUAL(getSourcePart(*contract.getEvents().front()), - "event Event(uint256 a,uint256 indexed b);"); -} - BOOST_AUTO_TEST_CASE(events) { char const* sourceCode = "contract test {\n" @@ -137,10 +119,8 @@ BOOST_AUTO_TEST_CASE(events) " event e2(); \n" "}\n"; ContractDefinition const& contract = checkInterface(sourceCode); - set expectation({"event e1(uint256 b,address indexed c);", "event e2;"}); - BOOST_REQUIRE_EQUAL(2, contract.getEvents().size()); - BOOST_CHECK(expectation == set({getSourcePart(*contract.getEvents().at(0)), - getSourcePart(*contract.getEvents().at(1))})); + // events should not appear in the Solidity Interface + BOOST_REQUIRE_EQUAL(0, contract.getEvents().size()); } BOOST_AUTO_TEST_CASE(inheritance) @@ -155,12 +135,8 @@ BOOST_AUTO_TEST_CASE(inheritance) " event derivedEvent(uint indexed evtArgDerived); \n" " }"; ContractDefinition const& contract = checkInterface(sourceCode); - set expectedEvents({"event derivedEvent(uint256 indexed evtArgDerived);", - "event baseEvent(string32 indexed evtArgBase);"}); set expectedFunctions({"function baseFunction(uint256 p)returns(uint256 i){}", "function derivedFunction(string32 p)returns(string32 i){}"}); - BOOST_CHECK(expectedEvents == set({getSourcePart(*contract.getEvents().at(0)), - getSourcePart(*contract.getEvents().at(1))})); BOOST_REQUIRE_EQUAL(2, contract.getDefinedFunctions().size()); BOOST_CHECK(expectedFunctions == set({getSourcePart(*contract.getDefinedFunctions().at(0)), getSourcePart(*contract.getDefinedFunctions().at(1))})); From b1077bfd297fd5aa4579865347e5c8e373b833bf Mon Sep 17 00:00:00 2001 From: winsvega Date: Mon, 16 Feb 2015 20:04:11 +0300 Subject: [PATCH 108/201] 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 30d129a17c0dfc5ab9e698afb5a52beb0868d6db Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Mon, 16 Feb 2015 18:03:40 +0100 Subject: [PATCH 109/201] added shh_getMessages, fixed #899 --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 23 +++++++++++++++++++++ libweb3jsonrpc/WebThreeStubServerBase.h | 1 + libweb3jsonrpc/abstractwebthreestubserver.h | 6 ++++++ libweb3jsonrpc/spec.json | 3 ++- test/webthreestubclient.h | 10 +++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 27b8268da..f9f609c1b 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -613,6 +613,29 @@ Json::Value WebThreeStubServerBase::shh_changed(int _id) return ret; } +Json::Value WebThreeStubServerBase::shh_getMessages(int _id) +{ + Json::Value ret(Json::arrayValue); + auto pub = m_shhWatches[_id]; + if (!pub || m_ids.count(pub)) + for (h256 const& h: face()->watchMessages(_id)) + { + auto e = face()->envelope(h); + shh::Message m; + if (pub) + { + cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here."; + m = e.open(face()->fullTopic(_id), m_ids[pub]); + } + else + m = e.open(face()->fullTopic(_id)); + if (!m) + continue; + ret.append(toJson(h, e, m)); + } + return ret; +} + int WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) { auto w = toWatch(_json); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 005ac4130..578acf9a9 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -113,6 +113,7 @@ public: virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who); virtual Json::Value shh_changed(int _id); + virtual Json::Value shh_getMessages(int _id); virtual bool shh_haveIdentity(std::string const& _id); virtual int shh_newFilter(Json::Value const& _json); virtual std::string shh_newGroup(std::string const& _id, std::string const& _who); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 5bade41f6..98236bb68 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -63,6 +63,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("shh_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_newFilterI); this->bindAndAddMethod(jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI); this->bindAndAddMethod(jsonrpc::Procedure("shh_changed", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_changedI); + this->bindAndAddMethod(jsonrpc::Procedure("shh_getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::shh_getMessagesI); } inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response) @@ -281,6 +282,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServershh_changed(request[0u].asInt()); } + inline virtual void shh_getMessagesI(const Json::Value &request, Json::Value &response) + { + response = this->shh_getMessages(request[0u].asInt()); + } virtual std::string web3_sha3(const std::string& param1) = 0; virtual std::string eth_coinbase() = 0; virtual bool eth_setCoinbase(const std::string& param1) = 0; @@ -332,6 +337,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("shh_getMessages",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } }; #endif //JSONRPC_CPP_STUB_WEBTHREESTUBCLIENT_H_ From 0185ac5a0d4609732410d5962a2bd7ad867f90c3 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 14 Feb 2015 00:43:02 +0100 Subject: [PATCH 110/201] "external" visibility specifier. --- libsolidity/AST.h | 7 ++-- libsolidity/DeclarationContainer.cpp | 13 ++++--- libsolidity/DeclarationContainer.h | 6 +++- libsolidity/NameAndTypeResolver.cpp | 9 ++--- libsolidity/Parser.cpp | 4 ++- libsolidity/Token.h | 4 ++- libsolidity/Types.cpp | 7 ++-- test/SolidityNameAndTypeResolution.cpp | 50 ++++++++++++++++++++++++++ test/SolidityParser.cpp | 18 ++++++++++ 9 files changed, 102 insertions(+), 16 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 51d8031a3..c40e24d1d 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -133,7 +133,8 @@ class Declaration: public ASTNode { public: enum class LValueType { None, Local, Storage }; - enum class Visibility { Default, Public, Protected, Private }; + /// Visibility ordered from restricted to unrestricted. + enum class Visibility { Default, Private, Protected, Public, External }; Declaration(Location const& _location, ASTPointer const& _name, Visibility _visibility = Visibility::Default): @@ -142,7 +143,9 @@ public: /// @returns the declared name. ASTString const& getName() const { return *m_name; } Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } - bool isPublic() const { return getVisibility() == Visibility::Public; } + bool isPublic() const { return getVisibility() >= Visibility::Public; } + bool isVisibleInContract() const { return getVisibility() != Visibility::External; } + bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Protected; } /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/DeclarationContainer.cpp index 2e810a4cf..2594d4281 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/libsolidity/DeclarationContainer.cpp @@ -28,14 +28,19 @@ namespace dev namespace solidity { -bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _update) +bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update) { - if (_declaration.getName().empty()) + ASTString const& name(_declaration.getName()); + if (name.empty()) return true; - if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end()) + if (!_update && (m_declarations.count(name) || m_invisibleDeclarations.count(name))) return false; - m_declarations[_declaration.getName()] = &_declaration; + + if (_invisible) + m_invisibleDeclarations.insert(name); + else + m_declarations[name] = &_declaration; return true; } diff --git a/libsolidity/DeclarationContainer.h b/libsolidity/DeclarationContainer.h index 1216fcef2..f70881f5b 100644 --- a/libsolidity/DeclarationContainer.h +++ b/libsolidity/DeclarationContainer.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include @@ -43,8 +44,10 @@ public: DeclarationContainer const* _enclosingContainer = nullptr): m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {} /// Registers the declaration in the scope unless its name is already declared or the name is empty. + /// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName + /// @param _update if true, replaces a potential declaration that is already present /// @returns false if the name was already declared. - bool registerDeclaration(Declaration const& _declaration, bool _update = false); + bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false); Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } std::map const& getDeclarations() const { return m_declarations; } @@ -53,6 +56,7 @@ private: Declaration const* m_enclosingDeclaration; DeclarationContainer const* m_enclosingContainer; std::map m_declarations; + std::set m_invisibleDeclarations; }; } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index dbe5693a8..ea70b65b4 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -86,7 +86,7 @@ void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract) void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration) { - m_scopes[nullptr].registerDeclaration(_declaration, true); + m_scopes[nullptr].registerDeclaration(_declaration, false, true); solAssert(_declaration.getScope() == nullptr, "Updated declaration outside global scope."); } @@ -110,8 +110,9 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) for (auto const& nameAndDeclaration: iterator->second.getDeclarations()) { Declaration const* declaration = nameAndDeclaration.second; - // Import if it was declared in the base and is not the constructor - if (declaration->getScope() == &_base && declaration->getName() != _base.getName()) + // Import if it was declared in the base, is not the constructor and is visible in derived classes + if (declaration->getScope() == &_base && declaration->getName() != _base.getName() && + declaration->isVisibleInDerivedContracts()) m_currentScope->registerDeclaration(*declaration); } } @@ -308,7 +309,7 @@ void DeclarationRegistrationHelper::closeCurrentScope() void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - if (!m_scopes[m_currentScope].registerDeclaration(_declaration)) + if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract())) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); //@todo the exception should also contain the location of the first declaration diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index c96593f64..cf57ca50e 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -190,6 +190,8 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) visibility = Declaration::Visibility::Protected; else if (_token == Token::Private) visibility = Declaration::Visibility::Private; + else if (_token == Token::External) + visibility = Declaration::Visibility::External; else solAssert(false, "Invalid visibility specifier."); m_scanner->next(); @@ -306,7 +308,7 @@ ASTPointer Parser::parseVariableDeclaration(VarDeclParserOp ASTPointer identifier; Token::Value token = m_scanner->getCurrentToken(); Declaration::Visibility visibility(Declaration::Visibility::Default); - if (_options.isStateVariable && Token::isVisibilitySpecifier(token)) + if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) visibility = parseVisibilitySpecifier(token); if (_options.allowIndexed && token == Token::Indexed) { diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 3e599a6ee..7bf8a7ef0 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -150,6 +150,7 @@ namespace solidity K(Do, "do", 0) \ K(Else, "else", 0) \ K(Event, "event", 0) \ + K(External, "external", 0) \ K(Is, "is", 0) \ K(Indexed, "indexed", 0) \ K(For, "for", 0) \ @@ -378,7 +379,8 @@ public: static bool isUnaryOp(Value op) { return (Not <= op && op <= Delete) || op == Add || op == Sub; } 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 op == Public || op == Private || op == Protected; } + static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } + static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; } 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/Types.cpp b/libsolidity/Types.cpp index 5d753645c..99515a3ac 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -572,7 +572,8 @@ MemberList const& ContractType::getMembers() const { 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))); } else @@ -957,10 +958,10 @@ MemberList const& TypeType::getMembers() const ContractDefinition const& contract = dynamic_cast(*m_actualType).getContractDefinition(); vector currentBases = m_currentContract->getLinearizedBaseContracts(); if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end()) - // We are accessing the type of a base contract, so add all public and private + // We are accessing the type of a base contract, so add all public and protected // functions. Note that this does not add inherited functions on purpose. for (ASTPointer const& f: contract.getDefinedFunctions()) - if (!f->isConstructor() && !f->getName().empty()) + if (!f->isConstructor() && !f->getName().empty() && f->isVisibleInDerivedContracts()) members[f->getName()] = make_shared(*f); } else if (m_actualType->getCategory() == Category::Enum) diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index d6e4ed516..f30de96ce 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1083,6 +1083,56 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values) BOOST_CHECK_THROW(parseTextAndResolveNames(text), DeclarationError); } +BOOST_AUTO_TEST_CASE(private_visibility) +{ + char const* sourceCode = R"( + contract base { + function f() private {} + } + contract derived is base { + function g() { f(); } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError); +} + +BOOST_AUTO_TEST_CASE(private_visibility_via_explicit_base_access) +{ + char const* sourceCode = R"( + contract base { + function f() private {} + } + contract derived is base { + function g() { base.f(); } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(external_visibility) +{ + char const* sourceCode = R"( + contract c { + function f() external {} + function g() { f(); } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), DeclarationError); +} + +BOOST_AUTO_TEST_CASE(external_base_visibility) +{ + char const* sourceCode = R"( + contract base { + function f() external {} + } + contract derived is base { + function g() { base.f(); } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index af82f612a..5f9064e0c 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -735,6 +735,24 @@ BOOST_AUTO_TEST_CASE(malformed_enum_declaration) BOOST_CHECK_THROW(parseText(text), ParserError); } +BOOST_AUTO_TEST_CASE(external_function) +{ + char const* text = R"( + contract c { + function x() external {} + })"; + BOOST_CHECK_NO_THROW(parseTextExplainError(text)); +} + +BOOST_AUTO_TEST_CASE(external_variable) +{ + char const* text = R"( + contract c { + uint external x; + })"; + BOOST_CHECK_THROW(parseText(text), ParserError); +} + BOOST_AUTO_TEST_SUITE_END() } From ed0384b75922cd4834bc1a77dd5caf81c03d6dbd Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 14 Feb 2015 01:22:44 +0100 Subject: [PATCH 111/201] No write access to parameters of external functions. --- libsolidity/AST.cpp | 28 ++++++++++++++++-------- libsolidity/AST.h | 16 ++++++-------- libsolidity/ASTJsonConverter.cpp | 17 ++++++--------- libsolidity/Compiler.cpp | 23 ++++++++++++++------ test/SolidityEndToEndTest.cpp | 15 +++++++++++++ test/SolidityNameAndTypeResolution.cpp | 30 ++++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 34 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0dbad433f..0fafd2d12 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -288,12 +288,23 @@ string FunctionDefinition::getCanonicalSignature() const return FunctionType(*this).getCanonicalSignature(getName()); } -Declaration::LValueType VariableDeclaration::getLValueType() const +bool VariableDeclaration::isLValue() const { - if (dynamic_cast(getScope()) || dynamic_cast(getScope())) - return Declaration::LValueType::Local; - else - return Declaration::LValueType::Storage; + if (auto const* function = dynamic_cast(getScope())) + if (function->getVisibility() == Declaration::Visibility::External && isFunctionParameter()) + return false; + return true; +} + +bool VariableDeclaration::isFunctionParameter() const +{ + auto const* function = dynamic_cast(getScope()); + if (!function) + return false; + for (auto const& variable: function->getParameters()) + if (variable.get() == this) + return true; + return false; } TypePointer ModifierDefinition::getType(ContractDefinition const*) const @@ -586,8 +597,7 @@ void MemberAccess::checkTypeRequirements() if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not " "visible in " + type.toString())); - //@todo later, this will not always be STORAGE - m_lvalue = type.getCategory() == Type::Category::Struct ? Declaration::LValueType::Storage : Declaration::LValueType::None; + m_isLValue = (type.getCategory() == Type::Category::Struct); } void IndexAccess::checkTypeRequirements() @@ -599,14 +609,14 @@ void IndexAccess::checkTypeRequirements() MappingType const& type = dynamic_cast(*m_base->getType()); m_index->expectType(*type.getKeyType()); m_type = type.getValueType(); - m_lvalue = Declaration::LValueType::Storage; + m_isLValue = true; } void Identifier::checkTypeRequirements() { solAssert(m_referencedDeclaration, "Identifier not resolved."); - m_lvalue = m_referencedDeclaration->getLValueType(); + m_isLValue = m_referencedDeclaration->isLValue(); m_type = m_referencedDeclaration->getType(m_currentContract); if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined.")); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index c40e24d1d..af45934f7 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -132,7 +132,6 @@ private: class Declaration: public ASTNode { public: - enum class LValueType { None, Local, Storage }; /// Visibility ordered from restricted to unrestricted. enum class Visibility { Default, Private, Protected, Public, External }; @@ -156,8 +155,7 @@ public: /// The current contract has to be given since this context can change the type, especially of /// contract types. virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0; - /// @returns the lvalue type of expressions referencing this declaration - virtual LValueType getLValueType() const { return LValueType::None; } + virtual bool isLValue() const { return false; } protected: virtual Visibility getDefaultVisibility() const { return Visibility::Public; } @@ -448,8 +446,9 @@ public: TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; } void setType(std::shared_ptr const& _type) { m_type = _type; } - virtual LValueType getLValueType() const override; + virtual bool isLValue() const override; bool isLocalVariable() const { return !!dynamic_cast(getScope()); } + bool isFunctionParameter() const; bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } @@ -887,8 +886,7 @@ public: virtual void checkTypeRequirements() = 0; std::shared_ptr const& getType() const { return m_type; } - bool isLValue() const { return m_lvalue != Declaration::LValueType::None; } - bool isLocalLValue() const { return m_lvalue == Declaration::LValueType::Local; } + bool isLValue() const { return m_isLValue; } /// Helper function, infer the type via @ref checkTypeRequirements and then check that it /// is implicitly convertible to @a _expectedType. If not, throw exception. @@ -903,9 +901,9 @@ public: protected: //! Inferred type of the expression, only filled after a call to checkTypeRequirements(). std::shared_ptr m_type; - //! If this expression is an lvalue (i.e. something that can be assigned to) and is stored - //! locally or in storage. This is set during calls to @a checkTypeRequirements() - Declaration::LValueType m_lvalue = Declaration::LValueType::None; + //! If this expression is an lvalue (i.e. something that can be assigned to). + //! This is set during calls to @a checkTypeRequirements() + bool m_isLValue = false; //! Whether the outer expression requested the address (true) or the value (false) of this expression. bool m_lvalueRequested = false; }; diff --git a/libsolidity/ASTJsonConverter.cpp b/libsolidity/ASTJsonConverter.cpp index a216a59ac..04feafe2f 100644 --- a/libsolidity/ASTJsonConverter.cpp +++ b/libsolidity/ASTJsonConverter.cpp @@ -118,11 +118,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) bool ASTJsonConverter::visit(VariableDeclaration const& _node) { - bool isLocalVariable = (_node.getLValueType() == VariableDeclaration::LValueType::Local); - addJsonNode("VariableDeclaration", - { make_pair("name", _node.getName()), - make_pair("local", boost::lexical_cast(isLocalVariable))}, - true); + addJsonNode("VariableDeclaration", { make_pair("name", _node.getName()) }, true); return true; } @@ -216,11 +212,12 @@ bool ASTJsonConverter::visit(ExpressionStatement const&) bool ASTJsonConverter::visit(Expression const& _node) { - addJsonNode("Expression", - { make_pair("type", getType(_node)), - make_pair("lvalue", boost::lexical_cast(_node.isLValue())), - make_pair("local_lvalue", boost::lexical_cast(_node.isLocalLValue())) }, - true); + addJsonNode( + "Expression", + { make_pair("type", getType(_node)), + make_pair("lvalue", boost::lexical_cast(_node.isLValue())) }, + true + ); return true; } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index dad79bb06..4dbcbbfe6 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -255,12 +255,22 @@ bool Compiler::visit(FunctionDefinition const& _function) // stack upon entry: [return address] [arg0] [arg1] ... [argn] // reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp] - unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters()); - m_context.adjustStackOffset(parametersSize); - for (ASTPointer const& variable: _function.getParameters()) + if (_function.getVisibility() != Declaration::Visibility::External) { - m_context.addVariable(*variable, parametersSize); - parametersSize -= variable->getType()->getSizeOnStack(); + unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters()); + m_context.adjustStackOffset(parametersSize); + for (ASTPointer const& variable: _function.getParameters()) + { + m_context.addVariable(*variable, parametersSize); + parametersSize -= variable->getType()->getSizeOnStack(); + } + } + else + { + unsigned calldataPos = CompilerUtils::dataStartOffset; + // calldatapos is _always_ dynamic. + for (ASTPointer const& variable: _function.getParameters()) + m_context.addCalldataVariable(*variable, calldataPos); } for (ASTPointer const& variable: _function.getReturnParameters()) m_context.addAndInitializeVariable(*variable); @@ -277,7 +287,8 @@ bool Compiler::visit(FunctionDefinition const& _function) // Note that the fact that the return arguments are of increasing index is vital for this // algorithm to work. - unsigned const c_argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters()); + unsigned const c_argumentsSize = (_function.getVisibility() == Declaration::Visibility::External + ? 0 : CompilerUtils::getSizeOnStack(_function.getParameters())); unsigned const c_returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters()); unsigned const c_localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables()); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 0325c4c6a..9899af29f 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2534,6 +2534,21 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints) BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); } +BOOST_AUTO_TEST_CASE(external_function) +{ + char const* sourceCode = R"( + contract c { + function f(uint a) returns (uint) { return a; } + function test(uint a, uint b) external returns (uint r_a, uint r_b) { + r_a = f(a + 7); + r_b = b; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", 2, 3) == encodeArgs(2, 3+7)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index f30de96ce..6b337ac74 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1133,6 +1133,36 @@ BOOST_AUTO_TEST_CASE(external_base_visibility) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(external_argument_assign) +{ + char const* sourceCode = R"( + contract c { + function f(uint a) external { a = 1; } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(external_argument_increment) +{ + char const* sourceCode = R"( + contract c { + function f(uint a) external { a++; } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(external_argument_delete) +{ + char const* sourceCode = R"( + contract c { + function f(uint a) external { delete a; } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 9ba105a763764a2d956653fc99c93bde1a57a435 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 15 Feb 2015 00:11:51 +0100 Subject: [PATCH 112/201] Move code to loadFromMemory. --- libsolidity/Compiler.cpp | 36 ++++++------------------ libsolidity/CompilerUtils.cpp | 45 +++++++++++++++--------------- libsolidity/CompilerUtils.h | 9 +++--- libsolidity/ExpressionCompiler.cpp | 7 ++--- 4 files changed, 38 insertions(+), 59 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 4dbcbbfe6..e14935873 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -147,7 +147,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) // retrieve the function signature hash from the calldata if (!interfaceFunctions.empty()) - CompilerUtils(m_context).loadFromMemory(0, 4, false, true); + CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true); // stack now is: 1 0 for (auto const& it: interfaceFunctions) @@ -182,18 +182,10 @@ unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, b { // We do not check the calldata size, everything is zero-padded. unsigned dataOffset = CompilerUtils::dataStartOffset; // the 4 bytes of the function hash signature - //@todo this can be done more efficiently, saving some CALLDATALOAD calls + + bool const c_padToWords = true; for (TypePointer const& type: _typeParameters) - { - unsigned const c_numBytes = type->getCalldataEncodedSize(); - if (c_numBytes > 32) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_comment("Type " + type->toString() + " not yet supported.")); - bool const c_leftAligned = type->getCategory() == Type::Category::String; - bool const c_padToWords = true; - dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, c_numBytes, c_leftAligned, - !_fromMemory, c_padToWords); - } + dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, *type, !_fromMemory, c_padToWords); return dataOffset; } @@ -255,22 +247,12 @@ bool Compiler::visit(FunctionDefinition const& _function) // stack upon entry: [return address] [arg0] [arg1] ... [argn] // reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp] - if (_function.getVisibility() != Declaration::Visibility::External) - { - unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters()); - m_context.adjustStackOffset(parametersSize); - for (ASTPointer const& variable: _function.getParameters()) - { - m_context.addVariable(*variable, parametersSize); - parametersSize -= variable->getType()->getSizeOnStack(); - } - } - else + unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters()); + m_context.adjustStackOffset(parametersSize); + for (ASTPointer const& variable: _function.getParameters()) { - unsigned calldataPos = CompilerUtils::dataStartOffset; - // calldatapos is _always_ dynamic. - for (ASTPointer const& variable: _function.getParameters()) - m_context.addCalldataVariable(*variable, calldataPos); + m_context.addVariable(*variable, parametersSize); + parametersSize -= variable->getType()->getSizeOnStack(); } for (ASTPointer const& variable: _function.getReturnParameters()) m_context.addAndInitializeVariable(*variable); diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index dda1736d6..6f99dc7c2 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -33,33 +33,34 @@ namespace solidity const unsigned int CompilerUtils::dataStartOffset = 4; -unsigned CompilerUtils::loadFromMemory(unsigned _offset, unsigned _bytes, bool _leftAligned, - bool _fromCalldata, bool _padToWordBoundaries) +unsigned CompilerUtils::loadFromMemory(unsigned _offset, Type const& _type, + bool _fromCalldata, bool _padToWordBoundaries) { - if (_bytes == 0) - { + solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically load dynamic type."); + unsigned _encodedSize = _type.getCalldataEncodedSize(); + unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize; + bool leftAligned = _type.getCategory() == Type::Category::String; + if (numBytes == 0) m_context << u256(0); - return 0; - } - eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD; - solAssert(_bytes <= 32, "Memory load of more than 32 bytes requested."); - if (_bytes == 32 || _padToWordBoundaries) - { - m_context << u256(_offset) << load; - return 32; - } else { - // load data and add leading or trailing zeros by dividing/multiplying depending on alignment - u256 shiftFactor = u256(1) << ((32 - _bytes) * 8); - m_context << shiftFactor; - if (_leftAligned) - m_context << eth::Instruction::DUP1; - m_context << u256(_offset) << load << eth::Instruction::DIV; - if (_leftAligned) - m_context << eth::Instruction::MUL; - return _bytes; + eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD; + solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested."); + if (numBytes == 32) + m_context << u256(_offset) << load; + else + { + // load data and add leading or trailing zeros by dividing/multiplying depending on alignment + u256 shiftFactor = u256(1) << ((32 - numBytes) * 8); + m_context << shiftFactor; + if (leftAligned) + m_context << eth::Instruction::DUP1; + m_context << u256(_offset) << load << eth::Instruction::DIV; + if (leftAligned) + m_context << eth::Instruction::MUL; + } } + return numBytes; } unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries) diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index fe28ceadf..89973b6be 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -37,14 +37,13 @@ public: /// Loads data from memory to the stack. /// @param _offset offset in memory (or calldata) - /// @param _bytes number of bytes to load - /// @param _leftAligned if true, store left aligned on stack (otherwise right aligned) + /// @param _type data type to load /// @param _fromCalldata if true, load from calldata, not from memory /// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries /// @returns the number of bytes consumed in memory (can be different from _bytes if - /// _padToWordBoundaries is true) - unsigned loadFromMemory(unsigned _offset, unsigned _bytes = 32, bool _leftAligned = false, - bool _fromCalldata = false, bool _padToWordBoundaries = false); + /// _padToWordBoundaries is true) + unsigned loadFromMemory(unsigned _offset, Type const& _type = IntegerType(256), + bool _fromCalldata = false, bool _padToWordBoundaries = false); /// Stores data from stack in memory. /// @param _offset offset in memory /// @param _type type of the data on the stack diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 0f0e94f21..7128459a4 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -885,11 +885,8 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio m_context << eth::Instruction::POP; m_context << eth::Instruction::POP; // pop contract address - if (retSize > 0) - { - bool const c_leftAligned = firstType->getCategory() == Type::Category::String; - CompilerUtils(m_context).loadFromMemory(0, retSize, c_leftAligned, false, true); - } + if (firstType) + CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true); } void ExpressionCompiler::appendArgumentsCopyToMemory(vector> const& _arguments, From 9111abbc8a3e77f7a56fa914e3c2b8f7cf271467 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 15 Feb 2015 01:02:38 +0100 Subject: [PATCH 113/201] loadFromMemoryDynamic --- libsolidity/CompilerUtils.cpp | 63 ++++++++++++++++++++++------------- libsolidity/CompilerUtils.h | 9 +++-- test/SolidityCompiler.cpp | 10 +++--- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 6f99dc7c2..0a95c3adb 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -37,32 +37,22 @@ unsigned CompilerUtils::loadFromMemory(unsigned _offset, Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) { solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically load dynamic type."); - unsigned _encodedSize = _type.getCalldataEncodedSize(); - unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize; - bool leftAligned = _type.getCategory() == Type::Category::String; - if (numBytes == 0) - m_context << u256(0); - else - { - eth::Instruction load = _fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD; - solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested."); - if (numBytes == 32) - m_context << u256(_offset) << load; - else - { - // load data and add leading or trailing zeros by dividing/multiplying depending on alignment - u256 shiftFactor = u256(1) << ((32 - numBytes) * 8); - m_context << shiftFactor; - if (leftAligned) - m_context << eth::Instruction::DUP1; - m_context << u256(_offset) << load << eth::Instruction::DIV; - if (leftAligned) - m_context << eth::Instruction::MUL; - } - } - return numBytes; + m_context << u256(_offset); + return loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries); +} + +void CompilerUtils::loadFromMemoryDynamic(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) +{ + solAssert(_type.getCategory() != Type::Category::ByteArray, "Byte arrays not yet implemented."); + m_context << eth::Instruction::DUP1; + unsigned numBytes = loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries); + // update memory counter + for (unsigned i = 0; i < _type.getSizeOnStack(); ++i) + m_context << eth::swapInstruction(1 + i); + m_context << u256(numBytes) << eth::Instruction::ADD; } + unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries) { solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically store dynamic type."); @@ -121,6 +111,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); if (numBytes > 0) { + solAssert(_type.getSizeOnStack() == 1, "Memory store of types with stack size != 1 not implemented."); m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; m_context << u256(numBytes) << eth::Instruction::ADD; } @@ -290,6 +281,30 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType, } } +unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) +{ + unsigned _encodedSize = _type.getCalldataEncodedSize(); + unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize; + bool leftAligned = _type.getCategory() == Type::Category::String; + if (numBytes == 0) + m_context << eth::Instruction::POP << u256(0); + else + { + solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested."); + m_context << (_fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD); + if (numBytes != 32) + { + // add leading or trailing zeros by dividing/multiplying depending on alignment + u256 shiftFactor = u256(1) << ((32 - numBytes) * 8); + m_context << shiftFactor << eth::Instruction::SWAP1 << eth::Instruction::DIV; + if (leftAligned) + m_context << shiftFactor << eth::Instruction::MUL; + } + } + + return numBytes; +} + void CompilerUtils::clearByteArray(ByteArrayType const& _type) const { solAssert(_type.getLocation() == ByteArrayType::Location::Storage, ""); diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index 89973b6be..5369d3bf2 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -40,10 +40,13 @@ public: /// @param _type data type to load /// @param _fromCalldata if true, load from calldata, not from memory /// @param _padToWordBoundaries if true, assume the data is padded to word (32 byte) boundaries - /// @returns the number of bytes consumed in memory (can be different from _bytes if - /// _padToWordBoundaries is true) + /// @returns the number of bytes consumed in memory. unsigned loadFromMemory(unsigned _offset, Type const& _type = IntegerType(256), bool _fromCalldata = false, bool _padToWordBoundaries = false); + /// Dynamic version of @see loadFromMemory, expects the memory offset on the stack. + /// Stack pre: memory_offset + /// Stack post: value... (memory_offset+length) + void loadFromMemoryDynamic(Type const& _type, bool _fromCalldata = false, bool _padToWordBoundaries = true); /// Stores data from stack in memory. /// @param _offset offset in memory /// @param _type type of the data on the stack @@ -92,6 +95,8 @@ public: private: /// Prepares the given type for storing in memory by shifting it if necessary. unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const; + /// Loads type from memory assuming memory offset is on stack top. + unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries); /// Appends a loop that clears a sequence of storage slots (excluding end). /// Stack pre: end_ref start_ref /// Stack post: end_ref diff --git a/test/SolidityCompiler.cpp b/test/SolidityCompiler.cpp index 17d9a7c07..1369b038f 100644 --- a/test/SolidityCompiler.cpp +++ b/test/SolidityCompiler.cpp @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) "}\n"; bytes code = compileContract(sourceCode); - unsigned boilerplateSize = 69; + unsigned boilerplateSize = 70; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, // initialize local variable x byte(Instruction::PUSH1), 0x2, @@ -114,8 +114,8 @@ BOOST_AUTO_TEST_CASE(ifStatement) " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 56; - unsigned boilerplateSize = 69; + unsigned shift = 57; + unsigned boilerplateSize = 70; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), @@ -155,8 +155,8 @@ BOOST_AUTO_TEST_CASE(loops) " function f() { while(true){1;break;2;continue;3;return;4;} }" "}\n"; bytes code = compileContract(sourceCode); - unsigned shift = 56; - unsigned boilerplateSize = 69; + unsigned shift = 57; + unsigned boilerplateSize = 70; bytes expectation({byte(Instruction::JUMPDEST), byte(Instruction::JUMPDEST), byte(Instruction::PUSH1), 0x1, From cad718715bcfbe610be870787e85f5f68917409f Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 15 Feb 2015 02:00:33 +0100 Subject: [PATCH 114/201] Unpacking of dynamically sized arguments. --- libsolidity/Compiler.cpp | 35 ++++++++++++++++++++++++++++++----- libsolidity/Compiler.h | 4 ++-- libsolidity/Types.h | 3 +++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index e14935873..98c9ffaac 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -178,15 +178,40 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) } } -unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) +void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) { // We do not check the calldata size, everything is zero-padded. - unsigned dataOffset = CompilerUtils::dataStartOffset; // the 4 bytes of the function hash signature - + unsigned offset(CompilerUtils::dataStartOffset); bool const c_padToWords = true; + + unsigned dynamicParameterCount = 0; for (TypePointer const& type: _typeParameters) - dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, *type, !_fromMemory, c_padToWords); - return dataOffset; + if (type->isDynamicallySized()) + dynamicParameterCount++; + offset += dynamicParameterCount * 32; + unsigned currentDynamicParameter = 0; + for (TypePointer const& type: _typeParameters) + if (type->isDynamicallySized()) + { + // value on stack: [memory_offset] (only if we are already in dynamic mode) + if (currentDynamicParameter == 0) + // switch from static to dynamic + m_context << u256(offset); + CompilerUtils(m_context).loadFromMemory( + CompilerUtils::dataStartOffset + currentDynamicParameter * 32, + IntegerType(256), !_fromMemory, c_padToWords); + // store new memory pointer + m_context << eth::Instruction::DUP2 << eth::Instruction::DUP2 << eth::Instruction::ADD; + currentDynamicParameter++; + // value on stack: offset length next_memory_offset + } + else if (currentDynamicParameter == 0) + // we can still use static load + offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, c_padToWords); + else + CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, c_padToWords); + if (dynamicParameterCount > 0) + m_context << eth::Instruction::POP; } void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index b3eae5b17..5d5b6d47b 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -52,8 +52,8 @@ private: void appendConstructorCall(FunctionDefinition const& _constructor); void appendFunctionSelector(ContractDefinition const& _contract); /// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers. - /// From memory if @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes. - unsigned appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false); + /// From memory if @a _fromMemory is true, otherwise from call data. + void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false); void appendReturnValuePacker(TypePointers const& _typeParameters); void registerStateVariables(ContractDefinition const& _contract); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 3b4eee57f..90812f564 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -122,6 +122,8 @@ public: /// is not a simple big-endian encoding or the type cannot be stored in calldata. /// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes. virtual unsigned getCalldataEncodedSize() const { return 0; } + /// @returns true if the type is dynamically encoded in calldata + virtual bool isDynamicallySized() const { return false; } /// @returns number of bytes required to hold this value in storage. /// For dynamically "allocated" types, it returns the size of the statically allocated head, virtual u256 getStorageSize() const { return 1; } @@ -289,6 +291,7 @@ public: virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(const Type& _other) const override; + virtual bool isDynamicallySized() const { return true; } virtual unsigned getSizeOnStack() const override; virtual std::string toString() const override { return "bytes"; } virtual MemberList const& getMembers() const override { return s_byteArrayMemberList; } From bed225c9810b3ebecaa3540a4731e1bffa25b2f7 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 16 Feb 2015 17:33:13 +0100 Subject: [PATCH 115/201] Calldata byte arrays stored on the stack. --- libsolidity/AST.cpp | 9 ++++++++ libsolidity/Compiler.cpp | 17 +++++++++----- libsolidity/CompilerUtils.cpp | 34 +++++++++++++++++----------- libsolidity/ExpressionCompiler.cpp | 19 ++++++++++++---- libsolidity/Types.cpp | 11 +++++++-- libsolidity/Types.h | 4 ++++ test/SolidityEndToEndTest.cpp | 36 ++++++++++++++++++++++++++---- 7 files changed, 101 insertions(+), 29 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0fafd2d12..c6d8f5c58 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -274,6 +274,15 @@ 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.")); diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 98c9ffaac..14acc0113 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -193,17 +193,23 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool for (TypePointer const& type: _typeParameters) if (type->isDynamicallySized()) { - // value on stack: [memory_offset] (only if we are already in dynamic mode) + // value on stack: [calldata_offset] (only if we are already in dynamic mode) if (currentDynamicParameter == 0) // switch from static to dynamic m_context << u256(offset); + // retrieve length CompilerUtils(m_context).loadFromMemory( CompilerUtils::dataStartOffset + currentDynamicParameter * 32, IntegerType(256), !_fromMemory, c_padToWords); - // store new memory pointer - m_context << eth::Instruction::DUP2 << eth::Instruction::DUP2 << eth::Instruction::ADD; + // stack: offset length + // add 32-byte padding to copy of length + m_context << u256(32) << eth::Instruction::DUP1 << u256(31) + << eth::Instruction::DUP4 << eth::Instruction::ADD + << eth::Instruction::DIV << eth::Instruction::MUL; + // stack: offset length padded_length + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; currentDynamicParameter++; - // value on stack: offset length next_memory_offset + // stack: offset length next_calldata_offset } else if (currentDynamicParameter == 0) // we can still use static load @@ -294,8 +300,7 @@ bool Compiler::visit(FunctionDefinition const& _function) // Note that the fact that the return arguments are of increasing index is vital for this // algorithm to work. - unsigned const c_argumentsSize = (_function.getVisibility() == Declaration::Visibility::External - ? 0 : CompilerUtils::getSizeOnStack(_function.getParameters())); + unsigned const c_argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters()); unsigned const c_returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters()); unsigned const c_localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables()); diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 0a95c3adb..047bc6d62 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -70,9 +70,12 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound if (type.getLocation() == ByteArrayType::Location::CallData) { - m_context << eth::Instruction::CALLDATASIZE << u256(0) << eth::Instruction::DUP3 - << eth::Instruction::CALLDATACOPY - << eth::Instruction::CALLDATASIZE << eth::Instruction::ADD; + // stack: target source_offset source_len + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5 + // stack: target source_offset source_len source_len source_offset target + << eth::Instruction::CALLDATACOPY + << eth::Instruction::DUP3 << eth::Instruction::ADD + << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; } else { @@ -171,29 +174,32 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType, { case ByteArrayType::Location::CallData: { - // @todo this does not take length into account. It also assumes that after "CALLDATALENGTH" we only have zeros. + // This also assumes that after "length" we only have zeros, i.e. it cannot be used to + // slice a byte array from calldata. + + // stack: source_offset source_len target_ref // fetch old length and convert to words m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; m_context << u256(31) << eth::Instruction::ADD << u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV; - // stack here: target_ref target_length_words + // stack here: source_offset source_len target_ref target_length_words // actual array data is stored at SHA3(storage_offset) m_context << eth::Instruction::DUP2; CompilerUtils(m_context).computeHashStatic(); // compute target_data_end m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD << eth::Instruction::SWAP1; - // stack here: target_ref target_data_end target_data_ref + // stack here: source_offset source_len target_ref target_data_end target_data_ref // store length (in bytes) - m_context << eth::Instruction::CALLDATASIZE; - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP5 << eth::Instruction::SSTORE; + m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5 + << eth::Instruction::SSTORE; // jump to end if length is zero m_context << eth::Instruction::ISZERO; eth::AssemblyItem copyLoopEnd = m_context.newTag(); m_context.appendConditionalJumpTo(copyLoopEnd); // store start offset - m_context << u256(0); - // stack now: target_ref target_data_end target_data_ref calldata_offset + m_context << eth::Instruction::DUP5; + // stack now: source_offset source_len target_ref target_data_end target_data_ref calldata_offset eth::AssemblyItem copyLoopStart = m_context.newTag(); m_context << copyLoopStart // copy from calldata and store @@ -204,16 +210,18 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType, // increment calldata_offset by 32 << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD // check for loop condition - << eth::Instruction::DUP1 << eth::Instruction::CALLDATASIZE << eth::Instruction::GT; + << eth::Instruction::DUP1 << eth::Instruction::DUP6 << eth::Instruction::GT; m_context.appendConditionalJumpTo(copyLoopStart); m_context << eth::Instruction::POP; m_context << copyLoopEnd; // now clear leftover bytes of the old value - // stack now: target_ref target_data_end target_data_ref + // stack now: source_offset source_len target_ref target_data_end target_data_ref clearStorageLoop(); + // stack now: source_offset source_len target_ref target_data_end - m_context << eth::Instruction::POP; + m_context << eth::Instruction::POP << eth::Instruction::SWAP2 + << eth::Instruction::POP << eth::Instruction::POP; break; } case ByteArrayType::Location::Storage: diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 7128459a4..3bf1c8c93 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -475,9 +475,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) else if (member == "gasprice") m_context << eth::Instruction::GASPRICE; else if (member == "data") - { - // nothing to store on the stack - } + m_context << u256(0) << eth::Instruction::CALLDATASIZE; else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member.")); break; @@ -510,6 +508,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) m_context << m_context.getFunctionEntryLabel(*function).pushTag(); return; } + solAssert(false, "Function not found in member access."); } else if (auto enumType = dynamic_cast(type.getActualType().get())) m_context << enumType->getMemberValue(_memberAccess.getMemberName()); @@ -518,7 +517,19 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) case Type::Category::ByteArray: { solAssert(member == "length", "Illegal bytearray member."); - m_context << eth::Instruction::SLOAD; + auto const& type = dynamic_cast(*_memberAccess.getExpression().getType()); + switch (type.getLocation()) + { + case ByteArrayType::Location::CallData: + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + break; + case ByteArrayType::Location::Storage: + m_context << eth::Instruction::SLOAD; + break; + default: + solAssert(false, "Unsupported byte array location."); + break; + } break; } default: diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 99515a3ac..6149f34f8 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -540,12 +540,19 @@ bool ByteArrayType::operator==(Type const& _other) const unsigned ByteArrayType::getSizeOnStack() const { if (m_location == Location::CallData) - return 0; + // offset, length (stack top) + return 2; else + // offset return 1; } -const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared(256)}}); +shared_ptr ByteArrayType::copyForLocation(ByteArrayType::Location _location) const +{ + return make_shared(_location); +} + +const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared(256)}}); bool ContractType::operator==(Type const& _other) const { diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 90812f564..b66857f0c 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -298,6 +298,10 @@ public: Location getLocation() const { return m_location; } + /// @returns a copy of this type with location changed to @a _location + /// @todo this might move as far up as Type later + std::shared_ptr copyForLocation(Location _location) const; + private: Location m_location; static const MemberList s_byteArrayMemberList; diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 9899af29f..103b11269 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2283,9 +2283,9 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory) } )"; compileAndRun(sourceCode); - bytes calldata = bytes(61, 0x22) + bytes(12, 0x12); - sendMessage(calldata, false); - BOOST_CHECK(m_output == encodeArgs(dev::sha3(bytes{'a', 'b', 'c'} + calldata))); + bytes calldata1 = bytes(61, 0x22) + bytes(12, 0x12); + sendMessage(calldata1, false); + BOOST_CHECK(m_output == encodeArgs(dev::sha3(bytes{'a', 'b', 'c'} + calldata1))); } BOOST_AUTO_TEST_CASE(call_forward_bytes) @@ -2546,7 +2546,35 @@ BOOST_AUTO_TEST_CASE(external_function) } )"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("test(uint256,uint256)", 2, 3) == encodeArgs(2, 3+7)); + BOOST_CHECK(callContractFunction("test(uint256,uint256)", 2, 3) == encodeArgs(2+7, 3)); +} + +BOOST_AUTO_TEST_CASE(bytes_in_arguments) +{ + char const* sourceCode = R"( + contract c { + uint result; + function f(uint a, uint b) { result += a + b; } + function g(uint a) { result *= a; } + function test(uint a, bytes data1, bytes data2, uint b) external returns (uint r_a, uint r, uint r_b, uint l) { + r_a = a; + this.call(data1); + this.call(data2); + r = result; + r_b = b; + l = data1.length; + } + } + )"; + compileAndRun(sourceCode); + string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); + bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13); + string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); + bytes calldata = encodeArgs( + u256(innercalldata1.length()), u256(innercalldata2.length()), + 12, innercalldata1, innercalldata2, 13); + BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata) + == encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))); } BOOST_AUTO_TEST_SUITE_END() From 092312d4af60fa50589d5c0366482e88ef8f633a Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 16 Feb 2015 22:29:28 +0100 Subject: [PATCH 116/201] - small ui changes. - bug fix: mix, windows - unreadable fonts #1051. --- mix/qml/Debugger.qml | 7 +++++++ mix/qml/DefaultLabel.qml | 6 ------ mix/qml/DefaultTextField.qml | 7 ------- mix/qml/Ether.qml | 8 -------- mix/qml/StateDialog.qml | 2 +- mix/qml/TransactionDialog.qml | 10 +--------- mix/qml/WebPreview.qml | 14 ++++---------- 7 files changed, 13 insertions(+), 41 deletions(-) diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 1dd05574f..098cc77d1 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -131,7 +131,14 @@ Rectangle { Layout.fillWidth: true Layout.minimumHeight: 60 height: 250 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: machineStates.sideMargin + anchors.rightMargin: machineStates.sideMargin + anchors.topMargin: machineStates.sideMargin } + ScrollView { property int sideMargin: 10 diff --git a/mix/qml/DefaultLabel.qml b/mix/qml/DefaultLabel.qml index a1304e673..d8ef1faff 100644 --- a/mix/qml/DefaultLabel.qml +++ b/mix/qml/DefaultLabel.qml @@ -4,12 +4,6 @@ import "." Label { text: text - font.family: regularFont.name - font.pointSize: Style.generic.size.titlePointSize - SourceSansProLight - { - id: regularFont - } } diff --git a/mix/qml/DefaultTextField.qml b/mix/qml/DefaultTextField.qml index 6705273db..de306fa5e 100644 --- a/mix/qml/DefaultTextField.qml +++ b/mix/qml/DefaultTextField.qml @@ -3,11 +3,4 @@ import QtQuick.Controls 1.1 TextField { id: titleField - focus: true - font.family: regularFont.name - - SourceSansProRegular - { - id: regularFont; - } } diff --git a/mix/qml/Ether.qml b/mix/qml/Ether.qml index be41fced9..1a0f7ffe6 100644 --- a/mix/qml/Ether.qml +++ b/mix/qml/Ether.qml @@ -49,10 +49,6 @@ RowLayout { id: etherValueEdit; } - SourceSansProBold { - id: regularFont; - } - ComboBox { id: units @@ -87,15 +83,11 @@ RowLayout { ListElement { text: "Kwei"; } ListElement { text: "wei"; } } - style: ComboBoxStyle { - font: regularFont.name - } } Text { visible: displayFormattedValue id: formattedValue - font.family: regularFont.name } } diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index eeda2ae22..abb045497 100644 --- a/mix/qml/StateDialog.qml +++ b/mix/qml/StateDialog.qml @@ -12,7 +12,7 @@ Window { id: modalStateDialog modality: Qt.ApplicationModal - width: 450 + width: 520 height: 480 title: qsTr("Edit State") visible: false diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index a38886354..c71bd4155 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -10,7 +10,7 @@ import "." Window { id: modalTransactionDialog modality: Qt.ApplicationModal - width: 450 + width: 520 height: (paramsModel.count > 0 ? 500 : 300) visible: false color: StateDialogStyle.generic.backgroundColor @@ -174,11 +174,6 @@ Window { anchors.fill: parent anchors.margins: 10 - SourceSansProLight - { - id: lightFont - } - ColumnLayout { id: dialogContent anchors.top: parent.top @@ -204,9 +199,6 @@ Window { onCurrentIndexChanged: { loadParameters(); } - style: ComboBoxStyle { - font: lightFont.name - } } } diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 88b992b54..5d4d0e617 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -162,11 +162,6 @@ Item { spacing: 0 Rectangle { - SourceSansProLight - { - id: regularFont - } - anchors.leftMargin: 4 color: WebPreviewStyle.general.headerBackgroundColor Layout.preferredWidth: parent.width @@ -188,9 +183,7 @@ Item { currentIndex: -1 onCurrentIndexChanged: changePage() anchors.verticalCenter: parent.verticalCenter - style: ComboBoxStyle { - font: regularFont.name - } + height: 21 } Action { @@ -205,12 +198,13 @@ Item { iconSource: "qrc:/qml/img/available_updates.png" action: buttonReloadAction anchors.verticalCenter: parent.verticalCenter - width: 26 - height: 26 + width: 21 + height: 21 } CheckBox { id: autoReloadOnSave checked: true + height: 21 anchors.verticalCenter: parent.verticalCenter style: CheckBoxStyle { label: DefaultLabel { From 7af5ac1252a289790e8d0ff346e29b0b6c850d2a Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 15 Feb 2015 20:02:40 +0100 Subject: [PATCH 117/201] allow more than one contract --- libsolidity/Compiler.h | 2 + mix/CMakeLists.txt | 2 +- mix/ClientModel.cpp | 67 ++++++---- mix/ClientModel.h | 21 ++-- mix/CodeModel.cpp | 213 ++++++++++++++++++-------------- mix/CodeModel.h | 76 ++++++------ mix/QContractDefinition.cpp | 2 +- mix/QContractDefinition.h | 2 +- mix/StatusPane.cpp | 11 -- mix/StatusPane.h | 4 - mix/qml/CodeEditorView.qml | 2 +- mix/qml/Debugger.qml | 2 +- mix/qml/MainContent.qml | 2 +- mix/qml/ProjectList.qml | 21 ++-- mix/qml/ProjectModel.qml | 2 +- mix/qml/StateListModel.qml | 18 +-- mix/qml/StatusPane.qml | 14 ++- mix/qml/TransactionDialog.qml | 107 ++++++++++++---- mix/qml/WebPreview.qml | 12 +- mix/qml/html/WebContainer.html | 16 +-- mix/qml/js/ProjectModel.js | 77 ++++++++---- mix/qml/js/TransactionHelper.js | 1 - mix/qml/main.qml | 2 +- 23 files changed, 409 insertions(+), 267 deletions(-) diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index b3eae5b17..cbfb8dae0 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -20,6 +20,8 @@ * Solidity AST to EVM bytecode compiler. */ +#pragma once + #include #include #include diff --git a/mix/CMakeLists.txt b/mix/CMakeLists.txt index 4390a4eb0..892f2c1ed 100644 --- a/mix/CMakeLists.txt +++ b/mix/CMakeLists.txt @@ -71,4 +71,4 @@ eth_install_executable(${EXECUTABLE} #add qml asnd stdc files to project tree in Qt creator file(GLOB_RECURSE QMLFILES "qml/*.*") file(GLOB_RECURSE SOLFILES "stdc/*.*") -add_custom_target(dummy SOURCES ${QMLFILES} ${SOLFILES}) +add_custom_target(mix_qml SOURCES ${QMLFILES} ${SOLFILES}) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 57caf573c..91e5c98ab 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -65,7 +65,7 @@ private: ClientModel::ClientModel(AppContext* _context): - m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address()) + m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()) { qRegisterMetaType("QBigInt*"); qRegisterMetaType("QIntType*"); @@ -136,9 +136,12 @@ void ClientModel::mine() }); } -QString ClientModel::contractAddress() const +QVariantMap ClientModel::contractAddresses() const { - return QString::fromStdString(dev::toJS(m_contractAddress)); + QVariantMap res; + for (auto const& c: m_contractAddresses) + res.insert(c.first, QString::fromStdString(dev::toJS(c.second))); + return res; } void ClientModel::debugDeployment() @@ -155,8 +158,8 @@ void ClientModel::setupState(QVariantMap _state) for (auto const& t: transactions) { QVariantMap transaction = t.toMap(); + QString contractId = transaction.value("contractId").toString(); QString functionId = transaction.value("functionId").toString(); - u256 gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); @@ -164,7 +167,9 @@ void ClientModel::setupState(QVariantMap _state) bool isStdContract = (transaction.value("stdContract").toBool()); if (isStdContract) { - TransactionSettings transactionSettings(functionId, transaction.value("url").toString()); + if (contractId.isEmpty()) //TODO: This is to support old project files, remove later + contractId = functionId; + TransactionSettings transactionSettings(contractId, transaction.value("url").toString()); transactionSettings.gasPrice = 10000000000000; transactionSettings.gas = 125000; transactionSettings.value = 0; @@ -172,8 +177,10 @@ void ClientModel::setupState(QVariantMap _state) } else { + if (contractId.isEmpty() && m_context->codeModel()->hasContract()) //TODO: This is to support old project files, remove later + contractId = m_context->codeModel()->contracts().keys()[0]; QVariantList qParams = transaction.value("qType").toList(); - TransactionSettings transactionSettings(functionId, value, gas, gasPrice); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasPrice); for (QVariant const& variant: qParams) { @@ -181,7 +188,7 @@ void ClientModel::setupState(QVariantMap _state) transactionSettings.parameterValues.push_back(param); } - if (transaction.value("executeConstructor").toBool()) + if (contractId == functionId || functionId == "Constructor") transactionSettings.functionId.clear(); transactionSequence.push_back(transactionSettings); @@ -194,8 +201,6 @@ void ClientModel::executeSequence(std::vector const& _seque { if (m_running) BOOST_THROW_EXCEPTION(ExecutionStateException()); - CompilationResult* compilerRes = m_context->codeModel()->code(); - std::shared_ptr contractDef = compilerRes->sharedContract(); m_running = true; emit runStarted(); @@ -206,7 +211,6 @@ void ClientModel::executeSequence(std::vector const& _seque { try { - bytes contractCode = compilerRes->bytes(); m_client->resetState(_balance); onStateReset(); for (TransactionSettings const& transaction: _sequence) @@ -216,14 +220,17 @@ void ClientModel::executeSequence(std::vector const& _seque if (!transaction.stdContractUrl.isEmpty()) { //std contract - dev::bytes const& stdContractCode = m_context->codeModel()->getStdContractCode(transaction.functionId, transaction.stdContractUrl); + dev::bytes const& stdContractCode = m_context->codeModel()->getStdContractCode(transaction.contractId, transaction.stdContractUrl); Address address = deployContract(stdContractCode, transaction); - m_stdContractAddresses[transaction.functionId] = address; - m_stdContractNames[address] = transaction.functionId; + m_stdContractAddresses[transaction.contractId] = address; + m_stdContractNames[address] = transaction.contractId; } else { //encode data + CompiledContract const& compilerRes = m_context->codeModel()->contract(transaction.contractId); + bytes contractCode = compilerRes.bytes(); + std::shared_ptr contractDef = compilerRes.sharedContract(); f = nullptr; if (transaction.functionId.isEmpty()) f = contractDef->constructor(); @@ -240,24 +247,31 @@ void ClientModel::executeSequence(std::vector const& _seque encoder.encode(f); for (int p = 0; p < transaction.parameterValues.size(); p++) { - if (f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type()) - BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(f->parametersList().at(p)->type().toStdString())); + if (f->parametersList().size() <= p || f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type()) + BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(transaction.functionId.toStdString())); encoder.push(transaction.parameterValues.at(p)->encodeValue()); } - if (transaction.functionId.isEmpty()) + if (transaction.functionId.isEmpty() || transaction.functionId == transaction.contractId) { bytes param = encoder.encodedData(); contractCode.insert(contractCode.end(), param.begin(), param.end()); Address newAddress = deployContract(contractCode, transaction); - if (newAddress != m_contractAddress) + auto contractAddressIter = m_contractAddresses.find(transaction.contractId); + if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second) { - m_contractAddress = newAddress; - contractAddressChanged(); + m_contractAddresses[transaction.contractId] = newAddress; + m_contractNames[newAddress] = transaction.contractId; + contractAddressesChanged(); } } else - callContract(m_contractAddress, encoder.encodedData(), transaction); + { + auto contractAddressIter = m_contractAddresses.find(transaction.contractId); + if (contractAddressIter == m_contractAddresses.end()) + BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Contract not deployed: " + transaction.contractId.toStdString())); + callContract(contractAddressIter->second, encoder.encodedData(), transaction); + } } onNewTransaction(); } @@ -338,7 +352,8 @@ void ClientModel::callContract(Address const& _contract, bytes const& _data, Tra void ClientModel::onStateReset() { - m_contractAddress = dev::Address(); + m_contractAddresses.clear(); + m_contractNames.clear(); m_stdContractAddresses.clear(); m_stdContractNames.clear(); emit stateCleared(); @@ -389,14 +404,16 @@ void ClientModel::onNewTransaction() if (creation) returned = QString::fromStdString(toJS(tr.contractAddress)); - if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress)) + Address contractAddress = tr.address != 0 ? tr.address : tr.contractAddress; + auto contractAddressIter = m_contractNames.find(contractAddress); + if (contractAddressIter != m_contractNames.end()) { - auto compilerRes = m_context->codeModel()->code(); - QContractDefinition* def = compilerRes->contract(); + CompiledContract const& compilerRes = m_context->codeModel()->contract(contractAddressIter->second); + const QContractDefinition* def = compilerRes.contract(); contract = def->name(); if (abi) { - QFunctionDefinition* funcDef = def->getFunction(functionHash); + QFunctionDefinition const* funcDef = def->getFunction(functionHash); if (funcDef) { function = funcDef->name(); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 530dc50cf..dda60cb10 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -46,13 +46,13 @@ class QVariableDefinition; struct TransactionSettings { TransactionSettings() {} - TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): - functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} - TransactionSettings(u256 _value, u256 _gas, u256 _gasPrice): - value(_value), gas(_gas), gasPrice(_gasPrice) {} + TransactionSettings(QString const& _contractId, QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): + contractId(_contractId), functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} TransactionSettings(QString const& _stdContractName, QString const& _stdContractUrl): - functionId(_stdContractName), stdContractUrl(_stdContractUrl) {} + contractId(_stdContractName), stdContractUrl(_stdContractUrl) {} + /// Contract name + QString contractId; /// Contract function name QString functionId; /// Transaction value @@ -121,8 +121,8 @@ public: Q_PROPERTY(bool running MEMBER m_running NOTIFY runStateChanged) /// @returns true if currently mining Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged) - /// @returns address of the last executed contract - Q_PROPERTY(QString contractAddress READ contractAddress NOTIFY contractAddressChanged) + /// @returns deployed contracts addresses + Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) /// ethereum.js RPC request entry point /// @param _message RPC request in Json format /// @returns RPC response in Json format @@ -161,7 +161,7 @@ signals: /// @param _message Error message void runFailed(QString const& _message); /// Contract address changed - void contractAddressChanged(); + void contractAddressesChanged(); /// Execution state changed void newBlock(); /// Execution state changed @@ -177,7 +177,7 @@ signals: void stateCleared(); private: - QString contractAddress() const; + QVariantMap contractAddresses() const; void executeSequence(std::vector const& _sequence, u256 _balance); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); void callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); @@ -191,7 +191,8 @@ private: std::unique_ptr m_client; std::unique_ptr m_rpcConnector; std::unique_ptr m_web3Server; - Address m_contractAddress; + std::map m_contractAddresses; + std::map m_contractNames; std::map m_stdContractAddresses; std::map m_stdContractNames; }; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index aae9dac86..d605f1c6e 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -38,51 +39,31 @@ using namespace dev::mix; -void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content) +const std::set c_predefinedContracts = + { "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" }; + +void BackgroundWorker::queueCodeChange(int _jobId) { - m_model->runCompilationJob(_jobId, _content); + m_model->runCompilationJob(_jobId); } -CompilationResult::CompilationResult(): - QObject(nullptr), - m_successful(false), - m_codeHash(qHash(QString())), - m_contract(new QContractDefinition()), - m_contractInterface("[]"), - m_codeHighlighter(new CodeHighlighter()) -{} - -CompilationResult::CompilationResult(const dev::solidity::CompilerStack& _compiler): +CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler, QString const& _contractName, QString const& _source): QObject(nullptr), - m_successful(true), - m_codeHash(qHash(QString())) + m_sourceHash(qHash(_source)) { - if (!_compiler.getContractNames().empty()) - { - auto const& contractDefinition = _compiler.getContractDefinition(std::string()); - m_contract.reset(new QContractDefinition(&contractDefinition)); - m_bytes = _compiler.getBytecode(); - dev::solidity::InterfaceHandler interfaceHandler; - m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition)); - if (m_contractInterface.isEmpty()) - m_contractInterface = "[]"; - } - else - m_contract.reset(new QContractDefinition()); + auto const& contractDefinition = _compiler.getContractDefinition(_contractName.toStdString()); + m_contract.reset(new QContractDefinition(&contractDefinition)); + QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership); + m_bytes = _compiler.getBytecode(_contractName.toStdString()); + dev::solidity::InterfaceHandler interfaceHandler; + m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition)); + if (m_contractInterface.isEmpty()) + m_contractInterface = "[]"; + if (contractDefinition.getLocation().sourceName.get()) + m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName); } -CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage): - QObject(nullptr), - m_successful(false), - m_codeHash(qHash(QString())), - m_contract(_prev.m_contract), - m_compilerMessage(_compilerMessage), - m_bytes(_prev.m_bytes), - m_contractInterface(_prev.m_contractInterface), - m_codeHighlighter(_prev.m_codeHighlighter) -{} - -QString CompilationResult::codeHex() const +QString CompiledContract::codeHex() const { return QString::fromStdString(toJS(m_bytes)); } @@ -90,27 +71,26 @@ QString CompilationResult::codeHex() const CodeModel::CodeModel(QObject* _parent): QObject(_parent), m_compiling(false), - m_result(new CompilationResult()), m_codeHighlighterSettings(new CodeHighlighterSettings()), m_backgroundWorker(this), m_backgroundJobId(0) { + m_backgroundThread.start(); m_backgroundWorker.moveToThread(&m_backgroundThread); connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection); - connect(this, &CodeModel::compilationCompleteInternal, this, &CodeModel::onCompilationComplete, Qt::QueuedConnection); - qRegisterMetaType("CompilationResult*"); + qRegisterMetaType("CompiledContract*"); qRegisterMetaType("QContractDefinition*"); qRegisterMetaType("QFunctionDefinition*"); qRegisterMetaType("QVariableDeclaration*"); qmlRegisterType("org.ethereum.qml", 1, 0, "QFunctionDefinition"); qmlRegisterType("org.ethereum.qml", 1, 0, "QVariableDeclaration"); - m_backgroundThread.start(); } CodeModel::~CodeModel() { stop(); disconnect(this); + releaseContracts(); } void CodeModel::stop() @@ -120,80 +100,133 @@ void CodeModel::stop() m_backgroundThread.wait(); } -void CodeModel::registerCodeChange(QString const& _code) +void CodeModel::reset(QVariantMap const& _documents) { + ///@todo: cancel bg job + Guard l(x_contractMap); + releaseContracts(); + Guard pl(x_pendingContracts); + m_pendingContracts.clear(); + + for (QVariantMap::const_iterator d = _documents.cbegin(); d != _documents.cend(); d++) + m_pendingContracts[d.key()] = d.value().toString(); // launch the background thread - uint hash = qHash(_code); - if (m_result->m_codeHash == hash) - return; - m_backgroundJobId++; m_compiling = true; emit stateChanged(); - emit scheduleCompilationJob(m_backgroundJobId, _code); + emit scheduleCompilationJob(++m_backgroundJobId); } -void CodeModel::runCompilationJob(int _jobId, QString const& _code) +void CodeModel::registerCodeChange(QString const& _documentId, QString const& _code) { - if (_jobId != m_backgroundJobId) - return; //obsolete job + { + Guard l(x_contractMap); + CompiledContract* contract = m_contractMap.value(_documentId); + if (contract != nullptr && contract->m_sourceHash == qHash(_code)) + return; - solidity::CompilerStack cs(true); - std::unique_ptr result; + Guard pl(x_pendingContracts); + m_pendingContracts[_documentId] = _code; + } + + // launch the background thread + m_compiling = true; + emit stateChanged(); + emit scheduleCompilationJob(++m_backgroundJobId); +} + +QVariantMap CodeModel::contracts() const +{ + QVariantMap result; + Guard l(x_contractMap); + for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); c++) + result.insert(c.key(), QVariant::fromValue(c.value())); + return result; +} - std::string source = _code.toStdString(); - // run syntax highlighting first - // @todo combine this with compilation step - auto codeHighlighter = std::make_shared(); - codeHighlighter->processSource(source); +CompiledContract* CodeModel::contractByDocumentId(QString _documentId) const +{ + Guard l(x_contractMap); + for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); c++) + if (c.value()->m_documentId == _documentId) + return c.value(); + return nullptr; +} + +CompiledContract const& CodeModel::contract(QString _name) const +{ + Guard l(x_contractMap); + CompiledContract* res = m_contractMap.value(_name); + if (res == nullptr) + BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Contract not found: " + _name.toStdString())); + return *res; +} - cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})"); +void CodeModel::releaseContracts() +{ + for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); c++) + c.value()->deleteLater(); + m_contractMap.clear(); +} + +void CodeModel::runCompilationJob(int _jobId) +{ + if (_jobId != m_backgroundJobId) + return; //obsolete job - // run compilation + ContractMap result; + solidity::CompilerStack cs(true); try { - cs.addSource("", source); + cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})"); + { + Guard l(x_pendingContracts); + for (auto const& c: m_pendingContracts) + cs.addSource(c.first.toStdString(), c.second.toStdString()); + } cs.compile(false); - codeHighlighter->processAST(cs.getAST()); - result.reset(new CompilationResult(cs)); - qDebug() << QString(QApplication::tr("compilation succeeded")); + + { + Guard pl(x_pendingContracts); + Guard l(x_contractMap); + for (std::string n: cs.getContractNames()) + { + if (c_predefinedContracts.count(n) != 0) + continue; + QString name = QString::fromStdString(n); + auto sourceIter = m_pendingContracts.find(name); + QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString(); + CompiledContract* contract = new CompiledContract(cs, name, source); + QQmlEngine::setObjectOwnership(contract, QQmlEngine::CppOwnership); + result[name] = contract; + CompiledContract* prevContract = m_contractMap.value(name); + if (prevContract != nullptr && prevContract->contractInterface() != result[name]->contractInterface()) + emit contractInterfaceChanged(name); + } + releaseContracts(); + m_contractMap.swap(result); + emit codeChanged(); + emit compilationComplete(); + } } catch (dev::Exception const& _exception) { std::ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, _exception, "Error", cs); - result.reset(new CompilationResult(*m_result, QString::fromStdString(error.str()))); - codeHighlighter->processError(_exception); - qDebug() << QString(QApplication::tr("compilation failed:") + " " + result->compilerMessage()); + solidity::Location const* location = boost::get_error_info(_exception); + QString message = QString::fromStdString(error.str()); + CompiledContract* contract = nullptr; + if (location && location->sourceName.get() && (contract = contractByDocumentId(QString::fromStdString(*location->sourceName)))) + message = message.replace(QString::fromStdString(*location->sourceName), contract->contract()->name()); //substitute the location to match our contract names + compilationError(message); } - result->m_codeHighlighter = codeHighlighter; - result->m_codeHash = qHash(_code); - - emit compilationCompleteInternal(result.release()); -} - -void CodeModel::onCompilationComplete(CompilationResult* _newResult) -{ m_compiling = false; - bool contractChanged = m_result->contractInterface() != _newResult->contractInterface(); - m_result.reset(_newResult); - emit compilationComplete(); emit stateChanged(); - if (m_result->successful()) - { - emit codeChanged(); - if (contractChanged) - emit contractInterfaceChanged(); - } } bool CodeModel::hasContract() const { - return m_result->successful(); -} - -void CodeModel::updateFormatting(QTextDocument* _document) -{ - m_result->codeHighlighter()->updateFormatting(_document, *m_codeHighlighterSettings); + Guard l(x_contractMap); + return m_contractMap.size() != 0; } dev::bytes const& CodeModel::getStdContractCode(const QString& _contractName, const QString& _url) diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 0262aa094..48dbbcd6c 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include class QTextDocument; @@ -56,59 +58,50 @@ public: BackgroundWorker(CodeModel* _model): QObject(), m_model(_model) {} public slots: - void queueCodeChange(int _jobId, QString const& _content); + void queueCodeChange(int _jobId); private: CodeModel* m_model; }; ///Compilation result model. Contains all the compiled contract data required by UI -class CompilationResult: public QObject +class CompiledContract: public QObject { Q_OBJECT Q_PROPERTY(QContractDefinition* contract READ contract) - Q_PROPERTY(QString compilerMessage READ compilerMessage CONSTANT) - Q_PROPERTY(bool successful READ successful CONSTANT) Q_PROPERTY(QString contractInterface READ contractInterface CONSTANT) Q_PROPERTY(QString codeHex READ codeHex CONSTANT) + Q_PROPERTY(QString documentId MEMBER m_documentId CONSTANT) public: - /// Empty compilation result constructor - CompilationResult(); /// Successful compilation result constructor - CompilationResult(solidity::CompilerStack const& _compiler); - /// Failed compilation result constructor - CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage); + CompiledContract(solidity::CompilerStack const& _compiler, QString const& _contractName, QString const& _source); /// @returns contract definition for QML property - QContractDefinition* contract() { return m_contract.get(); } + QContractDefinition* contract() const { return m_contract.get(); } /// @returns contract definition - std::shared_ptr sharedContract() { return m_contract; } - /// Indicates if the compilation was successful - bool successful() const { return m_successful; } - /// @returns compiler error message in case of unsuccessful compilation - QString compilerMessage() const { return m_compilerMessage; } + std::shared_ptr sharedContract() const { return m_contract; } /// @returns contract bytecode dev::bytes const& bytes() const { return m_bytes; } /// @returns contract bytecode as hex string QString codeHex() const; /// @returns contract definition in JSON format QString contractInterface() const { return m_contractInterface; } - /// Get code highlighter - std::shared_ptr codeHighlighter() { return m_codeHighlighter; } private: - bool m_successful; - uint m_codeHash; + uint m_sourceHash; std::shared_ptr m_contract; QString m_compilerMessage; ///< @todo: use some structure here dev::bytes m_bytes; QString m_contractInterface; - std::shared_ptr m_codeHighlighter; + QString m_documentId; friend class CodeModel; }; -/// Background code compiler + +using ContractMap = QHash; + +/// Code compilation model. Compiles contracts in background an provides compiled contract data class CodeModel: public QObject { Q_OBJECT @@ -117,56 +110,59 @@ public: CodeModel(QObject* _parent); ~CodeModel(); - /// @returns latest compilation result - CompilationResult* code() { return m_result.get(); } - /// @returns latest compilation resul - CompilationResult const* code() const { return m_result.get(); } - - Q_PROPERTY(CompilationResult* code READ code NOTIFY codeChanged) + Q_PROPERTY(QVariantMap contracts READ contracts NOTIFY codeChanged) Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged) Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged) + /// @returns latest compilation results for contracts + QVariantMap contracts() const; /// @returns compilation status bool isCompiling() const { return m_compiling; } - /// @returns true if contract has at least one function + /// @returns true there is a contract which has at least one function bool hasContract() const; - /// Apply text document formatting. @todo Move this to editor module - void updateFormatting(QTextDocument* _document); /// Get contract code by url. Contract is compiled on first access and cached dev::bytes const& getStdContractCode(QString const& _contractName, QString const& _url); + /// Get contract by name + CompiledContract const& contract(QString _name) const; + /// Find a contract by document id + /// @returns CompiledContract object or null if not found + Q_INVOKABLE CompiledContract* contractByDocumentId(QString _documentId) const; signals: /// Emited on compilation state change void stateChanged(); /// Emitted on compilation complete void compilationComplete(); + /// Emitted on compilation error + void compilationError(QString _error); /// Internal signal used to transfer compilation job to background thread - void scheduleCompilationJob(int _jobId, QString const& _content); + void scheduleCompilationJob(int _jobId); /// Emitted if there are any changes in the code model void codeChanged(); /// Emitted if there are any changes in the contract interface - void contractInterfaceChanged(); - /// Emitted on compilation complete. Internal - void compilationCompleteInternal(CompilationResult* _newResult); - -private slots: - void onCompilationComplete(CompilationResult* _newResult); + void contractInterfaceChanged(QString _documentId); public slots: /// Update code model on source code change - void registerCodeChange(QString const& _code); + void registerCodeChange(QString const& _documentId, QString const& _code); + /// Reset code model for a new project + void reset(QVariantMap const& _documents); private: - void runCompilationJob(int _jobId, QString const& _content); + void runCompilationJob(int _jobId); void stop(); + void releaseContracts(); std::atomic m_compiling; - std::unique_ptr m_result; + mutable dev::Mutex x_contractMap; + ContractMap m_contractMap; std::unique_ptr m_codeHighlighterSettings; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; int m_backgroundJobId = 0; //protects from starting obsolete compilation job std::map m_compiledContracts; //by name + dev::Mutex x_pendingContracts; + std::map m_pendingContracts; //name to source friend class BackgroundWorker; }; diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index 488e08ea3..eacaee2f9 100644 --- a/mix/QContractDefinition.cpp +++ b/mix/QContractDefinition.cpp @@ -42,7 +42,7 @@ QContractDefinition::QContractDefinition(dev::solidity::ContractDefinition const m_functions.append(new QFunctionDefinition(it.second));} -QFunctionDefinition* QContractDefinition::getFunction(dev::FixedHash<4> _hash) +QFunctionDefinition const* QContractDefinition::getFunction(dev::FixedHash<4> _hash) const { for (auto const& f: m_functions) if (f->hash() == _hash) diff --git a/mix/QContractDefinition.h b/mix/QContractDefinition.h index 22f913a70..4d586a239 100644 --- a/mix/QContractDefinition.h +++ b/mix/QContractDefinition.h @@ -47,7 +47,7 @@ public: QFunctionDefinition* constructor() const { return m_constructor; } QList const& functionsList() const { return m_functions; } /// Find function by hash, returns nullptr if not found - QFunctionDefinition* getFunction(dev::FixedHash<4> _hash); + QFunctionDefinition const* getFunction(dev::FixedHash<4> _hash) const; private: QList m_functions; QFunctionDefinition* m_constructor; diff --git a/mix/StatusPane.cpp b/mix/StatusPane.cpp index f74b8f22b..9022b7033 100644 --- a/mix/StatusPane.cpp +++ b/mix/StatusPane.cpp @@ -36,7 +36,6 @@ using namespace dev::mix; StatusPane::StatusPane(AppContext* _context): Extension(_context, ExtensionDisplayBehavior::HeaderView) { - connect(_context->codeModel(), &CodeModel::compilationComplete, this, &StatusPane::update); _context->appEngine()->rootContext()->setContextProperty("statusPane", this); } @@ -54,13 +53,3 @@ void StatusPane::start() const { } -CompilationResult* StatusPane::result() const -{ - return m_ctx->codeModel()->code(); -} - -void StatusPane::update() -{ - QObject* ctrl = m_view->findChild("statusPane", Qt::FindChildrenRecursively); - QMetaObject::invokeMethod(ctrl, "updateStatus"); -} diff --git a/mix/StatusPane.h b/mix/StatusPane.h index ee65252b5..28b5b449b 100644 --- a/mix/StatusPane.h +++ b/mix/StatusPane.h @@ -20,7 +20,6 @@ #pragma once #include "Extension.h" -#include "CodeModel.h" namespace dev { @@ -33,7 +32,6 @@ namespace mix class StatusPane: public Extension { Q_OBJECT - Q_PROPERTY(CompilationResult* result READ result CONSTANT) public: StatusPane(AppContext* _appContext); @@ -41,10 +39,8 @@ public: void start() const override; QString title() const override; QString contentUrl() const override; - CompilationResult* result() const; public slots: - void update(); }; } diff --git a/mix/qml/CodeEditorView.qml b/mix/qml/CodeEditorView.qml index 9c0b804d7..439c36199 100644 --- a/mix/qml/CodeEditorView.qml +++ b/mix/qml/CodeEditorView.qml @@ -43,7 +43,7 @@ Item { editor.onEditorTextChanged.connect(function() { documentEdit(document.documentId); if (document.isContract) - codeModel.registerCodeChange(editor.getText()); + codeModel.registerCodeChange(document.documentId, editor.getText()); }); editor.setText(data, document.syntaxMode); } diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 098cc77d1..316ec86c7 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -25,7 +25,7 @@ Rectangle { function update(data, giveFocus) { - if (statusPane && statusPane.result.successful) + if (statusPane && codeModel.hasContract) { Debugger.init(data); debugScrollArea.visible = true; diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 6c6781878..15a7a638f 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -34,7 +34,7 @@ Rectangle { onCompilationComplete: { if (firstCompile) { firstCompile = false; - if (codeModel.code.successful && runOnProjectLoad) + if (runOnProjectLoad) startQuickDebugging(); } } diff --git a/mix/qml/ProjectList.qml b/mix/qml/ProjectList.qml index 925bb0bab..d4875220a 100644 --- a/mix/qml/ProjectList.qml +++ b/mix/qml/ProjectList.qml @@ -101,14 +101,19 @@ Item { Connections { target: codeModel onCompilationComplete: { - if (modelData === "Contracts") - { - var ctr = projectModel.listModel.get(0); - if (codeModel.code.contract.name !== ctr.name) - { - ctr.name = codeModel.code.contract.name; - projectModel.listModel.set(0, ctr); - sectionModel.set(0, ctr); + if (modelData === "Contracts") { + var ci = 0; + for (var si = 0; si < projectModel.listModel.count; si++) { + var document = projectModel.listModel.get(si); + if (document.isContract) { + var compiledDoc = codeModel.contractByDocumentId(document.documentId); + if (compiledDoc && compiledDoc.documentId === document.documentId && compiledDoc.contract.name !== document.name) { + document.name = compiledDoc.contract.name; + projectModel.listModel.set(si, document); + sectionModel.set(ci, document); + } + ci++; + } } } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index e74be7a9b..97dec227c 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -45,7 +45,7 @@ Item { function newHtmlFile() { ProjectModelCode.newHtmlFile(); } function newJsFile() { ProjectModelCode.newJsFile(); } function newCssFile() { ProjectModelCode.newCssFile(); } - //function newContract() { ProjectModelCode.newContract(); } + function newContract() { ProjectModelCode.newContract(); } function openDocument(documentId) { ProjectModelCode.openDocument(documentId); } function openNextDocument() { ProjectModelCode.openNextDocument(); } function openPrevDocument() { ProjectModelCode.openPrevDocument(); } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index c68a433f7..da02ce5e6 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -22,12 +22,12 @@ Item { function fromPlainTransactionItem(t) { var r = { + contractId: t.contractId, functionId: t.functionId, url: t.url, value: QEtherHelper.createEther(t.value.value, t.value.unit), gas: QEtherHelper.createBigInt(t.gas.value), //t.gas,//QEtherHelper.createEther(t.gas.value, t.gas.unit), gasPrice: QEtherHelper.createEther(t.gasPrice.value, t.gasPrice.unit), - executeConstructor: t.executeConstructor, stdContract: t.stdContract, parameters: {} }; @@ -78,12 +78,12 @@ Item { function toPlainTransactionItem(t) { var r = { + contractId: t.contractId, functionId: t.functionId, url: t.url, value: { value: t.value.value, unit: t.value.unit }, gas: { value: t.gas.value() }, gasPrice: { value: t.gasPrice.value, unit: t.gasPrice.unit }, - executeConstructor: t.executeConstructor, stdContract: t.stdContract, parameters: {} }; @@ -159,7 +159,6 @@ Item { value: QEtherHelper.createEther("100", QEther.Wei), gas: QEtherHelper.createBigInt("125000"), gasPrice: QEtherHelper.createEther("10000000000000", QEther.Wei), - executeConstructor: false, stdContract: false }; } @@ -178,16 +177,19 @@ Item { var contractTransaction = defaultTransactionItem(); var contractItem = contractLibrary.model.get(i); contractTransaction.url = contractItem.url; + contractTransaction.contractId = contractItem.name; contractTransaction.functionId = contractItem.name; contractTransaction.stdContract = true; item.transactions.push(contractTransaction); }; - //add constructor - var ctorTr = defaultTransactionItem(); - ctorTr.executeConstructor = true; - ctorTr.functionId = qsTr("Constructor"); - item.transactions.push(ctorTr); + //add constructors, //TODO: order by dependencies + for(var c in codeModel.contracts) { + var ctorTr = defaultTransactionItem(); + ctorTr.functionId = c; + ctorTr.contractId = c; + item.transactions.push(ctorTr); + } return item; } diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index ddadb9953..6a8a0093d 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -8,9 +8,9 @@ Rectangle { id: statusHeader objectName: "statusPane" - function updateStatus() + function updateStatus(message) { - if (statusPane.result.successful) + if (!message) { status.state = ""; status.text = qsTr("Compile without errors."); @@ -20,12 +20,12 @@ Rectangle { else { status.state = "error"; - var errorInfo = ErrorLocationFormater.extractErrorInfo(statusPane.result.compilerMessage, true); + var errorInfo = ErrorLocationFormater.extractErrorInfo(message, true); status.text = errorInfo.errorLocation + " " + errorInfo.errorDetail; logslink.visible = true; debugImg.state = ""; } - debugRunActionIcon.enabled = statusPane.result.successful; + debugRunActionIcon.enabled = codeModel.hasContract; } function infoMessage(text) @@ -35,7 +35,6 @@ Rectangle { logslink.visible = false; } - Connections { target:clientModel onRunStarted: infoMessage(qsTr("Running transactions...")); @@ -49,6 +48,11 @@ Rectangle { onDeploymentError: infoMessage(error); onDeploymentComplete: infoMessage(qsTr("Deployment complete")); } + Connections { + target: codeModel + onCompilationComplete: updateStatus(); + onCompilationError: updateStatus(_error); + } color: "transparent" anchors.fill: parent diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index c71bd4155..e5a8bc746 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -20,9 +20,9 @@ Window { property alias gas: gasValueEdit.gasValue; property alias gasPrice: gasPriceField.value; property alias transactionValue: valueField.value; + property string contractId: contractComboBox.currentValue(); property alias functionId: functionComboBox.currentText; property var itemParams; - property bool isConstructorTransaction; property bool useTransactionDefaultValue: false property var qType; @@ -39,32 +39,47 @@ Window { gasValueEdit.gasValue = item.gas; gasPriceField.value = item.gasPrice; valueField.value = item.value; + var contractId = item.contractId; var functionId = item.functionId; - isConstructorTransaction = item.executeConstructor; - rowFunction.visible = !item.executeConstructor; + rowFunction.visible = true; itemParams = item.parameters !== undefined ? item.parameters : {}; - functionsModel.clear(); + + contractsModel.clear(); + var contractIndex = -1; + var contracts = codeModel.contracts; + for (var c in contracts) { + contractsModel.append({ cid: c, text: contracts[c].contract.name }); + if (contracts[c].contract.name === contractId) + contractIndex = contractsModel.count - 1; + } + + if (contractIndex == -1 && contractsModel.count > 0) + contractIndex = 0; //@todo suggest unused contract + contractComboBox.currentIndex = contractIndex; + + loadFunctions(contractComboBox.currentValue()); + var functionIndex = -1; - var functions = codeModel.code.contract.functions; - for (var f = 0; f < functions.length; f++) { - functionsModel.append({ text: functions[f].name }); - if (functions[f].name === item.functionId) + for (var f = 0; f < functionsModel.count; f++) + if (functionsModel.get(f).text === item.functionId) functionIndex = f; - } if (functionIndex == -1 && functionsModel.count > 0) functionIndex = 0; //@todo suggest unused function functionComboBox.currentIndex = functionIndex; + paramsModel.clear(); - if (!item.executeConstructor) + if (functionId !== contractComboBox.currentValue()) loadParameters(); - else - { - var parameters = codeModel.code.contract.constructor.parameters; - for (var p = 0; p < parameters.length; p++) - loadParameter(parameters[p]); + else { + var contract = codeModel.contracts[contractId]; + if (contract) { + var parameters = contract.contract.constructor.parameters; + for (var p = 0; p < parameters.length; p++) + loadParameter(parameters[p]); + } } modalTransactionDialog.setX((Screen.width - width) / 2); modalTransactionDialog.setY((Screen.height - height) / 2); @@ -73,6 +88,21 @@ Window { valueField.focus = true; } + function loadFunctions(contractId) + { + functionsModel.clear(); + var contract = codeModel.contracts[contractId]; + if (contract) { + var functions = codeModel.contracts[contractId].contract.functions; + for (var f = 0; f < functions.length; f++) { + functionsModel.append({ text: functions[f].name }); + } + } + //append constructor + functionsModel.append({ text: contractId }); + + } + function loadParameter(parameter) { var type = parameter.type; @@ -104,10 +134,15 @@ Window { if (!paramsModel) return; if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var func = codeModel.code.contract.functions[functionComboBox.currentIndex]; - var parameters = func.parameters; - for (var p = 0; p < parameters.length; p++) - loadParameter(parameters[p]); + var contract = codeModel.contracts[contractComboBox.currentValue()]; + if (contract) { + var func = contract.contract.functions[functionComboBox.currentIndex]; + if (func) { + var parameters = func.parameters; + for (var p = 0; p < parameters.length; p++) + loadParameter(parameters[p]); + } + } } } @@ -140,24 +175,21 @@ Window { if (!useTransactionDefaultValue) { item = { + contractId: transactionDialog.contractId, functionId: transactionDialog.functionId, gas: transactionDialog.gas, gasPrice: transactionDialog.gasPrice, value: transactionDialog.transactionValue, parameters: {}, - executeConstructor: isConstructorTransaction }; } else { item = TransactionHelper.defaultTransaction(); + item.contractId = transactionDialog.contractId; item.functionId = transactionDialog.functionId; - item.executeConstructor = isConstructorTransaction; } - if (isConstructorTransaction) - item.functionId = qsTr("Constructor"); - var orderedQType = []; for (var p = 0; p < transactionDialog.transactionParams.count; p++) { var parameter = transactionDialog.transactionParams.get(p); @@ -178,6 +210,33 @@ Window { id: dialogContent anchors.top: parent.top spacing: 10 + RowLayout + { + id: rowContract + Layout.fillWidth: true + height: 150 + DefaultLabel { + Layout.preferredWidth: 75 + text: qsTr("Contract") + } + ComboBox { + id: contractComboBox + function currentValue() { + return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : ""; + } + Layout.preferredWidth: 350 + currentIndex: -1 + textRole: "text" + editable: false + model: ListModel { + id: contractsModel + } + onCurrentIndexChanged: { + loadFunctions(currentValue()); + } + } + } + RowLayout { id: rowFunction diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 5d4d0e617..9886a71c6 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -29,7 +29,16 @@ Item { } function updateContract() { - webView.runJavaScript("updateContract(\"" + codeModel.code.contract.name + "\", \"" + clientModel.contractAddress + "\", " + codeModel.code.contractInterface + ")"); + var contracts = {}; + for (var c in codeModel.contracts) { + var contract = codeModel.contracts[c]; + contracts[c] = { + name: contract.contract.name, + address: clientModel.contractAddresses[contract.contract.name], + interface: JSON.parse(contract.contractInterface), + }; + } + webView.runJavaScript("updateContracts(" + JSON.stringify(contracts) + ")"); } function reloadOnSave() { @@ -62,7 +71,6 @@ Item { Connections { target: clientModel - onContractAddressChanged: reload(); onRunComplete: reload(); } diff --git a/mix/qml/html/WebContainer.html b/mix/qml/html/WebContainer.html index 09a8734d5..26cac5103 100644 --- a/mix/qml/html/WebContainer.html +++ b/mix/qml/html/WebContainer.html @@ -15,16 +15,18 @@ reloadPage = function() { preview.contentWindow.location.reload(); }; -updateContract = function(name, address, contractFace) { +updateContracts = function(contracts) { if (window.web3) { window.web3.provider.polls = []; - var contract = window.web3.eth.contract(address, contractFace); window.contracts = {}; - window.contracts[name] = { - address: address, - interface: contractFace, - contract: contract, - }; + for (var c in contracts) { + var contract = window.web3.eth.contract(contracts[c].address, contracts[c].interface); + window.contracts[c] = { + address: c.address, + interface: c.interface, + contract: contract, + }; + } } }; diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index be6c07c5b..5a7bf4332 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -20,6 +20,9 @@ * Ethereum IDE client. */ +var htmlTemplate = "\n\n\n\n\n\n\n"; +var contractTemplate = "contract Contract {\n}\n"; + function saveAll() { saveProject(); } @@ -76,6 +79,16 @@ function loadProject(path) { projectSettings.lastProjectPath = path; projectLoading(projectData); projectLoaded() + + //TODO: move this to codemodel + var contractSources = {}; + for (var d = 0; d < listModel.count; d++) { + var doc = listModel.get(d); + if (doc.isContract) + contractSources[doc.documentId] = fileIo.readFile(doc.path); + } + codeModel.reset(contractSources); + } function addFile(fileName) { @@ -92,7 +105,7 @@ function addFile(fileName) { contract: false, path: p, fileName: fileName, - name: isContract ? "Contract" : fileName, + name: fileName, documentId: fileName, syntaxMode: syntaxMode, isText: isContract || isHtml || isCss || isJs, @@ -150,7 +163,7 @@ function openPrevDocument() { } function doCloseProject() { - console.log("closing project"); + console.log("Closing project"); projectListModel.clear(); projectPath = ""; currentDocumentId = ""; @@ -167,14 +180,14 @@ function doCreateProject(title, path) { var projectFile = dirPath + projectFileName; var indexFile = "index.html"; - var contractsFile = "contracts.sol"; + var contractsFile = "contract.sol"; var projectData = { title: title, files: [ contractsFile, indexFile ] }; //TODO: copy from template - fileIo.writeFile(dirPath + indexFile, "\n\n\n\n\n\n\n"); - fileIo.writeFile(dirPath + contractsFile, "contract Contract {\n}\n"); + fileIo.writeFile(dirPath + indexFile, htmlTemplate); + fileIo.writeFile(dirPath + contractsFile, contractTemplate); newProject(projectData); var json = JSON.stringify(projectData, null, "\t"); fileIo.writeFile(projectFile, json); @@ -222,7 +235,7 @@ function removeDocument(documentId) { } function newHtmlFile() { - createAndAddFile("page", "html", "\n"); + createAndAddFile("page", "html", htmlTemplate); } function newCssFile() { @@ -233,6 +246,11 @@ function newJsFile() { createAndAddFile("script", "js", "function foo() {\n}\n"); } +function newContract() { + createAndAddFile("contract", "sol", contractTemplate); +} + + function createAndAddFile(name, extension, content) { var fileName = generateFileName(name, extension); var filePath = projectPath + fileName; @@ -267,15 +285,21 @@ function deployProject(force) { var jsonRpcUrl = "http://localhost:8080"; console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); deploymentStarted(); - var code = codeModel.codeHex - var rpcRequest = JSON.stringify({ - jsonrpc: "2.0", - method: "eth_transact", - params: [ { - "code": code - } ], - id: jsonRpcRequestId++ - }); + + var requests = []; + var requestNames = []; + for (var c in codeModel.contracts) { //TODO: order based on dependencies + var code = codeModel.contracts[c].codeHex; + requests.push({ + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "code": code } ], + id: jsonRpcRequestId++ + }); + requestNames.push(c); + } + + var rpcRequest = JSON.stringify(requests);; var httpRequest = new XMLHttpRequest() httpRequest.open("POST", jsonRpcUrl, true); httpRequest.setRequestHeader("Content-type", "application/json"); @@ -285,9 +309,12 @@ function deployProject(force) { if (httpRequest.readyState === XMLHttpRequest.DONE) { if (httpRequest.status === 200) { var rpcResponse = JSON.parse(httpRequest.responseText); - var address = rpcResponse.result; - console.log("Created contract, address: " + address); - finalizeDeployment(deploymentId, address); + if (rpcResponse.length === requestNames.length) { + var contractAddresses = {}; + for (var r = 0; r < rpcResponse.lenght; r++) + contractAddresses[requestNames[r]] = rpcResponse.result; + finalizeDeployment(deploymentId, contractAddresses); + } } else { var errorText = qsTr("Deployment error: RPC server HTTP status ") + httpRequest.status; console.log(errorText); @@ -298,7 +325,7 @@ function deployProject(force) { httpRequest.send(rpcRequest); } -function finalizeDeployment(deploymentId, address) { +function finalizeDeployment(deploymentId, addresses) { //create a dir for frontend files and copy them var deploymentDir = projectPath + deploymentId + "/"; fileIo.makeDir(deploymentDir); @@ -326,16 +353,18 @@ function finalizeDeployment(deploymentId, address) { fileIo.copyFile(doc.path, deploymentDir + doc.fileName); } //write deployment js - var contractAccessor = "contracts[\"" + codeModel.code.contract.name + "\"]"; var deploymentJs = "// Autogenerated by Mix\n" + "web3 = require(\"web3\");\n" + - "contracts = {};\n" + - contractAccessor + " = {\n" + - "\tinterface: " + codeModel.code.contractInterface + ",\n" + - "\taddress: \"" + address + "\"\n" + + "contracts = {};\n"; + for (var c in codeModel.contracts) { + var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; + deploymentJs += contractAccessor + " = {\n" + + "\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" + + "\taddress: \"" + addresses[c] + "\"\n" + "};\n" + contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; + } fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); //copy scripts fileIo.copyFile("qrc:///js/bignumber.min.js", deploymentDir + "bignumber.min.js"); diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index 87dd74beb..62399161e 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -7,7 +7,6 @@ function defaultTransaction() functionId: "", gas: createBigInt("125000"), gasPrice: createEther("100000", QEther.Wei), - executeConstructor: false, parameters: {} }; } diff --git a/mix/qml/main.qml b/mix/qml/main.qml index 71d8c24bf..a1cf99de6 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -30,7 +30,7 @@ ApplicationWindow { MenuItem { action: addNewHtmlFileAction } MenuItem { action: addNewCssFileAction } MenuSeparator {} - //MenuItem { action: addNewContractAction } + MenuItem { action: addNewContractAction } MenuItem { action: closeProjectAction } MenuSeparator {} MenuItem { action: exitAppAction } From 37fa06106b651e1a50c2ea3f34164e19622d74df Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 17 Feb 2015 09:23:23 +0100 Subject: [PATCH 118/201] fixed cppcheck warnings --- mix/ClientModel.cpp | 3 +-- mix/CodeHighlighter.cpp | 2 +- mix/CodeModel.cpp | 8 ++++---- mix/ContractCallDataEncoder.cpp | 2 +- mix/MixClient.cpp | 4 ++-- mix/QVariableDefinition.h | 4 ++-- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 91e5c98ab..45198c114 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -216,7 +216,6 @@ void ClientModel::executeSequence(std::vector const& _seque for (TransactionSettings const& transaction: _sequence) { ContractCallDataEncoder encoder; - QFunctionDefinition const* f = nullptr; if (!transaction.stdContractUrl.isEmpty()) { //std contract @@ -229,9 +228,9 @@ void ClientModel::executeSequence(std::vector const& _seque { //encode data CompiledContract const& compilerRes = m_context->codeModel()->contract(transaction.contractId); + QFunctionDefinition const* f = nullptr; bytes contractCode = compilerRes.bytes(); std::shared_ptr contractDef = compilerRes.sharedContract(); - f = nullptr; if (transaction.functionId.isEmpty()) f = contractDef->constructor(); else diff --git a/mix/CodeHighlighter.cpp b/mix/CodeHighlighter.cpp index d76d8b73e..86dfe9e5d 100644 --- a/mix/CodeHighlighter.cpp +++ b/mix/CodeHighlighter.cpp @@ -119,7 +119,7 @@ void CodeHighlighter::processComments(std::string const& _source) //add single line comment int start = i; i += 2; - while (_source[i] != '\n' && i < size) + while (i < size && _source[i] != '\n') ++i; m_formats.push_back(FormatRange(CodeHighlighterSettings::Comment, start, i - start)); } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index d605f1c6e..7a38594ce 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -108,7 +108,7 @@ void CodeModel::reset(QVariantMap const& _documents) Guard pl(x_pendingContracts); m_pendingContracts.clear(); - for (QVariantMap::const_iterator d = _documents.cbegin(); d != _documents.cend(); d++) + for (QVariantMap::const_iterator d = _documents.cbegin(); d != _documents.cend(); ++d) m_pendingContracts[d.key()] = d.value().toString(); // launch the background thread m_compiling = true; @@ -138,7 +138,7 @@ QVariantMap CodeModel::contracts() const { QVariantMap result; Guard l(x_contractMap); - for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); c++) + for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); ++c) result.insert(c.key(), QVariant::fromValue(c.value())); return result; } @@ -146,7 +146,7 @@ QVariantMap CodeModel::contracts() const CompiledContract* CodeModel::contractByDocumentId(QString _documentId) const { Guard l(x_contractMap); - for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); c++) + for (ContractMap::const_iterator c = m_contractMap.cbegin(); c != m_contractMap.cend(); ++c) if (c.value()->m_documentId == _documentId) return c.value(); return nullptr; @@ -163,7 +163,7 @@ CompiledContract const& CodeModel::contract(QString _name) const void CodeModel::releaseContracts() { - for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); c++) + for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); ++c) c.value()->deleteLater(); m_contractMap.clear(); } diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 19ece2a4d..e31f79e9f 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -56,7 +56,7 @@ QList ContractCallDataEncoder::decode(QList r; for (int k = 0; k <_returnParameters.length(); k++) { - QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k); + QVariableDeclaration* dec = static_cast(_returnParameters.at(k)); QVariableDefinition* def = nullptr; if (dec->type().contains("int")) def = new QIntType(dec, QString()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index b2a367929..3b0a2a03b 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -117,8 +117,8 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c unsigned dataIndex = 0; auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) { - VM& vm = *(VM*)voidVM; - ExtVM const& ext = *(ExtVM const*)voidExt; + VM& vm = *static_cast(voidVM); + ExtVM const& ext = *static_cast(voidExt); if (lastCode == nullptr || lastCode != &ext.code) { auto const& iter = codeIndexes.find(&ext.code); diff --git a/mix/QVariableDefinition.h b/mix/QVariableDefinition.h index ae9bf9459..1825c2567 100644 --- a/mix/QVariableDefinition.h +++ b/mix/QVariableDefinition.h @@ -135,8 +135,8 @@ class QBoolType: public QVariableDefinition Q_OBJECT public: - QBoolType() {} - QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {} + QBoolType(): m_boolValue(false) {} + QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value), m_boolValue(false) {} dev::bytes encodeValue() override; void decodeValue(dev::bytes const& _rawValue) override; /// @returns the boolean value for the current definition. From 69f3733501606d1e390ee24d2cad9872fca2570b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 17 Feb 2015 09:24:58 +0100 Subject: [PATCH 119/201] Initialize FunctionType's m_isConstant attribute in the Event Constructor --- libsolidity/Types.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 5d753645c..b41834d84 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -769,7 +769,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): } FunctionType::FunctionType(const EventDefinition& _event): - m_location(Location::Event), m_declaration(&_event) + m_location(Location::Event), m_isConstant(true), m_declaration(&_event) { TypePointers params; vector paramNames; From 9e87abc136b31ae42a332e104900cc3eaccadf05 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 17 Feb 2015 11:14:53 +0100 Subject: [PATCH 120/201] minor fixes --- mix/qml/StateListModel.qml | 9 ++++++++- mix/qml/WebPreview.qml | 12 +++++++----- mix/qml/main.qml | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index da02ce5e6..52b0d542d 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -47,6 +47,10 @@ Item { varComponent = Qt.createComponent("qrc:/qml/QHashType.qml"); else if (type.indexOf("bool") !== -1) varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml"); + else { + console.log("Unknown parameter type: " + type); + continue; + } var param = varComponent.createObject(stateListModel); var dec = Qt.createComponent("qrc:/qml/QVariableDeclaration.qml"); @@ -203,7 +207,7 @@ Item { } function debugDefaultState() { - if (defaultStateIndex >= 0) + if (defaultStateIndex >= 0 && defaultStateIndex < stateList.length) runState(defaultStateIndex); } @@ -221,6 +225,9 @@ Item { defaultStateIndex = 0; defaultStateChanged(); } + else if (defaultStateIndex > index) + defaultStateIndex--; + save(); } diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index 9886a71c6..0d0d70d31 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -24,8 +24,10 @@ Item { } function reload() { - updateContract(); - webView.runJavaScript("reloadPage()"); + if (initialized) { + updateContract(); + webView.runJavaScript("reloadPage()"); + } } function updateContract() { @@ -33,9 +35,9 @@ Item { for (var c in codeModel.contracts) { var contract = codeModel.contracts[c]; contracts[c] = { - name: contract.contract.name, - address: clientModel.contractAddresses[contract.contract.name], - interface: JSON.parse(contract.contractInterface), + name: contract.contract.name, + address: clientModel.contractAddresses[contract.contract.name], + interface: JSON.parse(contract.contractInterface), }; } webView.runJavaScript("updateContracts(" + JSON.stringify(contracts) + ")"); diff --git a/mix/qml/main.qml b/mix/qml/main.qml index a1cf99de6..c9e8c8225 100644 --- a/mix/qml/main.qml +++ b/mix/qml/main.qml @@ -95,7 +95,7 @@ ApplicationWindow { text: qsTr("Mine") shortcut: "Ctrl+M" onTriggered: clientModel.mine(); - enabled: codeModel.hasContract && !clientModel.running &&!clientModel.mining + enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining } StateList { From a3278d1b117651751a9555038272c8a792ef1cf4 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 17 Feb 2015 11:17:47 +0100 Subject: [PATCH 121/201] Bug fix - mix: windows - crash when click on 'Deploy to Network' #1077 --- mix/main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mix/main.cpp b/mix/main.cpp index d0a19cfb5..8c5e7d046 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -36,6 +36,12 @@ int main(int _argc, char* _argv[]) //https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853 putenv((char*)"QT_QPA_PLATFORMTHEME="); putenv((char*)"QSG_RENDER_LOOP=threaded"); +#endif +#ifdef _WIN32 + putenv((char*)"OPENSSL_CONF=c:\\"); +#endif +#ifdef _WIN64 + putenv((char*)"OPENSSL_CONF=c:\\"); #endif try { From 11a381915ddb7f09d74c5ba08ae99b804ad489f6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 17 Feb 2015 12:26:42 +0100 Subject: [PATCH 122/201] Change WIN32 (WIN64) test. --- mix/main.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mix/main.cpp b/mix/main.cpp index 8c5e7d046..798520e39 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -37,11 +37,9 @@ int main(int _argc, char* _argv[]) putenv((char*)"QT_QPA_PLATFORMTHEME="); putenv((char*)"QSG_RENDER_LOOP=threaded"); #endif -#ifdef _WIN32 - putenv((char*)"OPENSSL_CONF=c:\\"); -#endif -#ifdef _WIN64 - putenv((char*)"OPENSSL_CONF=c:\\"); +#if (defined(_WIN32) || defined(_WIN64)) + if (!getenv("OPENSSL_CONF")) + putenv((char*)"OPENSSL_CONF=c:\\"); #endif try { From d9ebbfde48abf4d27d6c80aa9084fefed553317f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 17 Feb 2015 13:28:58 +0100 Subject: [PATCH 123/201] ManyFunctions performance test: replace xor with correct exp operator --- test/ManyFunctions.sol | 424 ++++++++++++++++-------------- test/ManyFunctionsGenerator.py | 4 +- test/vmPerformanceTestFiller.json | 2 +- 3 files changed, 229 insertions(+), 201 deletions(-) diff --git a/test/ManyFunctions.sol b/test/ManyFunctions.sol index 60dc61c42..691d98f46 100644 --- a/test/ManyFunctions.sol +++ b/test/ManyFunctions.sol @@ -1,14 +1,41 @@ +// Based on input param calls ~100 functions from ~200, random algorithm is really bad. +contract ManyFunctions { + + function start(uint seed) returns (uint) { + var r = nextRand(seed); + if (r >= 2**78) + return left1(r); + return right1(r); + } + + function finish(uint seed) returns (uint) { + return seed; + } + + function nextRand(uint seed) returns (uint) { + var a = 39948330534945941795786356397633709378407037920056054402537049186942880579585; + return a * seed + 1; + } + + function right100(uint seed) returns (uint) { + return finish(seed); + } + + function left100(uint seed) returns (uint) { + return finish(nextRand(seed)); + } + function right1(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^79) + if (r >= 2**79) return right2(r); return left2(r); } function left1(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^79) + if (r >= 2**79) return left2(r); return right2(r); } @@ -16,14 +43,14 @@ function right2(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^80) + if (r >= 2**80) return right3(r); return left3(r); } function left2(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^80) + if (r >= 2**80) return left3(r); return right3(r); } @@ -31,14 +58,14 @@ function right3(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^81) + if (r >= 2**81) return right4(r); return left4(r); } function left3(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^81) + if (r >= 2**81) return left4(r); return right4(r); } @@ -46,14 +73,14 @@ function right4(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^82) + if (r >= 2**82) return right5(r); return left5(r); } function left4(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^82) + if (r >= 2**82) return left5(r); return right5(r); } @@ -61,14 +88,14 @@ function right5(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^83) + if (r >= 2**83) return right6(r); return left6(r); } function left5(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^83) + if (r >= 2**83) return left6(r); return right6(r); } @@ -76,14 +103,14 @@ function right6(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^84) + if (r >= 2**84) return right7(r); return left7(r); } function left6(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^84) + if (r >= 2**84) return left7(r); return right7(r); } @@ -91,14 +118,14 @@ function right7(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^85) + if (r >= 2**85) return right8(r); return left8(r); } function left7(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^85) + if (r >= 2**85) return left8(r); return right8(r); } @@ -106,14 +133,14 @@ function right8(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^86) + if (r >= 2**86) return right9(r); return left9(r); } function left8(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^86) + if (r >= 2**86) return left9(r); return right9(r); } @@ -121,14 +148,14 @@ function right9(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^87) + if (r >= 2**87) return right10(r); return left10(r); } function left9(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^87) + if (r >= 2**87) return left10(r); return right10(r); } @@ -136,14 +163,14 @@ function right10(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^88) + if (r >= 2**88) return right11(r); return left11(r); } function left10(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^88) + if (r >= 2**88) return left11(r); return right11(r); } @@ -151,14 +178,14 @@ function right11(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^89) + if (r >= 2**89) return right12(r); return left12(r); } function left11(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^89) + if (r >= 2**89) return left12(r); return right12(r); } @@ -166,14 +193,14 @@ function right12(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^90) + if (r >= 2**90) return right13(r); return left13(r); } function left12(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^90) + if (r >= 2**90) return left13(r); return right13(r); } @@ -181,14 +208,14 @@ function right13(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^91) + if (r >= 2**91) return right14(r); return left14(r); } function left13(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^91) + if (r >= 2**91) return left14(r); return right14(r); } @@ -196,14 +223,14 @@ function right14(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^92) + if (r >= 2**92) return right15(r); return left15(r); } function left14(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^92) + if (r >= 2**92) return left15(r); return right15(r); } @@ -211,14 +238,14 @@ function right15(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^93) + if (r >= 2**93) return right16(r); return left16(r); } function left15(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^93) + if (r >= 2**93) return left16(r); return right16(r); } @@ -226,14 +253,14 @@ function right16(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^94) + if (r >= 2**94) return right17(r); return left17(r); } function left16(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^94) + if (r >= 2**94) return left17(r); return right17(r); } @@ -241,14 +268,14 @@ function right17(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^95) + if (r >= 2**95) return right18(r); return left18(r); } function left17(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^95) + if (r >= 2**95) return left18(r); return right18(r); } @@ -256,14 +283,14 @@ function right18(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^96) + if (r >= 2**96) return right19(r); return left19(r); } function left18(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^96) + if (r >= 2**96) return left19(r); return right19(r); } @@ -271,14 +298,14 @@ function right19(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^97) + if (r >= 2**97) return right20(r); return left20(r); } function left19(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^97) + if (r >= 2**97) return left20(r); return right20(r); } @@ -286,14 +313,14 @@ function right20(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^98) + if (r >= 2**98) return right21(r); return left21(r); } function left20(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^98) + if (r >= 2**98) return left21(r); return right21(r); } @@ -301,14 +328,14 @@ function right21(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^99) + if (r >= 2**99) return right22(r); return left22(r); } function left21(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^99) + if (r >= 2**99) return left22(r); return right22(r); } @@ -316,14 +343,14 @@ function right22(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^100) + if (r >= 2**100) return right23(r); return left23(r); } function left22(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^100) + if (r >= 2**100) return left23(r); return right23(r); } @@ -331,14 +358,14 @@ function right23(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^101) + if (r >= 2**101) return right24(r); return left24(r); } function left23(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^101) + if (r >= 2**101) return left24(r); return right24(r); } @@ -346,14 +373,14 @@ function right24(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^102) + if (r >= 2**102) return right25(r); return left25(r); } function left24(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^102) + if (r >= 2**102) return left25(r); return right25(r); } @@ -361,14 +388,14 @@ function right25(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^103) + if (r >= 2**103) return right26(r); return left26(r); } function left25(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^103) + if (r >= 2**103) return left26(r); return right26(r); } @@ -376,14 +403,14 @@ function right26(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^104) + if (r >= 2**104) return right27(r); return left27(r); } function left26(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^104) + if (r >= 2**104) return left27(r); return right27(r); } @@ -391,14 +418,14 @@ function right27(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^105) + if (r >= 2**105) return right28(r); return left28(r); } function left27(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^105) + if (r >= 2**105) return left28(r); return right28(r); } @@ -406,14 +433,14 @@ function right28(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^106) + if (r >= 2**106) return right29(r); return left29(r); } function left28(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^106) + if (r >= 2**106) return left29(r); return right29(r); } @@ -421,14 +448,14 @@ function right29(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^107) + if (r >= 2**107) return right30(r); return left30(r); } function left29(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^107) + if (r >= 2**107) return left30(r); return right30(r); } @@ -436,14 +463,14 @@ function right30(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^108) + if (r >= 2**108) return right31(r); return left31(r); } function left30(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^108) + if (r >= 2**108) return left31(r); return right31(r); } @@ -451,14 +478,14 @@ function right31(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^109) + if (r >= 2**109) return right32(r); return left32(r); } function left31(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^109) + if (r >= 2**109) return left32(r); return right32(r); } @@ -466,14 +493,14 @@ function right32(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^110) + if (r >= 2**110) return right33(r); return left33(r); } function left32(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^110) + if (r >= 2**110) return left33(r); return right33(r); } @@ -481,14 +508,14 @@ function right33(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^111) + if (r >= 2**111) return right34(r); return left34(r); } function left33(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^111) + if (r >= 2**111) return left34(r); return right34(r); } @@ -496,14 +523,14 @@ function right34(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^112) + if (r >= 2**112) return right35(r); return left35(r); } function left34(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^112) + if (r >= 2**112) return left35(r); return right35(r); } @@ -511,14 +538,14 @@ function right35(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^113) + if (r >= 2**113) return right36(r); return left36(r); } function left35(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^113) + if (r >= 2**113) return left36(r); return right36(r); } @@ -526,14 +553,14 @@ function right36(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^114) + if (r >= 2**114) return right37(r); return left37(r); } function left36(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^114) + if (r >= 2**114) return left37(r); return right37(r); } @@ -541,14 +568,14 @@ function right37(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^115) + if (r >= 2**115) return right38(r); return left38(r); } function left37(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^115) + if (r >= 2**115) return left38(r); return right38(r); } @@ -556,14 +583,14 @@ function right38(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^116) + if (r >= 2**116) return right39(r); return left39(r); } function left38(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^116) + if (r >= 2**116) return left39(r); return right39(r); } @@ -571,14 +598,14 @@ function right39(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^117) + if (r >= 2**117) return right40(r); return left40(r); } function left39(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^117) + if (r >= 2**117) return left40(r); return right40(r); } @@ -586,14 +613,14 @@ function right40(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^118) + if (r >= 2**118) return right41(r); return left41(r); } function left40(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^118) + if (r >= 2**118) return left41(r); return right41(r); } @@ -601,14 +628,14 @@ function right41(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^119) + if (r >= 2**119) return right42(r); return left42(r); } function left41(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^119) + if (r >= 2**119) return left42(r); return right42(r); } @@ -616,14 +643,14 @@ function right42(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^120) + if (r >= 2**120) return right43(r); return left43(r); } function left42(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^120) + if (r >= 2**120) return left43(r); return right43(r); } @@ -631,14 +658,14 @@ function right43(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^121) + if (r >= 2**121) return right44(r); return left44(r); } function left43(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^121) + if (r >= 2**121) return left44(r); return right44(r); } @@ -646,14 +673,14 @@ function right44(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^122) + if (r >= 2**122) return right45(r); return left45(r); } function left44(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^122) + if (r >= 2**122) return left45(r); return right45(r); } @@ -661,14 +688,14 @@ function right45(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^123) + if (r >= 2**123) return right46(r); return left46(r); } function left45(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^123) + if (r >= 2**123) return left46(r); return right46(r); } @@ -676,14 +703,14 @@ function right46(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^124) + if (r >= 2**124) return right47(r); return left47(r); } function left46(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^124) + if (r >= 2**124) return left47(r); return right47(r); } @@ -691,14 +718,14 @@ function right47(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^125) + if (r >= 2**125) return right48(r); return left48(r); } function left47(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^125) + if (r >= 2**125) return left48(r); return right48(r); } @@ -706,14 +733,14 @@ function right48(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^126) + if (r >= 2**126) return right49(r); return left49(r); } function left48(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^126) + if (r >= 2**126) return left49(r); return right49(r); } @@ -721,14 +748,14 @@ function right49(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^127) + if (r >= 2**127) return right50(r); return left50(r); } function left49(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^127) + if (r >= 2**127) return left50(r); return right50(r); } @@ -736,14 +763,14 @@ function right50(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^128) + if (r >= 2**128) return right51(r); return left51(r); } function left50(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^128) + if (r >= 2**128) return left51(r); return right51(r); } @@ -751,14 +778,14 @@ function right51(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^129) + if (r >= 2**129) return right52(r); return left52(r); } function left51(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^129) + if (r >= 2**129) return left52(r); return right52(r); } @@ -766,14 +793,14 @@ function right52(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^130) + if (r >= 2**130) return right53(r); return left53(r); } function left52(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^130) + if (r >= 2**130) return left53(r); return right53(r); } @@ -781,14 +808,14 @@ function right53(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^131) + if (r >= 2**131) return right54(r); return left54(r); } function left53(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^131) + if (r >= 2**131) return left54(r); return right54(r); } @@ -796,14 +823,14 @@ function right54(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^132) + if (r >= 2**132) return right55(r); return left55(r); } function left54(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^132) + if (r >= 2**132) return left55(r); return right55(r); } @@ -811,14 +838,14 @@ function right55(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^133) + if (r >= 2**133) return right56(r); return left56(r); } function left55(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^133) + if (r >= 2**133) return left56(r); return right56(r); } @@ -826,14 +853,14 @@ function right56(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^134) + if (r >= 2**134) return right57(r); return left57(r); } function left56(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^134) + if (r >= 2**134) return left57(r); return right57(r); } @@ -841,14 +868,14 @@ function right57(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^135) + if (r >= 2**135) return right58(r); return left58(r); } function left57(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^135) + if (r >= 2**135) return left58(r); return right58(r); } @@ -856,14 +883,14 @@ function right58(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^136) + if (r >= 2**136) return right59(r); return left59(r); } function left58(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^136) + if (r >= 2**136) return left59(r); return right59(r); } @@ -871,14 +898,14 @@ function right59(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^137) + if (r >= 2**137) return right60(r); return left60(r); } function left59(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^137) + if (r >= 2**137) return left60(r); return right60(r); } @@ -886,14 +913,14 @@ function right60(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^138) + if (r >= 2**138) return right61(r); return left61(r); } function left60(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^138) + if (r >= 2**138) return left61(r); return right61(r); } @@ -901,14 +928,14 @@ function right61(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^139) + if (r >= 2**139) return right62(r); return left62(r); } function left61(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^139) + if (r >= 2**139) return left62(r); return right62(r); } @@ -916,14 +943,14 @@ function right62(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^140) + if (r >= 2**140) return right63(r); return left63(r); } function left62(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^140) + if (r >= 2**140) return left63(r); return right63(r); } @@ -931,14 +958,14 @@ function right63(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^141) + if (r >= 2**141) return right64(r); return left64(r); } function left63(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^141) + if (r >= 2**141) return left64(r); return right64(r); } @@ -946,14 +973,14 @@ function right64(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^142) + if (r >= 2**142) return right65(r); return left65(r); } function left64(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^142) + if (r >= 2**142) return left65(r); return right65(r); } @@ -961,14 +988,14 @@ function right65(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^143) + if (r >= 2**143) return right66(r); return left66(r); } function left65(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^143) + if (r >= 2**143) return left66(r); return right66(r); } @@ -976,14 +1003,14 @@ function right66(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^144) + if (r >= 2**144) return right67(r); return left67(r); } function left66(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^144) + if (r >= 2**144) return left67(r); return right67(r); } @@ -991,14 +1018,14 @@ function right67(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^145) + if (r >= 2**145) return right68(r); return left68(r); } function left67(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^145) + if (r >= 2**145) return left68(r); return right68(r); } @@ -1006,14 +1033,14 @@ function right68(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^146) + if (r >= 2**146) return right69(r); return left69(r); } function left68(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^146) + if (r >= 2**146) return left69(r); return right69(r); } @@ -1021,14 +1048,14 @@ function right69(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^147) + if (r >= 2**147) return right70(r); return left70(r); } function left69(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^147) + if (r >= 2**147) return left70(r); return right70(r); } @@ -1036,14 +1063,14 @@ function right70(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^148) + if (r >= 2**148) return right71(r); return left71(r); } function left70(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^148) + if (r >= 2**148) return left71(r); return right71(r); } @@ -1051,14 +1078,14 @@ function right71(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^149) + if (r >= 2**149) return right72(r); return left72(r); } function left71(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^149) + if (r >= 2**149) return left72(r); return right72(r); } @@ -1066,14 +1093,14 @@ function right72(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^150) + if (r >= 2**150) return right73(r); return left73(r); } function left72(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^150) + if (r >= 2**150) return left73(r); return right73(r); } @@ -1081,14 +1108,14 @@ function right73(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^151) + if (r >= 2**151) return right74(r); return left74(r); } function left73(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^151) + if (r >= 2**151) return left74(r); return right74(r); } @@ -1096,14 +1123,14 @@ function right74(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^152) + if (r >= 2**152) return right75(r); return left75(r); } function left74(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^152) + if (r >= 2**152) return left75(r); return right75(r); } @@ -1111,14 +1138,14 @@ function right75(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^153) + if (r >= 2**153) return right76(r); return left76(r); } function left75(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^153) + if (r >= 2**153) return left76(r); return right76(r); } @@ -1126,14 +1153,14 @@ function right76(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^154) + if (r >= 2**154) return right77(r); return left77(r); } function left76(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^154) + if (r >= 2**154) return left77(r); return right77(r); } @@ -1141,14 +1168,14 @@ function right77(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^155) + if (r >= 2**155) return right78(r); return left78(r); } function left77(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^155) + if (r >= 2**155) return left78(r); return right78(r); } @@ -1156,14 +1183,14 @@ function right78(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^156) + if (r >= 2**156) return right79(r); return left79(r); } function left78(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^156) + if (r >= 2**156) return left79(r); return right79(r); } @@ -1171,14 +1198,14 @@ function right79(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^157) + if (r >= 2**157) return right80(r); return left80(r); } function left79(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^157) + if (r >= 2**157) return left80(r); return right80(r); } @@ -1186,14 +1213,14 @@ function right80(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^158) + if (r >= 2**158) return right81(r); return left81(r); } function left80(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^158) + if (r >= 2**158) return left81(r); return right81(r); } @@ -1201,14 +1228,14 @@ function right81(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^159) + if (r >= 2**159) return right82(r); return left82(r); } function left81(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^159) + if (r >= 2**159) return left82(r); return right82(r); } @@ -1216,14 +1243,14 @@ function right82(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^160) + if (r >= 2**160) return right83(r); return left83(r); } function left82(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^160) + if (r >= 2**160) return left83(r); return right83(r); } @@ -1231,14 +1258,14 @@ function right83(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^161) + if (r >= 2**161) return right84(r); return left84(r); } function left83(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^161) + if (r >= 2**161) return left84(r); return right84(r); } @@ -1246,14 +1273,14 @@ function right84(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^162) + if (r >= 2**162) return right85(r); return left85(r); } function left84(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^162) + if (r >= 2**162) return left85(r); return right85(r); } @@ -1261,14 +1288,14 @@ function right85(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^163) + if (r >= 2**163) return right86(r); return left86(r); } function left85(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^163) + if (r >= 2**163) return left86(r); return right86(r); } @@ -1276,14 +1303,14 @@ function right86(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^164) + if (r >= 2**164) return right87(r); return left87(r); } function left86(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^164) + if (r >= 2**164) return left87(r); return right87(r); } @@ -1291,14 +1318,14 @@ function right87(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^165) + if (r >= 2**165) return right88(r); return left88(r); } function left87(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^165) + if (r >= 2**165) return left88(r); return right88(r); } @@ -1306,14 +1333,14 @@ function right88(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^166) + if (r >= 2**166) return right89(r); return left89(r); } function left88(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^166) + if (r >= 2**166) return left89(r); return right89(r); } @@ -1321,14 +1348,14 @@ function right89(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^167) + if (r >= 2**167) return right90(r); return left90(r); } function left89(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^167) + if (r >= 2**167) return left90(r); return right90(r); } @@ -1336,14 +1363,14 @@ function right90(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^168) + if (r >= 2**168) return right91(r); return left91(r); } function left90(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^168) + if (r >= 2**168) return left91(r); return right91(r); } @@ -1351,14 +1378,14 @@ function right91(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^169) + if (r >= 2**169) return right92(r); return left92(r); } function left91(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^169) + if (r >= 2**169) return left92(r); return right92(r); } @@ -1366,14 +1393,14 @@ function right92(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^170) + if (r >= 2**170) return right93(r); return left93(r); } function left92(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^170) + if (r >= 2**170) return left93(r); return right93(r); } @@ -1381,14 +1408,14 @@ function right93(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^171) + if (r >= 2**171) return right94(r); return left94(r); } function left93(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^171) + if (r >= 2**171) return left94(r); return right94(r); } @@ -1396,14 +1423,14 @@ function right94(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^172) + if (r >= 2**172) return right95(r); return left95(r); } function left94(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^172) + if (r >= 2**172) return left95(r); return right95(r); } @@ -1411,14 +1438,14 @@ function right95(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^173) + if (r >= 2**173) return right96(r); return left96(r); } function left95(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^173) + if (r >= 2**173) return left96(r); return right96(r); } @@ -1426,14 +1453,14 @@ function right96(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^174) + if (r >= 2**174) return right97(r); return left97(r); } function left96(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^174) + if (r >= 2**174) return left97(r); return right97(r); } @@ -1441,14 +1468,14 @@ function right97(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^175) + if (r >= 2**175) return right98(r); return left98(r); } function left97(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^175) + if (r >= 2**175) return left98(r); return right98(r); } @@ -1456,14 +1483,14 @@ function right98(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^176) + if (r >= 2**176) return right99(r); return left99(r); } function left98(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^176) + if (r >= 2**176) return left99(r); return right99(r); } @@ -1471,15 +1498,16 @@ function right99(uint seed) returns (uint) { var r = nextRand(seed); - if (r >= 2^177) + if (r >= 2**177) return right100(r); return left100(r); } function left99(uint seed) returns (uint) { var r = nextRand(nextRand(seed)); - if (r >= 2^177) + if (r >= 2**177) return left100(r); return right100(r); } +} \ No newline at end of file diff --git a/test/ManyFunctionsGenerator.py b/test/ManyFunctionsGenerator.py index 93eef784c..b4f36af0e 100644 --- a/test/ManyFunctionsGenerator.py +++ b/test/ManyFunctionsGenerator.py @@ -7,14 +7,14 @@ i = 1 template = """ function right{0}(uint seed) returns (uint) {{ var r = nextRand(seed); - if (r >= 2^{2}) + if (r >= 2**{2}) return right{1}(r); return left{1}(r); }} function left{0}(uint seed) returns (uint) {{ var r = nextRand(nextRand(seed)); - if (r >= 2^{2}) + if (r >= 2**{2}) return left{1}(r); return right{1}(r); }} diff --git a/test/vmPerformanceTestFiller.json b/test/vmPerformanceTestFiller.json index eab8a2240..e33bd1955 100644 --- a/test/vmPerformanceTestFiller.json +++ b/test/vmPerformanceTestFiller.json @@ -13,7 +13,7 @@ "balance" : "1000000000000000000", "nonce" : "0", "//" : "ManyFunctions.sol", - "code" : "0x60e060020a60003504806301f99ad7146108c3578063023a624a146108d857806303bdecf5146108ed57806305fe035f14610902578063082d8f4914610917578063090bf3b71461092c5780630bd9c534146109415780630c4bfa94146109565780630e20ebe21461096b5780630f76de0d1461098057806310cfcc191461099557806313ce15a9146109aa578063140dcec4146109bf57806314d07a3e146109d45780631687f112146109e957806316eb6603146109fe578063172cf71714610a135780631bd6f59614610a285780631cdb857114610a3d5780631cf74ece14610a525780631d09ba2c14610a675780631f69aa5114610a7c578063223dcc7414610a9157806325e524d314610aa6578063261de7c414610abb5780632632924d14610ad05780632909cc5d14610ae55780632981699814610afa5780632a85a45d14610b0f5780632ca36da014610b245780632cbf1f0d14610b395780632d0f557314610b4e5780632d97867814610b6357806331db9efd14610b7857806332064db714610b8d57806332931fbb14610ba2578063355f51a014610bb7578063361bb34014610bcc578063364ddb0e14610be15780633792a01814610bf657806338c68f8f14610c0b57806338e586fd14610c20578063392d42ae14610c3557806339a87bd914610c4a5780633a95a33214610c5f5780633b8ecdf914610c745780633cf0659a14610c895780633eaf992314610c9e5780633fe97ead14610cb35780633ff11c8b14610cc8578063404efc5314610cdd578063407fce7b14610cf257806340c3b18714610d07578063440208c314610d1c57806344e86b2f14610d31578063455df57914610d465780634689ab4d14610d5b57806346be2e0c14610d70578063487cd86f14610d8557806348e6178214610d9a57806349d4a34414610daf5780634a0f597414610dc45780634bc24ec514610dd95780634c2fe45614610dee5780634cc885d414610e035780634eaaad7b14610e185780634eb166af14610e2d5780635050093414610e42578063506bff1114610e57578063508762c114610e6c578063526938f814610e8157806354400c6014610e96578063559510d814610eab57806355a5f70214610ec057806356ca528f14610ed5578063570a2a1614610eea5780635dab2e0f14610eff5780635dca53d314610f1457806362017ebc14610f29578063621a25f814610f3e578063626d4a3614610f5357806362b6a28214610f6857806364faf22c14610f7d57806366d7ffde14610f9257806367b886e814610fa757806367e902c714610fbc57806369d7774014610fd15780636b7ae8e614610fe65780636c3b659114610ffb5780636e54181e146110105780636e978d91146110255780636f63d2ec1461103a578063706332d11461104f57806370ac4bb9146110645780637138ef521461107957806371dd46a91461108e57806372a7c229146110a35780637376fc8d146110b8578063738a2679146110cd57806374552650146110e2578063746fc8d0146110f757806379254bb81461110c5780637adaa3f8146111215780637e4eb35b14611136578063885ec18e1461114b5780638b9ff6b6146111605780638ce113dc146111755780638defbc5e1461118a5780638f4613d51461119f5780638fdc24ba146111b45780639002dba4146111c957806391d15735146111de57806391d43b23146111f357806393b14daa1461120857806394d63afd1461121d57806395805dad1461123257806396f68782146112475780639740e4a21461125c578063981290131461127157806399a3f0e8146112865780639acb1ad41461129b5780639be07908146112b05780639c15be0b146112c55780639d451c4d146112da5780639d8ee943146112ef5780639ef6ca0f14611304578063a0db0a2214611319578063a18e2eb91461132e578063a408384914611343578063a57544da14611358578063a5a83e4d1461136d578063a6843f3414611382578063a6dacdd714611397578063a8c4c8bc146113ac578063aa058a73146113c1578063aad62da2146113d6578063aaf3e4f4146113eb578063ab81e77314611400578063abc93aee14611415578063abde33f71461142a578063b114b96c1461143f578063b3df873714611454578063b4174cb014611469578063b5d02a561461147e578063b731e84814611493578063b7b96723146114a8578063bbcded7a146114bd578063bbececa9146114d2578063beca7440146114e7578063bf8981c0146114fc578063c028c67414611511578063c2385fa614611526578063c319a02c1461153b578063c569bae014611550578063c6715f8114611565578063c7b98dec1461157a578063c9acab841461158f578063ca9efc73146115a4578063cad80024146115b9578063cdadb0fa146115ce578063cdbdf391146115e3578063cf460fa5146115f8578063cf69318a1461160d578063d1835b8c14611622578063d353a1cb14611637578063d3e141e01461164c578063d5ec7e1d14611661578063d7ead1de14611676578063d90b02aa1461168b578063d959e244146116a0578063d9e68b44146116b5578063daacb24f146116ca578063dc12a805146116df578063dd946033146116f4578063dda5142414611709578063de6612171461171e578063dfb9560c14611733578063e03827d214611748578063e21720001461175d578063e2c718d814611772578063e3da539914611787578063e48e603f1461179c578063e5f9ec29146117b1578063e6c0459a146117c6578063e70addec146117db578063e7a01215146117f0578063ea7f4d2714611805578063ebb6c59f1461181a578063ed6302be1461182f578063ed64b36b14611844578063eecd278914611859578063f0ed14e01461186e578063f0f2134414611883578063f1e328f914611898578063f1e6f4cd146118ad578063f32fe995146118c2578063f75165c6146118d7578063f7ed71d0146118ec578063f80f44f314611901578063f8bc050514611916578063fbd3c51a1461192b578063fd72009014611940578063fed3a3001461195557005b6108ce600435611e83565b8060005260206000f35b6108e3600435611f50565b8060005260206000f35b6108f8600435613deb565b8060005260206000f35b61090d6004356119e8565b8060005260206000f35b610922600435612f82565b8060005260206000f35b6109376004356128fb565b8060005260206000f35b61094c60043561304f565b8060005260206000f35b61096160043561209b565b8060005260206000f35b610976600435614c0d565b8060005260206000f35b61098b60043561319a565b8060005260206000f35b6109a06004356122b3565b8060005260206000f35b6109b5600435613d1e565b8060005260206000f35b6109ca600435612598565b8060005260206000f35b6109df600435612875565b8060005260206000f35b6109f4600435613650565b8060005260206000f35b610a096004356133f9565b8060005260206000f35b610a1e6004356136d6565b8060005260206000f35b610a3360043561371d565b8060005260206000f35b610a48600435611ad9565b8060005260206000f35b610a5d60043561375c565b8060005260206000f35b610a72600435612168565b8060005260206000f35b610a8760043561425a565b8060005260206000f35b610a9c600435612121565b8060005260206000f35b610ab1600435611dbe565b8060005260206000f35b610ac6600435612b13565b8060005260206000f35b610adb600435612981565b8060005260206000f35b610af060043561222d565b8060005260206000f35b610b05600435613ac7565b8060005260206000f35b610b1a600435612db1565b8060005260206000f35b610b2f600435612e76565b8060005260206000f35b610b44600435613a80565b8060005260206000f35b610b59600435612c1f565b8060005260206000f35b610b6e6004356125d7565b8060005260206000f35b610b836004356147dd565b8060005260206000f35b610b98600435612445565b8060005260206000f35b610bad600435611a53565b8060005260206000f35b610bc2600435613373565b8060005260206000f35b610bd760043561332c565b8060005260206000f35b610bec600435613544565b8060005260206000f35b610c01600435611dfd565b8060005260206000f35b610c166004356145c5565b8060005260206000f35b610c2b600435611c2c565b8060005260206000f35b610c40600435612df0565b8060005260206000f35b610c55600435612a46565b8060005260206000f35b610c6a6004356137e2565b8060005260206000f35b610c7f600435611b20565b8060005260206000f35b610c946004356126a4565b8060005260206000f35b610ca9600435613d65565b8060005260206000f35b610cbe6004356133b2565b8060005260206000f35b610cd360043561464b565b8060005260206000f35b610ce8600435612769565b8060005260206000f35b610cfd600435612015565b8060005260206000f35b610d12600435612d6a565b8060005260206000f35b610d27600435611fd6565b8060005260206000f35b610d3c600435613f36565b8060005260206000f35b610d51600435614604565b8060005260206000f35b610d6660043561248c565b8060005260206000f35b610d7b600435612acc565b8060005260206000f35b610d90600435612b99565b8060005260206000f35b610da5600435611be5565b8060005260206000f35b610dba6004356129c8565b8060005260206000f35b610dcf6004356127ef565b8060005260206000f35b610de46004356139bb565b8060005260206000f35b610df9600435614b01565b8060005260206000f35b610e0e600435613bd3565b8060005260206000f35b610e23600435613fbc565b8060005260206000f35b610e38600435614003565b8060005260206000f35b610e4d600435612836565b8060005260206000f35b610e62600435611d77565b8060005260206000f35b610e77600435611eca565b8060005260206000f35b610e8c600435612c5e565b8060005260206000f35b610ea1600435612380565b8060005260206000f35b610eb66004356135ca565b8060005260206000f35b610ecb60043561315b565b8060005260206000f35b610ee06004356122fa565b8060005260206000f35b610ef560043561358b565b8060005260206000f35b610f0a6004356144f8565b8060005260206000f35b610f1f600435612942565b8060005260206000f35b610f34600435613220565b8060005260206000f35b610f49600435613c59565b8060005260206000f35b610f5e600435613697565b8060005260206000f35b610f73600435613008565b8060005260206000f35b610f88600435612339565b8060005260206000f35b610f9d60043561265d565b8060005260206000f35b610fb2600435614cd2565b8060005260206000f35b610fc76004356149f5565b8060005260206000f35b610fdc600435614a34565b8060005260206000f35b610ff16004356140c8565b8060005260206000f35b61100660043561453f565b8060005260206000f35b61101b60043561410f565b8060005260206000f35b6110306004356148e9565b8060005260206000f35b611045600435613c98565b8060005260206000f35b61105a6004356131e1565b8060005260206000f35b61106f600435612a8d565b8060005260206000f35b611084600435611e44565b8060005260206000f35b6110996004356123bf565b8060005260206000f35b6110ae600435612f43565b8060005260206000f35b6110c3600435613cdf565b8060005260206000f35b6110d860043561468a565b8060005260206000f35b6110ed600435614bc6565b8060005260206000f35b611102600435613267565b8060005260206000f35b6111176004356128bc565b8060005260206000f35b61112c600435612e37565b8060005260206000f35b61114160043561308e565b8060005260206000f35b611156600435611cf1565b8060005260206000f35b61116b6004356149ae565b8060005260206000f35b611180600435613935565b8060005260206000f35b611195600435612a07565b8060005260206000f35b6111aa600435611f09565b8060005260206000f35b6111bf600435614b40565b8060005260206000f35b6111d4600435612274565b8060005260206000f35b6111e9600435611f8f565b8060005260206000f35b6111fe600435614195565b8060005260206000f35b6112136004356120e2565b8060005260206000f35b611228600435611b5f565b8060005260206000f35b61123d60043561196a565b8060005260206000f35b611252600435613a41565b8060005260206000f35b611267600435614796565b8060005260206000f35b61127c6004356132a6565b8060005260206000f35b611291600435613e71565b8060005260206000f35b6112a6600435612d2b565b8060005260206000f35b6112bb600435614366565b8060005260206000f35b6112d0600435613c12565b8060005260206000f35b6112e560043561421b565b8060005260206000f35b6112fa600435613ef7565b8060005260206000f35b61130f600435612b52565b8060005260206000f35b611324600435611ba6565b8060005260206000f35b611339600435613e2a565b8060005260206000f35b61134e6004356130d5565b8060005260206000f35b611363600435612ca5565b8060005260206000f35b61137860043561496f565b8060005260206000f35b61138d6004356132ed565b8060005260206000f35b6113a26004356138af565b8060005260206000f35b6113b7600435613b4d565b8060005260206000f35b6113cc600435611cb2565b8060005260206000f35b6113e16004356148a2565b8060005260206000f35b6113f660043561481c565b8060005260206000f35b61140b6004356139fa565b8060005260206000f35b611420600435613b8c565b8060005260206000f35b61143560043561272a565b8060005260206000f35b61144a600435614d9f565b8060005260206000f35b61145f600435613438565b8060005260206000f35b61147460043561347f565b8060005260206000f35b6114896004356119b3565b8060005260206000f35b61149e600435614aba565b8060005260206000f35b6114b3600435611d38565b8060005260206000f35b6114c8600435614042565b8060005260206000f35b6114dd6004356142e0565b8060005260206000f35b6114f2600435613505565b8060005260206000f35b611507600435612ce4565b8060005260206000f35b61151c6004356144b9565b8060005260206000f35b6115316004356142a1565b8060005260206000f35b611546600435614d19565b8060005260206000f35b61155b600435614a7b565b8060005260206000f35b611570600435613114565b8060005260206000f35b611585600435611a14565b8060005260206000f35b61159a6004356138ee565b8060005260206000f35b6115af600435614472565b8060005260206000f35b6115c4600435613868565b8060005260206000f35b6115d9600435613829565b8060005260206000f35b6115ee600435612bd8565b8060005260206000f35b6116036004356121ee565b8060005260206000f35b611618600435613974565b8060005260206000f35b61162d6004356124cb565b8060005260206000f35b6116426004356119a9565b8060005260206000f35b611657600435611c6b565b8060005260206000f35b61166c600435612551565b8060005260206000f35b611681600435614089565b8060005260206000f35b6116966004356143ec565b8060005260206000f35b6116ab6004356126e3565b8060005260206000f35b6116c06004356119fa565b8060005260206000f35b6116d5600435612fc9565b8060005260206000f35b6116ea6004356137a3565b8060005260206000f35b6116ff600435614433565b8060005260206000f35b6117146004356143ad565b8060005260206000f35b61172960043561414e565b8060005260206000f35b61173e60043561261e565b8060005260206000f35b611753600435613eb0565b8060005260206000f35b611768600435613b06565b8060005260206000f35b61177d600435612406565b8060005260206000f35b611792600435614928565b8060005260206000f35b6117a7600435613611565b8060005260206000f35b6117bc6004356134be565b8060005260206000f35b6117d1600435614327565b8060005260206000f35b6117e6600435614757565b8060005260206000f35b6117fb600435611a9a565b8060005260206000f35b61181060043561205c565b8060005260206000f35b611825600435613f7d565b8060005260206000f35b61183a600435614d58565b8060005260206000f35b61184f6004356121a7565b8060005260206000f35b611864600435614710565b8060005260206000f35b611879600435614b87565b8060005260206000f35b61188e6004356127b0565b8060005260206000f35b6118a3600435613da4565b8060005260206000f35b6118b8600435612ebd565b8060005260206000f35b6118cd600435614c4c565b8060005260206000f35b6118e2600435612512565b8060005260206000f35b6118f7600435612efc565b8060005260206000f35b61190c600435614c93565b8060005260206000f35b6119216004356141d4565b8060005260206000f35b61193660043561457e565b8060005260206000f35b61194b6004356146d1565b8060005260206000f35b611960600435614863565b8060005260206000f35b60006000611977836119b3565b9050604c81101561198757611997565b61199081611a53565b91506119a3565b6119a081611a14565b91505b50919050565b6000819050919050565b600060007f5851f42d4c957f2c0000000000000000000000000000000000000000000000019050828102600101915050919050565b60006119f3826119a9565b9050919050565b6000611a0d611a08836119b3565b6119a9565b9050919050565b60006000611a21836119b3565b9050604d811015611a3157611a41565b611a3a81611a9a565b9150611a4d565b611a4a81611ad9565b91505b50919050565b60006000611a68611a63846119b3565b6119b3565b9050604d811015611a7857611a88565b611a8181611ad9565b9150611a94565b611a9181611a9a565b91505b50919050565b60006000611aa7836119b3565b90506052811015611ab757611ac7565b611ac081611b20565b9150611ad3565b611ad081611b5f565b91505b50919050565b60006000611aee611ae9846119b3565b6119b3565b90506052811015611afe57611b0e565b611b0781611b5f565b9150611b1a565b611b1781611b20565b91505b50919050565b60006000611b2d836119b3565b90506053811015611b3d57611b4d565b611b4681611ba6565b9150611b59565b611b5681611be5565b91505b50919050565b60006000611b74611b6f846119b3565b6119b3565b90506053811015611b8457611b94565b611b8d81611be5565b9150611ba0565b611b9d81611ba6565b91505b50919050565b60006000611bb3836119b3565b90506050811015611bc357611bd3565b611bcc81611c2c565b9150611bdf565b611bdc81611c6b565b91505b50919050565b60006000611bfa611bf5846119b3565b6119b3565b90506050811015611c0a57611c1a565b611c1381611c6b565b9150611c26565b611c2381611c2c565b91505b50919050565b60006000611c39836119b3565b90506051811015611c4957611c59565b611c5281611cb2565b9150611c65565b611c6281611cf1565b91505b50919050565b60006000611c80611c7b846119b3565b6119b3565b90506051811015611c9057611ca0565b611c9981611cf1565b9150611cac565b611ca981611cb2565b91505b50919050565b60006000611cbf836119b3565b90506056811015611ccf57611cdf565b611cd881611d38565b9150611ceb565b611ce881611d77565b91505b50919050565b60006000611d06611d01846119b3565b6119b3565b90506056811015611d1657611d26565b611d1f81611d77565b9150611d32565b611d2f81611d38565b91505b50919050565b60006000611d45836119b3565b90506057811015611d5557611d65565b611d5e81611dbe565b9150611d71565b611d6e81611dfd565b91505b50919050565b60006000611d8c611d87846119b3565b6119b3565b90506057811015611d9c57611dac565b611da581611dfd565b9150611db8565b611db581611dbe565b91505b50919050565b60006000611dcb836119b3565b90506054811015611ddb57611deb565b611de481611e44565b9150611df7565b611df481611e83565b91505b50919050565b60006000611e12611e0d846119b3565b6119b3565b90506054811015611e2257611e32565b611e2b81611e83565b9150611e3e565b611e3b81611e44565b91505b50919050565b60006000611e51836119b3565b90506055811015611e6157611e71565b611e6a81611eca565b9150611e7d565b611e7a81611f09565b91505b50919050565b60006000611e98611e93846119b3565b6119b3565b90506055811015611ea857611eb8565b611eb181611f09565b9150611ec4565b611ec181611eca565b91505b50919050565b60006000611ed7836119b3565b9050605a811015611ee757611ef7565b611ef081611f50565b9150611f03565b611f0081611f8f565b91505b50919050565b60006000611f1e611f19846119b3565b6119b3565b9050605a811015611f2e57611f3e565b611f3781611f8f565b9150611f4a565b611f4781611f50565b91505b50919050565b60006000611f5d836119b3565b9050605b811015611f6d57611f7d565b611f7681611fd6565b9150611f89565b611f8681612015565b91505b50919050565b60006000611fa4611f9f846119b3565b6119b3565b9050605b811015611fb457611fc4565b611fbd81612015565b9150611fd0565b611fcd81611fd6565b91505b50919050565b60006000611fe3836119b3565b90506058811015611ff357612003565b611ffc8161205c565b915061200f565b61200c8161209b565b91505b50919050565b6000600061202a612025846119b3565b6119b3565b9050605881101561203a5761204a565b6120438161209b565b9150612056565b6120538161205c565b91505b50919050565b60006000612069836119b3565b9050605981101561207957612089565b612082816120e2565b9150612095565b61209281612121565b91505b50919050565b600060006120b06120ab846119b3565b6119b3565b905060598110156120c0576120d0565b6120c981612121565b91506120dc565b6120d9816120e2565b91505b50919050565b600060006120ef836119b3565b9050605e8110156120ff5761210f565b61210881612168565b915061211b565b612118816121a7565b91505b50919050565b60006000612136612131846119b3565b6119b3565b9050605e81101561214657612156565b61214f816121a7565b9150612162565b61215f81612168565b91505b50919050565b60006000612175836119b3565b9050605f81101561218557612195565b61218e816121ee565b91506121a1565b61219e8161222d565b91505b50919050565b600060006121bc6121b7846119b3565b6119b3565b9050605f8110156121cc576121dc565b6121d58161222d565b91506121e8565b6121e5816121ee565b91505b50919050565b600060006121fb836119b3565b9050605c81101561220b5761221b565b61221481612274565b9150612227565b612224816122b3565b91505b50919050565b6000600061224261223d846119b3565b6119b3565b9050605c81101561225257612262565b61225b816122b3565b915061226e565b61226b81612274565b91505b50919050565b60006000612281836119b3565b9050605d811015612291576122a1565b61229a816122fa565b91506122ad565b6122aa81612339565b91505b50919050565b600060006122c86122c3846119b3565b6119b3565b9050605d8110156122d8576122e8565b6122e181612339565b91506122f4565b6122f1816122fa565b91505b50919050565b60006000612307836119b3565b9050606281101561231757612327565b61232081612380565b9150612333565b612330816123bf565b91505b50919050565b6000600061234e612349846119b3565b6119b3565b9050606281101561235e5761236e565b612367816123bf565b915061237a565b61237781612380565b91505b50919050565b6000600061238d836119b3565b9050606381101561239d576123ad565b6123a681612406565b91506123b9565b6123b681612445565b91505b50919050565b600060006123d46123cf846119b3565b6119b3565b905060638110156123e4576123f4565b6123ed81612445565b9150612400565b6123fd81612406565b91505b50919050565b60006000612413836119b3565b9050606081101561242357612433565b61242c8161248c565b915061243f565b61243c816124cb565b91505b50919050565b6000600061245a612455846119b3565b6119b3565b9050606081101561246a5761247a565b612473816124cb565b9150612486565b6124838161248c565b91505b50919050565b60006000612499836119b3565b905060618110156124a9576124b9565b6124b281612512565b91506124c5565b6124c281612551565b91505b50919050565b600060006124e06124db846119b3565b6119b3565b905060618110156124f057612500565b6124f981612551565b915061250c565b61250981612512565b91505b50919050565b6000600061251f836119b3565b9050606681101561252f5761253f565b61253881612598565b915061254b565b612548816125d7565b91505b50919050565b60006000612566612561846119b3565b6119b3565b9050606681101561257657612586565b61257f816125d7565b9150612592565b61258f81612598565b91505b50919050565b600060006125a5836119b3565b905060678110156125b5576125c5565b6125be8161261e565b91506125d1565b6125ce8161265d565b91505b50919050565b600060006125ec6125e7846119b3565b6119b3565b905060678110156125fc5761260c565b6126058161265d565b9150612618565b6126158161261e565b91505b50919050565b6000600061262b836119b3565b9050606481101561263b5761264b565b612644816126a4565b9150612657565b612654816126e3565b91505b50919050565b6000600061267261266d846119b3565b6119b3565b9050606481101561268257612692565b61268b816126e3565b915061269e565b61269b816126a4565b91505b50919050565b600060006126b1836119b3565b905060658110156126c1576126d1565b6126ca8161272a565b91506126dd565b6126da81612769565b91505b50919050565b600060006126f86126f3846119b3565b6119b3565b9050606581101561270857612718565b61271181612769565b9150612724565b6127218161272a565b91505b50919050565b60006000612737836119b3565b9050606a81101561274757612757565b612750816127b0565b9150612763565b612760816127ef565b91505b50919050565b6000600061277e612779846119b3565b6119b3565b9050606a81101561278e5761279e565b612797816127ef565b91506127aa565b6127a7816127b0565b91505b50919050565b600060006127bd836119b3565b9050606b8110156127cd576127dd565b6127d681612836565b91506127e9565b6127e681612875565b91505b50919050565b600060006128046127ff846119b3565b6119b3565b9050606b81101561281457612824565b61281d81612875565b9150612830565b61282d81612836565b91505b50919050565b60006000612843836119b3565b9050606881101561285357612863565b61285c816128bc565b915061286f565b61286c816128fb565b91505b50919050565b6000600061288a612885846119b3565b6119b3565b9050606881101561289a576128aa565b6128a3816128fb565b91506128b6565b6128b3816128bc565b91505b50919050565b600060006128c9836119b3565b905060698110156128d9576128e9565b6128e281612942565b91506128f5565b6128f281612981565b91505b50919050565b6000600061291061290b846119b3565b6119b3565b9050606981101561292057612930565b61292981612981565b915061293c565b61293981612942565b91505b50919050565b6000600061294f836119b3565b9050606e81101561295f5761296f565b61296881612a07565b915061297b565b61297881612a46565b91505b50919050565b60006000612996612991846119b3565b6119b3565b9050606e8110156129a6576129b6565b6129af81612a46565b91506129c2565b6129bf81612a07565b91505b50919050565b600060006129d5836119b3565b905060b38110156129e5576129f5565b6129ee816119e8565b9150612a01565b6129fe816119fa565b91505b50919050565b60006000612a14836119b3565b9050606f811015612a2457612a34565b612a2d81612a8d565b9150612a40565b612a3d81612acc565b91505b50919050565b60006000612a5b612a56846119b3565b6119b3565b9050606f811015612a6b57612a7b565b612a7481612acc565b9150612a87565b612a8481612a8d565b91505b50919050565b60006000612a9a836119b3565b9050606c811015612aaa57612aba565b612ab381612b13565b9150612ac6565b612ac381612b52565b91505b50919050565b60006000612ae1612adc846119b3565b6119b3565b9050606c811015612af157612b01565b612afa81612b52565b9150612b0d565b612b0a81612b13565b91505b50919050565b60006000612b20836119b3565b9050606d811015612b3057612b40565b612b3981612b99565b9150612b4c565b612b4981612bd8565b91505b50919050565b60006000612b67612b62846119b3565b6119b3565b9050606d811015612b7757612b87565b612b8081612bd8565b9150612b93565b612b9081612b99565b91505b50919050565b60006000612ba6836119b3565b90506072811015612bb657612bc6565b612bbf81612c1f565b9150612bd2565b612bcf81612c5e565b91505b50919050565b60006000612bed612be8846119b3565b6119b3565b90506072811015612bfd57612c0d565b612c0681612c5e565b9150612c19565b612c1681612c1f565b91505b50919050565b60006000612c2c836119b3565b90506073811015612c3c57612c4c565b612c4581612ca5565b9150612c58565b612c5581612ce4565b91505b50919050565b60006000612c73612c6e846119b3565b6119b3565b90506073811015612c8357612c93565b612c8c81612ce4565b9150612c9f565b612c9c81612ca5565b91505b50919050565b60006000612cb2836119b3565b90506070811015612cc257612cd2565b612ccb81612d2b565b9150612cde565b612cdb81612d6a565b91505b50919050565b60006000612cf9612cf4846119b3565b6119b3565b90506070811015612d0957612d19565b612d1281612d6a565b9150612d25565b612d2281612d2b565b91505b50919050565b60006000612d38836119b3565b90506071811015612d4857612d58565b612d5181612db1565b9150612d64565b612d6181612df0565b91505b50919050565b60006000612d7f612d7a846119b3565b6119b3565b90506071811015612d8f57612d9f565b612d9881612df0565b9150612dab565b612da881612db1565b91505b50919050565b60006000612dbe836119b3565b90506076811015612dce57612dde565b612dd781612e37565b9150612dea565b612de781612e76565b91505b50919050565b60006000612e05612e00846119b3565b6119b3565b90506076811015612e1557612e25565b612e1e81612e76565b9150612e31565b612e2e81612e37565b91505b50919050565b60006000612e44836119b3565b90506077811015612e5457612e64565b612e5d81612ebd565b9150612e70565b612e6d81612efc565b91505b50919050565b60006000612e8b612e86846119b3565b6119b3565b90506077811015612e9b57612eab565b612ea481612efc565b9150612eb7565b612eb481612ebd565b91505b50919050565b60006000612eca836119b3565b90506074811015612eda57612eea565b612ee381612f43565b9150612ef6565b612ef381612f82565b91505b50919050565b60006000612f11612f0c846119b3565b6119b3565b90506074811015612f2157612f31565b612f2a81612f82565b9150612f3d565b612f3a81612f43565b91505b50919050565b60006000612f50836119b3565b90506075811015612f6057612f70565b612f6981612fc9565b9150612f7c565b612f7981613008565b91505b50919050565b60006000612f97612f92846119b3565b6119b3565b90506075811015612fa757612fb7565b612fb081613008565b9150612fc3565b612fc081612fc9565b91505b50919050565b60006000612fd6836119b3565b9050607a811015612fe657612ff6565b612fef8161304f565b9150613002565b612fff8161308e565b91505b50919050565b6000600061301d613018846119b3565b6119b3565b9050607a81101561302d5761303d565b6130368161308e565b9150613049565b6130468161304f565b91505b50919050565b6000600061305c836119b3565b9050607b81101561306c5761307c565b613075816130d5565b9150613088565b61308581613114565b91505b50919050565b600060006130a361309e846119b3565b6119b3565b9050607b8110156130b3576130c3565b6130bc81613114565b91506130cf565b6130cc816130d5565b91505b50919050565b600060006130e2836119b3565b905060788110156130f257613102565b6130fb8161315b565b915061310e565b61310b8161319a565b91505b50919050565b60006000613129613124846119b3565b6119b3565b9050607881101561313957613149565b6131428161319a565b9150613155565b6131528161315b565b91505b50919050565b60006000613168836119b3565b9050607981101561317857613188565b613181816131e1565b9150613194565b61319181613220565b91505b50919050565b600060006131af6131aa846119b3565b6119b3565b905060798110156131bf576131cf565b6131c881613220565b91506131db565b6131d8816131e1565b91505b50919050565b600060006131ee836119b3565b9050607e8110156131fe5761320e565b61320781613267565b915061321a565b613217816132a6565b91505b50919050565b60006000613235613230846119b3565b6119b3565b9050607e81101561324557613255565b61324e816132a6565b9150613261565b61325e81613267565b91505b50919050565b60006000613274836119b3565b9050607f81101561328457613294565b61328d816132ed565b91506132a0565b61329d8161332c565b91505b50919050565b600060006132bb6132b6846119b3565b6119b3565b9050607f8110156132cb576132db565b6132d48161332c565b91506132e7565b6132e4816132ed565b91505b50919050565b600060006132fa836119b3565b9050607c81101561330a5761331a565b61331381613373565b9150613326565b613323816133b2565b91505b50919050565b6000600061334161333c846119b3565b6119b3565b9050607c81101561335157613361565b61335a816133b2565b915061336d565b61336a81613373565b91505b50919050565b60006000613380836119b3565b9050607d811015613390576133a0565b613399816133f9565b91506133ac565b6133a981613438565b91505b50919050565b600060006133c76133c2846119b3565b6119b3565b9050607d8110156133d7576133e7565b6133e081613438565b91506133f3565b6133f0816133f9565b91505b50919050565b60006000613406836119b3565b9050608281101561341657613426565b61341f8161347f565b9150613432565b61342f816134be565b91505b50919050565b6000600061344d613448846119b3565b6119b3565b9050608281101561345d5761346d565b613466816134be565b9150613479565b6134768161347f565b91505b50919050565b6000600061348c836119b3565b9050608381101561349c576134ac565b6134a581613505565b91506134b8565b6134b581613544565b91505b50919050565b600060006134d36134ce846119b3565b6119b3565b905060838110156134e3576134f3565b6134ec81613544565b91506134ff565b6134fc81613505565b91505b50919050565b60006000613512836119b3565b9050608081101561352257613532565b61352b8161358b565b915061353e565b61353b816135ca565b91505b50919050565b60006000613559613554846119b3565b6119b3565b9050608081101561356957613579565b613572816135ca565b9150613585565b6135828161358b565b91505b50919050565b60006000613598836119b3565b905060818110156135a8576135b8565b6135b181613611565b91506135c4565b6135c181613650565b91505b50919050565b600060006135df6135da846119b3565b6119b3565b905060818110156135ef576135ff565b6135f881613650565b915061360b565b61360881613611565b91505b50919050565b6000600061361e836119b3565b9050608681101561362e5761363e565b61363781613697565b915061364a565b613647816136d6565b91505b50919050565b60006000613665613660846119b3565b6119b3565b9050608681101561367557613685565b61367e816136d6565b9150613691565b61368e81613697565b91505b50919050565b600060006136a4836119b3565b905060878110156136b4576136c4565b6136bd8161371d565b91506136d0565b6136cd8161375c565b91505b50919050565b600060006136eb6136e6846119b3565b6119b3565b905060878110156136fb5761370b565b6137048161375c565b9150613717565b6137148161371d565b91505b50919050565b6000600061372a836119b3565b9050608481101561373a5761374a565b613743816137a3565b9150613756565b613753816137e2565b91505b50919050565b6000600061377161376c846119b3565b6119b3565b9050608481101561378157613791565b61378a816137e2565b915061379d565b61379a816137a3565b91505b50919050565b600060006137b0836119b3565b905060858110156137c0576137d0565b6137c981613829565b91506137dc565b6137d981613868565b91505b50919050565b600060006137f76137f2846119b3565b6119b3565b9050608581101561380757613817565b61381081613868565b9150613823565b61382081613829565b91505b50919050565b60006000613836836119b3565b9050608a81101561384657613856565b61384f816138af565b9150613862565b61385f816138ee565b91505b50919050565b6000600061387d613878846119b3565b6119b3565b9050608a81101561388d5761389d565b613896816138ee565b91506138a9565b6138a6816138af565b91505b50919050565b600060006138bc836119b3565b9050608b8110156138cc576138dc565b6138d581613935565b91506138e8565b6138e581613974565b91505b50919050565b600060006139036138fe846119b3565b6119b3565b9050608b81101561391357613923565b61391c81613974565b915061392f565b61392c81613935565b91505b50919050565b60006000613942836119b3565b9050608881101561395257613962565b61395b816139bb565b915061396e565b61396b816139fa565b91505b50919050565b60006000613989613984846119b3565b6119b3565b90506088811015613999576139a9565b6139a2816139fa565b91506139b5565b6139b2816139bb565b91505b50919050565b600060006139c8836119b3565b905060898110156139d8576139e8565b6139e181613a41565b91506139f4565b6139f181613a80565b91505b50919050565b60006000613a0f613a0a846119b3565b6119b3565b90506089811015613a1f57613a2f565b613a2881613a80565b9150613a3b565b613a3881613a41565b91505b50919050565b60006000613a4e836119b3565b9050608e811015613a5e57613a6e565b613a6781613ac7565b9150613a7a565b613a7781613b06565b91505b50919050565b60006000613a95613a90846119b3565b6119b3565b9050608e811015613aa557613ab5565b613aae81613b06565b9150613ac1565b613abe81613ac7565b91505b50919050565b60006000613ad4836119b3565b9050608f811015613ae457613af4565b613aed81613b4d565b9150613b00565b613afd81613b8c565b91505b50919050565b60006000613b1b613b16846119b3565b6119b3565b9050608f811015613b2b57613b3b565b613b3481613b8c565b9150613b47565b613b4481613b4d565b91505b50919050565b60006000613b5a836119b3565b9050608c811015613b6a57613b7a565b613b7381613bd3565b9150613b86565b613b8381613c12565b91505b50919050565b60006000613ba1613b9c846119b3565b6119b3565b9050608c811015613bb157613bc1565b613bba81613c12565b9150613bcd565b613bca81613bd3565b91505b50919050565b60006000613be0836119b3565b9050608d811015613bf057613c00565b613bf981613c59565b9150613c0c565b613c0981613c98565b91505b50919050565b60006000613c27613c22846119b3565b6119b3565b9050608d811015613c3757613c47565b613c4081613c98565b9150613c53565b613c5081613c59565b91505b50919050565b60006000613c66836119b3565b90506092811015613c7657613c86565b613c7f81613cdf565b9150613c92565b613c8f81613d1e565b91505b50919050565b60006000613cad613ca8846119b3565b6119b3565b90506092811015613cbd57613ccd565b613cc681613d1e565b9150613cd9565b613cd681613cdf565b91505b50919050565b60006000613cec836119b3565b90506093811015613cfc57613d0c565b613d0581613d65565b9150613d18565b613d1581613da4565b91505b50919050565b60006000613d33613d2e846119b3565b6119b3565b90506093811015613d4357613d53565b613d4c81613da4565b9150613d5f565b613d5c81613d65565b91505b50919050565b60006000613d72836119b3565b90506090811015613d8257613d92565b613d8b81613deb565b9150613d9e565b613d9b81613e2a565b91505b50919050565b60006000613db9613db4846119b3565b6119b3565b90506090811015613dc957613dd9565b613dd281613e2a565b9150613de5565b613de281613deb565b91505b50919050565b60006000613df8836119b3565b90506091811015613e0857613e18565b613e1181613e71565b9150613e24565b613e2181613eb0565b91505b50919050565b60006000613e3f613e3a846119b3565b6119b3565b90506091811015613e4f57613e5f565b613e5881613eb0565b9150613e6b565b613e6881613e71565b91505b50919050565b60006000613e7e836119b3565b90506096811015613e8e57613e9e565b613e9781613ef7565b9150613eaa565b613ea781613f36565b91505b50919050565b60006000613ec5613ec0846119b3565b6119b3565b90506096811015613ed557613ee5565b613ede81613f36565b9150613ef1565b613eee81613ef7565b91505b50919050565b60006000613f04836119b3565b90506097811015613f1457613f24565b613f1d81613f7d565b9150613f30565b613f2d81613fbc565b91505b50919050565b60006000613f4b613f46846119b3565b6119b3565b90506097811015613f5b57613f6b565b613f6481613fbc565b9150613f77565b613f7481613f7d565b91505b50919050565b60006000613f8a836119b3565b90506094811015613f9a57613faa565b613fa381614003565b9150613fb6565b613fb381614042565b91505b50919050565b60006000613fd1613fcc846119b3565b6119b3565b90506094811015613fe157613ff1565b613fea81614042565b9150613ffd565b613ffa81614003565b91505b50919050565b60006000614010836119b3565b9050609581101561402057614030565b61402981614089565b915061403c565b614039816140c8565b91505b50919050565b60006000614057614052846119b3565b6119b3565b9050609581101561406757614077565b614070816140c8565b9150614083565b61408081614089565b91505b50919050565b60006000614096836119b3565b9050609a8110156140a6576140b6565b6140af8161410f565b91506140c2565b6140bf8161414e565b91505b50919050565b600060006140dd6140d8846119b3565b6119b3565b9050609a8110156140ed576140fd565b6140f68161414e565b9150614109565b6141068161410f565b91505b50919050565b6000600061411c836119b3565b9050609b81101561412c5761413c565b61413581614195565b9150614148565b614145816141d4565b91505b50919050565b6000600061416361415e846119b3565b6119b3565b9050609b81101561417357614183565b61417c816141d4565b915061418f565b61418c81614195565b91505b50919050565b600060006141a2836119b3565b905060988110156141b2576141c2565b6141bb8161421b565b91506141ce565b6141cb8161425a565b91505b50919050565b600060006141e96141e4846119b3565b6119b3565b905060988110156141f957614209565b6142028161425a565b9150614215565b6142128161421b565b91505b50919050565b60006000614228836119b3565b9050609981101561423857614248565b614241816142a1565b9150614254565b614251816142e0565b91505b50919050565b6000600061426f61426a846119b3565b6119b3565b9050609981101561427f5761428f565b614288816142e0565b915061429b565b614298816142a1565b91505b50919050565b600060006142ae836119b3565b9050609e8110156142be576142ce565b6142c781614327565b91506142da565b6142d781614366565b91505b50919050565b600060006142f56142f0846119b3565b6119b3565b9050609e81101561430557614315565b61430e81614366565b9150614321565b61431e81614327565b91505b50919050565b60006000614334836119b3565b9050609f81101561434457614354565b61434d816143ad565b9150614360565b61435d816143ec565b91505b50919050565b6000600061437b614376846119b3565b6119b3565b9050609f81101561438b5761439b565b614394816143ec565b91506143a7565b6143a4816143ad565b91505b50919050565b600060006143ba836119b3565b9050609c8110156143ca576143da565b6143d381614433565b91506143e6565b6143e381614472565b91505b50919050565b600060006144016143fc846119b3565b6119b3565b9050609c81101561441157614421565b61441a81614472565b915061442d565b61442a81614433565b91505b50919050565b60006000614440836119b3565b9050609d81101561445057614460565b614459816144b9565b915061446c565b614469816144f8565b91505b50919050565b60006000614487614482846119b3565b6119b3565b9050609d811015614497576144a7565b6144a0816144f8565b91506144b3565b6144b0816144b9565b91505b50919050565b600060006144c6836119b3565b905060a28110156144d6576144e6565b6144df8161453f565b91506144f2565b6144ef8161457e565b91505b50919050565b6000600061450d614508846119b3565b6119b3565b905060a281101561451d5761452d565b6145268161457e565b9150614539565b6145368161453f565b91505b50919050565b6000600061454c836119b3565b905060a381101561455c5761456c565b614565816145c5565b9150614578565b61457581614604565b91505b50919050565b6000600061459361458e846119b3565b6119b3565b905060a38110156145a3576145b3565b6145ac81614604565b91506145bf565b6145bc816145c5565b91505b50919050565b600060006145d2836119b3565b905060a08110156145e2576145f2565b6145eb8161464b565b91506145fe565b6145fb8161468a565b91505b50919050565b60006000614619614614846119b3565b6119b3565b905060a081101561462957614639565b6146328161468a565b9150614645565b6146428161464b565b91505b50919050565b60006000614658836119b3565b905060a181101561466857614678565b614671816146d1565b9150614684565b61468181614710565b91505b50919050565b6000600061469f61469a846119b3565b6119b3565b905060a18110156146af576146bf565b6146b881614710565b91506146cb565b6146c8816146d1565b91505b50919050565b600060006146de836119b3565b905060a68110156146ee576146fe565b6146f781614757565b915061470a565b61470781614796565b91505b50919050565b60006000614725614720846119b3565b6119b3565b905060a681101561473557614745565b61473e81614796565b9150614751565b61474e81614757565b91505b50919050565b60006000614764836119b3565b905060a781101561477457614784565b61477d816147dd565b9150614790565b61478d8161481c565b91505b50919050565b600060006147ab6147a6846119b3565b6119b3565b905060a78110156147bb576147cb565b6147c48161481c565b91506147d7565b6147d4816147dd565b91505b50919050565b600060006147ea836119b3565b905060a48110156147fa5761480a565b61480381614863565b9150614816565b614813816148a2565b91505b50919050565b6000600061483161482c846119b3565b6119b3565b905060a481101561484157614851565b61484a816148a2565b915061485d565b61485a81614863565b91505b50919050565b60006000614870836119b3565b905060a581101561488057614890565b614889816148e9565b915061489c565b61489981614928565b91505b50919050565b600060006148b76148b2846119b3565b6119b3565b905060a58110156148c7576148d7565b6148d081614928565b91506148e3565b6148e0816148e9565b91505b50919050565b600060006148f6836119b3565b905060aa81101561490657614916565b61490f8161496f565b9150614922565b61491f816149ae565b91505b50919050565b6000600061493d614938846119b3565b6119b3565b905060aa81101561494d5761495d565b614956816149ae565b9150614969565b6149668161496f565b91505b50919050565b6000600061497c836119b3565b905060ab81101561498c5761499c565b614995816149f5565b91506149a8565b6149a581614a34565b91505b50919050565b600060006149c36149be846119b3565b6119b3565b905060ab8110156149d3576149e3565b6149dc81614a34565b91506149ef565b6149ec816149f5565b91505b50919050565b60006000614a02836119b3565b905060a8811015614a1257614a22565b614a1b81614a7b565b9150614a2e565b614a2b81614aba565b91505b50919050565b60006000614a49614a44846119b3565b6119b3565b905060a8811015614a5957614a69565b614a6281614aba565b9150614a75565b614a7281614a7b565b91505b50919050565b60006000614a88836119b3565b905060a9811015614a9857614aa8565b614aa181614b01565b9150614ab4565b614ab181614b40565b91505b50919050565b60006000614acf614aca846119b3565b6119b3565b905060a9811015614adf57614aef565b614ae881614b40565b9150614afb565b614af881614b01565b91505b50919050565b60006000614b0e836119b3565b905060ae811015614b1e57614b2e565b614b2781614b87565b9150614b3a565b614b3781614bc6565b91505b50919050565b60006000614b55614b50846119b3565b6119b3565b905060ae811015614b6557614b75565b614b6e81614bc6565b9150614b81565b614b7e81614b87565b91505b50919050565b60006000614b94836119b3565b905060af811015614ba457614bb4565b614bad81614c0d565b9150614bc0565b614bbd81614c4c565b91505b50919050565b60006000614bdb614bd6846119b3565b6119b3565b905060af811015614beb57614bfb565b614bf481614c4c565b9150614c07565b614c0481614c0d565b91505b50919050565b60006000614c1a836119b3565b905060ac811015614c2a57614c3a565b614c3381614c93565b9150614c46565b614c4381614cd2565b91505b50919050565b60006000614c61614c5c846119b3565b6119b3565b905060ac811015614c7157614c81565b614c7a81614cd2565b9150614c8d565b614c8a81614c93565b91505b50919050565b60006000614ca0836119b3565b905060ad811015614cb057614cc0565b614cb981614d19565b9150614ccc565b614cc981614d58565b91505b50919050565b60006000614ce7614ce2846119b3565b6119b3565b905060ad811015614cf757614d07565b614d0081614d58565b9150614d13565b614d1081614d19565b91505b50919050565b60006000614d26836119b3565b905060b2811015614d3657614d46565b614d3f816129c8565b9150614d52565b614d4f81614d9f565b91505b50919050565b60006000614d6d614d68846119b3565b6119b3565b905060b2811015614d7d57614d8d565b614d8681614d9f565b9150614d99565b614d96816129c8565b91505b50919050565b60006000614db4614daf846119b3565b6119b3565b905060b3811015614dc457614dd4565b614dcd816119fa565b9150614de0565b614ddd816119e8565b91505b5091905056", + "code" : "0x60e060020a60003504806301f99ad7146108c3578063023a624a146108d857806303bdecf5146108ed57806305fe035f14610902578063082d8f4914610917578063090bf3b71461092c5780630bd9c534146109415780630c4bfa94146109565780630e20ebe21461096b5780630f76de0d1461098057806310cfcc191461099557806313ce15a9146109aa578063140dcec4146109bf57806314d07a3e146109d45780631687f112146109e957806316eb6603146109fe578063172cf71714610a135780631bd6f59614610a285780631cdb857114610a3d5780631cf74ece14610a525780631d09ba2c14610a675780631f69aa5114610a7c578063223dcc7414610a9157806325e524d314610aa6578063261de7c414610abb5780632632924d14610ad05780632909cc5d14610ae55780632981699814610afa5780632a85a45d14610b0f5780632ca36da014610b245780632cbf1f0d14610b395780632d0f557314610b4e5780632d97867814610b6357806331db9efd14610b7857806332064db714610b8d57806332931fbb14610ba2578063355f51a014610bb7578063361bb34014610bcc578063364ddb0e14610be15780633792a01814610bf657806338c68f8f14610c0b57806338e586fd14610c20578063392d42ae14610c3557806339a87bd914610c4a5780633a95a33214610c5f5780633b8ecdf914610c745780633cf0659a14610c895780633eaf992314610c9e5780633fe97ead14610cb35780633ff11c8b14610cc8578063404efc5314610cdd578063407fce7b14610cf257806340c3b18714610d07578063440208c314610d1c57806344e86b2f14610d31578063455df57914610d465780634689ab4d14610d5b57806346be2e0c14610d70578063487cd86f14610d8557806348e6178214610d9a57806349d4a34414610daf5780634a0f597414610dc45780634bc24ec514610dd95780634c2fe45614610dee5780634cc885d414610e035780634eaaad7b14610e185780634eb166af14610e2d5780635050093414610e42578063506bff1114610e57578063508762c114610e6c578063526938f814610e8157806354400c6014610e96578063559510d814610eab57806355a5f70214610ec057806356ca528f14610ed5578063570a2a1614610eea5780635dab2e0f14610eff5780635dca53d314610f1457806362017ebc14610f29578063621a25f814610f3e578063626d4a3614610f5357806362b6a28214610f6857806364faf22c14610f7d57806366d7ffde14610f9257806367b886e814610fa757806367e902c714610fbc57806369d7774014610fd15780636b7ae8e614610fe65780636c3b659114610ffb5780636e54181e146110105780636e978d91146110255780636f63d2ec1461103a578063706332d11461104f57806370ac4bb9146110645780637138ef521461107957806371dd46a91461108e57806372a7c229146110a35780637376fc8d146110b8578063738a2679146110cd57806374552650146110e2578063746fc8d0146110f757806379254bb81461110c5780637adaa3f8146111215780637e4eb35b14611136578063885ec18e1461114b5780638b9ff6b6146111605780638ce113dc146111755780638defbc5e1461118a5780638f4613d51461119f5780638fdc24ba146111b45780639002dba4146111c957806391d15735146111de57806391d43b23146111f357806393b14daa1461120857806394d63afd1461121d57806395805dad1461123257806396f68782146112475780639740e4a21461125c578063981290131461127157806399a3f0e8146112865780639acb1ad41461129b5780639be07908146112b05780639c15be0b146112c55780639d451c4d146112da5780639d8ee943146112ef5780639ef6ca0f14611304578063a0db0a2214611319578063a18e2eb91461132e578063a408384914611343578063a57544da14611358578063a5a83e4d1461136d578063a6843f3414611382578063a6dacdd714611397578063a8c4c8bc146113ac578063aa058a73146113c1578063aad62da2146113d6578063aaf3e4f4146113eb578063ab81e77314611400578063abc93aee14611415578063abde33f71461142a578063b114b96c1461143f578063b3df873714611454578063b4174cb014611469578063b5d02a561461147e578063b731e84814611493578063b7b96723146114a8578063bbcded7a146114bd578063bbececa9146114d2578063beca7440146114e7578063bf8981c0146114fc578063c028c67414611511578063c2385fa614611526578063c319a02c1461153b578063c569bae014611550578063c6715f8114611565578063c7b98dec1461157a578063c9acab841461158f578063ca9efc73146115a4578063cad80024146115b9578063cdadb0fa146115ce578063cdbdf391146115e3578063cf460fa5146115f8578063cf69318a1461160d578063d1835b8c14611622578063d353a1cb14611637578063d3e141e01461164c578063d5ec7e1d14611661578063d7ead1de14611676578063d90b02aa1461168b578063d959e244146116a0578063d9e68b44146116b5578063daacb24f146116ca578063dc12a805146116df578063dd946033146116f4578063dda5142414611709578063de6612171461171e578063dfb9560c14611733578063e03827d214611748578063e21720001461175d578063e2c718d814611772578063e3da539914611787578063e48e603f1461179c578063e5f9ec29146117b1578063e6c0459a146117c6578063e70addec146117db578063e7a01215146117f0578063ea7f4d2714611805578063ebb6c59f1461181a578063ed6302be1461182f578063ed64b36b14611844578063eecd278914611859578063f0ed14e01461186e578063f0f2134414611883578063f1e328f914611898578063f1e6f4cd146118ad578063f32fe995146118c2578063f75165c6146118d7578063f7ed71d0146118ec578063f80f44f314611901578063f8bc050514611916578063fbd3c51a1461192b578063fd72009014611940578063fed3a3001461195557005b6108ce600435612edf565b8060005260206000f35b6108e3600435612fb5565b8060005260206000f35b6108f8600435613f47565b8060005260206000f35b61090d600435612a11565b8060005260206000f35b6109226004356127ec565b8060005260206000f35b61093760043561215c565b8060005260206000f35b61094c6004356128c2565b8060005260206000f35b61096160043561310f565b8060005260206000f35b610976600435614e0b565b8060005260206000f35b61098b600435613269565b8060005260206000f35b6109a0600435611a82565b8060005260206000f35b6109b5600435613e71565b8060005260206000f35b6109ca600435611dd2565b8060005260206000f35b6109df6004356120d0565b8060005260206000f35b6109f4600435613755565b8060005260206000f35b610a096004356134e3565b8060005260206000f35b610a1e6004356137e1565b8060005260206000f35b610a3360043561382b565b8060005260206000f35b610a48600435612b0b565b8060005260206000f35b610a5d60043561386d565b8060005260206000f35b610a726004356131e5565b8060005260206000f35b610a876004356143e9565b8060005260206000f35b610a9c60043561319b565b8060005260206000f35b610ab1600435612e11565b8060005260206000f35b610ac660043561234a565b8060005260206000f35b610adb6004356121e8565b8060005260206000f35b610af06004356119f6565b8060005260206000f35b610b05600435613bff565b8060005260206000f35b610b1a600435612606565b8060005260206000f35b610b2f6004356126d4565b8060005260206000f35b610b44600435613bb5565b8060005260206000f35b610b59600435612462565b8060005260206000f35b610b6e600435611e14565b8060005260206000f35b610b836004356149ab565b8060005260206000f35b610b98600435611c26565b8060005260206000f35b610bad600435612a7f565b8060005260206000f35b610bc2600435613457565b8060005260206000f35b610bd760043561340d565b8060005260206000f35b610bec60043561363d565b8060005260206000f35b610c01600435612e53565b8060005260206000f35b610c1660043561477b565b8060005260206000f35b610c2b600435612c6d565b8060005260206000f35b610c40600435612648565b8060005260206000f35b610c55600435612274565b8060005260206000f35b610c6a6004356138f9565b8060005260206000f35b610c7f600435612b55565b8060005260206000f35b610c94600435611eea565b8060005260206000f35b610ca9600435613ebb565b8060005260206000f35b610cbe600435613499565b8060005260206000f35b610cd3600435614807565b8060005260206000f35b610ce8600435611fb8565b8060005260206000f35b610cfd600435613083565b8060005260206000f35b610d126004356125bc565b8060005260206000f35b610d27600435613041565b8060005260206000f35b610d3c6004356140a1565b8060005260206000f35b610d516004356147bd565b8060005260206000f35b610d66600435611c70565b8060005260206000f35b610d7b600435612300565b8060005260206000f35b610d906004356123d6565b8060005260206000f35b610da5600435612c23565b8060005260206000f35b610dba600435614faf565b8060005260206000f35b610dcf600435612044565b8060005260206000f35b610de4600435613ae7565b8060005260206000f35b610df9600435614cf3565b8060005260206000f35b610e0e600435613d17565b8060005260206000f35b610e2360043561412d565b8060005260206000f35b610e38600435614177565b8060005260206000f35b610e4d60043561208e565b8060005260206000f35b610e62600435612dc7565b8060005260206000f35b610e77600435612f29565b8060005260206000f35b610e8c6004356124a4565b8060005260206000f35b610ea1600435611b58565b8060005260206000f35b610eb66004356136c9565b8060005260206000f35b610ecb600435613227565b8060005260206000f35b610ee0600435611acc565b8060005260206000f35b610ef5600435613687565b8060005260206000f35b610f0a6004356146a5565b8060005260206000f35b610f1f6004356121a6565b8060005260206000f35b610f346004356132f5565b8060005260206000f35b610f49600435613da3565b8060005260206000f35b610f5e60043561379f565b8060005260206000f35b610f73600435612878565b8060005260206000f35b610f88600435611b0e565b8060005260206000f35b610f9d600435611ea0565b8060005260206000f35b610fb2600435614ed9565b8060005260206000f35b610fc7600435614bdb565b8060005260206000f35b610fdc600435614c1d565b8060005260206000f35b610ff1600435614245565b8060005260206000f35b6110066004356146ef565b8060005260206000f35b61101b60043561428f565b8060005260206000f35b611030600435614ac3565b8060005260206000f35b611045600435613de5565b8060005260206000f35b61105a6004356132b3565b8060005260206000f35b61106f6004356122be565b8060005260206000f35b611084600435612e9d565b8060005260206000f35b611099600435611b9a565b8060005260206000f35b6110ae6004356127aa565b8060005260206000f35b6110c3600435613e2f565b8060005260206000f35b6110d8600435614849565b8060005260206000f35b6110ed600435614dc1565b8060005260206000f35b61110260043561333f565b8060005260206000f35b61111760043561211a565b8060005260206000f35b61112c600435612692565b8060005260206000f35b611141600435612904565b8060005260206000f35b611156600435612d3b565b8060005260206000f35b61116b600435614b91565b8060005260206000f35b611180600435613a5b565b8060005260206000f35b611195600435612232565b8060005260206000f35b6111aa600435612f6b565b8060005260206000f35b6111bf600435614d35565b8060005260206000f35b6111d4600435611a40565b8060005260206000f35b6111e9600435612ff7565b8060005260206000f35b6111fe60043561431b565b8060005260206000f35b611213600435613159565b8060005260206000f35b611228600435612b97565b8060005260206000f35b61123d600435612990565b8060005260206000f35b611252600435613b73565b8060005260206000f35b611267600435614961565b8060005260206000f35b61127c600435613381565b8060005260206000f35b611291600435613fd3565b8060005260206000f35b6112a660043561257a565b8060005260206000f35b6112bb600435614501565b8060005260206000f35b6112d0600435613d59565b8060005260206000f35b6112e56004356143a7565b8060005260206000f35b6112fa60043561405f565b8060005260206000f35b61130f60043561238c565b8060005260206000f35b611324600435612be1565b8060005260206000f35b611339600435613f89565b8060005260206000f35b61134e60043561294e565b8060005260206000f35b6113636004356124ee565b8060005260206000f35b611378600435614b4f565b8060005260206000f35b61138d6004356133cb565b8060005260206000f35b6113a26004356139cf565b8060005260206000f35b6113b7600435613c8b565b8060005260206000f35b6113cc600435612cf9565b8060005260206000f35b6113e1600435614a79565b8060005260206000f35b6113f66004356149ed565b8060005260206000f35b61140b600435613b29565b8060005260206000f35b611420600435613ccd565b8060005260206000f35b611435600435611f76565b8060005260206000f35b61144a600435614ff1565b8060005260206000f35b61145f600435613525565b8060005260206000f35b61147460043561356f565b8060005260206000f35b6114896004356129dc565b8060005260206000f35b61149e600435614ca9565b8060005260206000f35b6114b3600435612d85565b8060005260206000f35b6114c86004356141b9565b8060005260206000f35b6114dd600435614475565b8060005260206000f35b6114f26004356135fb565b8060005260206000f35b611507600435612530565b8060005260206000f35b61151c600435614663565b8060005260206000f35b611531600435614433565b8060005260206000f35b611546600435614f23565b8060005260206000f35b61155b600435614c67565b8060005260206000f35b611570600435611d3e565b8060005260206000f35b611585600435612a3d565b8060005260206000f35b61159a600435613a11565b8060005260206000f35b6115af600435614619565b8060005260206000f35b6115c4600435613985565b8060005260206000f35b6115d9600435613943565b8060005260206000f35b6115ee600435612418565b8060005260206000f35b6116036004356119b4565b8060005260206000f35b611618600435613a9d565b8060005260206000f35b61162d600435611cb2565b8060005260206000f35b6116426004356129d2565b8060005260206000f35b611657600435612caf565b8060005260206000f35b61166c600435611d88565b8060005260206000f35b611681600435614203565b8060005260206000f35b61169660043561458d565b8060005260206000f35b6116ab600435611f2c565b8060005260206000f35b6116c0600435612a23565b8060005260206000f35b6116d5600435612836565b8060005260206000f35b6116ea6004356138b7565b8060005260206000f35b6116ff6004356145d7565b8060005260206000f35b61171460043561454b565b8060005260206000f35b6117296004356142d1565b8060005260206000f35b61173e600435611e5e565b8060005260206000f35b611753600435614015565b8060005260206000f35b611768600435613c41565b8060005260206000f35b61177d600435611be4565b8060005260206000f35b611792600435614b05565b8060005260206000f35b6117a7600435613713565b8060005260206000f35b6117bc6004356135b1565b8060005260206000f35b6117d16004356144bf565b8060005260206000f35b6117e660043561491f565b8060005260206000f35b6117fb600435612ac9565b8060005260206000f35b6118106004356130cd565b8060005260206000f35b6118256004356140eb565b8060005260206000f35b61183a600435614f65565b8060005260206000f35b61184f60043561196a565b8060005260206000f35b6118646004356148d5565b8060005260206000f35b611879600435614d7f565b8060005260206000f35b61188e600435612002565b8060005260206000f35b6118a3600435613efd565b8060005260206000f35b6118b860043561271e565b8060005260206000f35b6118cd600435614e4d565b8060005260206000f35b6118e2600435611cfc565b8060005260206000f35b6118f7600435612760565b8060005260206000f35b61190c600435614e97565b8060005260206000f35b61192160043561435d565b8060005260206000f35b611936600435614731565b8060005260206000f35b61194b600435614893565b8060005260206000f35b611960600435614a37565b8060005260206000f35b6000600061197f61197a846129dc565b6129dc565b9050605d60020a811015611992576119a2565b61199b816119f6565b91506119ae565b6119ab816119b4565b91505b50919050565b600060006119c1836129dc565b9050605e60020a8110156119d4576119e4565b6119dd81611a40565b91506119f0565b6119ed81611a82565b91505b50919050565b60006000611a0b611a06846129dc565b6129dc565b9050605e60020a811015611a1e57611a2e565b611a2781611a82565b9150611a3a565b611a3781611a40565b91505b50919050565b60006000611a4d836129dc565b9050605f60020a811015611a6057611a70565b611a6981611acc565b9150611a7c565b611a7981611b0e565b91505b50919050565b60006000611a97611a92846129dc565b6129dc565b9050605f60020a811015611aaa57611aba565b611ab381611b0e565b9150611ac6565b611ac381611acc565b91505b50919050565b60006000611ad9836129dc565b9050606060020a811015611aec57611afc565b611af581611b58565b9150611b08565b611b0581611b9a565b91505b50919050565b60006000611b23611b1e846129dc565b6129dc565b9050606060020a811015611b3657611b46565b611b3f81611b9a565b9150611b52565b611b4f81611b58565b91505b50919050565b60006000611b65836129dc565b9050606160020a811015611b7857611b88565b611b8181611be4565b9150611b94565b611b9181611c26565b91505b50919050565b60006000611baf611baa846129dc565b6129dc565b9050606160020a811015611bc257611bd2565b611bcb81611c26565b9150611bde565b611bdb81611be4565b91505b50919050565b60006000611bf1836129dc565b9050606260020a811015611c0457611c14565b611c0d81611c70565b9150611c20565b611c1d81611cb2565b91505b50919050565b60006000611c3b611c36846129dc565b6129dc565b9050606260020a811015611c4e57611c5e565b611c5781611cb2565b9150611c6a565b611c6781611c70565b91505b50919050565b60006000611c7d836129dc565b9050606360020a811015611c9057611ca0565b611c9981611cfc565b9150611cac565b611ca981611d88565b91505b50919050565b60006000611cc7611cc2846129dc565b6129dc565b9050606360020a811015611cda57611cea565b611ce381611d88565b9150611cf6565b611cf381611cfc565b91505b50919050565b60006000611d09836129dc565b9050606460020a811015611d1c57611d2c565b611d2581611dd2565b9150611d38565b611d3581611e14565b91505b50919050565b60006000611d53611d4e846129dc565b6129dc565b9050607a60020a811015611d6657611d76565b611d6f81613269565b9150611d82565b611d7f81613227565b91505b50919050565b60006000611d9d611d98846129dc565b6129dc565b9050606460020a811015611db057611dc0565b611db981611e14565b9150611dcc565b611dc981611dd2565b91505b50919050565b60006000611ddf836129dc565b9050606560020a811015611df257611e02565b611dfb81611e5e565b9150611e0e565b611e0b81611ea0565b91505b50919050565b60006000611e29611e24846129dc565b6129dc565b9050606560020a811015611e3c57611e4c565b611e4581611ea0565b9150611e58565b611e5581611e5e565b91505b50919050565b60006000611e6b836129dc565b9050606660020a811015611e7e57611e8e565b611e8781611eea565b9150611e9a565b611e9781611f2c565b91505b50919050565b60006000611eb5611eb0846129dc565b6129dc565b9050606660020a811015611ec857611ed8565b611ed181611f2c565b9150611ee4565b611ee181611eea565b91505b50919050565b60006000611ef7836129dc565b9050606760020a811015611f0a57611f1a565b611f1381611f76565b9150611f26565b611f2381611fb8565b91505b50919050565b60006000611f41611f3c846129dc565b6129dc565b9050606760020a811015611f5457611f64565b611f5d81611fb8565b9150611f70565b611f6d81611f76565b91505b50919050565b60006000611f83836129dc565b9050606860020a811015611f9657611fa6565b611f9f81612002565b9150611fb2565b611faf81612044565b91505b50919050565b60006000611fcd611fc8846129dc565b6129dc565b9050606860020a811015611fe057611ff0565b611fe981612044565b9150611ffc565b611ff981612002565b91505b50919050565b6000600061200f836129dc565b9050606960020a81101561202257612032565b61202b8161208e565b915061203e565b61203b816120d0565b91505b50919050565b60006000612059612054846129dc565b6129dc565b9050606960020a81101561206c5761207c565b612075816120d0565b9150612088565b6120858161208e565b91505b50919050565b6000600061209b836129dc565b9050606a60020a8110156120ae576120be565b6120b78161211a565b91506120ca565b6120c78161215c565b91505b50919050565b600060006120e56120e0846129dc565b6129dc565b9050606a60020a8110156120f857612108565b6121018161215c565b9150612114565b6121118161211a565b91505b50919050565b60006000612127836129dc565b9050606b60020a81101561213a5761214a565b612143816121a6565b9150612156565b612153816121e8565b91505b50919050565b6000600061217161216c846129dc565b6129dc565b9050606b60020a81101561218457612194565b61218d816121e8565b91506121a0565b61219d816121a6565b91505b50919050565b600060006121b3836129dc565b9050606c60020a8110156121c6576121d6565b6121cf81612232565b91506121e2565b6121df81612274565b91505b50919050565b600060006121fd6121f8846129dc565b6129dc565b9050606c60020a81101561221057612220565b61221981612274565b915061222c565b61222981612232565b91505b50919050565b6000600061223f836129dc565b9050606d60020a81101561225257612262565b61225b816122be565b915061226e565b61226b81612300565b91505b50919050565b60006000612289612284846129dc565b6129dc565b9050606d60020a81101561229c576122ac565b6122a581612300565b91506122b8565b6122b5816122be565b91505b50919050565b600060006122cb836129dc565b9050606e60020a8110156122de576122ee565b6122e78161234a565b91506122fa565b6122f78161238c565b91505b50919050565b60006000612315612310846129dc565b6129dc565b9050606e60020a81101561232857612338565b6123318161238c565b9150612344565b6123418161234a565b91505b50919050565b60006000612357836129dc565b9050606f60020a81101561236a5761237a565b612373816123d6565b9150612386565b61238381612418565b91505b50919050565b600060006123a161239c846129dc565b6129dc565b9050606f60020a8110156123b4576123c4565b6123bd81612418565b91506123d0565b6123cd816123d6565b91505b50919050565b600060006123e3836129dc565b9050607060020a8110156123f657612406565b6123ff81612462565b9150612412565b61240f816124a4565b91505b50919050565b6000600061242d612428846129dc565b6129dc565b9050607060020a81101561244057612450565b612449816124a4565b915061245c565b61245981612462565b91505b50919050565b6000600061246f836129dc565b9050607160020a81101561248257612492565b61248b816124ee565b915061249e565b61249b81612530565b91505b50919050565b600060006124b96124b4846129dc565b6129dc565b9050607160020a8110156124cc576124dc565b6124d581612530565b91506124e8565b6124e5816124ee565b91505b50919050565b600060006124fb836129dc565b9050607260020a81101561250e5761251e565b6125178161257a565b915061252a565b612527816125bc565b91505b50919050565b60006000612545612540846129dc565b6129dc565b9050607260020a81101561255857612568565b612561816125bc565b9150612574565b6125718161257a565b91505b50919050565b60006000612587836129dc565b9050607360020a81101561259a576125aa565b6125a381612606565b91506125b6565b6125b381612648565b91505b50919050565b600060006125d16125cc846129dc565b6129dc565b9050607360020a8110156125e4576125f4565b6125ed81612648565b9150612600565b6125fd81612606565b91505b50919050565b60006000612613836129dc565b9050607460020a81101561262657612636565b61262f81612692565b9150612642565b61263f816126d4565b91505b50919050565b6000600061265d612658846129dc565b6129dc565b9050607460020a81101561267057612680565b612679816126d4565b915061268c565b61268981612692565b91505b50919050565b6000600061269f836129dc565b9050607560020a8110156126b2576126c2565b6126bb8161271e565b91506126ce565b6126cb81612760565b91505b50919050565b600060006126e96126e4846129dc565b6129dc565b9050607560020a8110156126fc5761270c565b61270581612760565b9150612718565b6127158161271e565b91505b50919050565b6000600061272b836129dc565b9050607660020a81101561273e5761274e565b612747816127aa565b915061275a565b612757816127ec565b91505b50919050565b60006000612775612770846129dc565b6129dc565b9050607660020a81101561278857612798565b612791816127ec565b91506127a4565b6127a1816127aa565b91505b50919050565b600060006127b7836129dc565b9050607760020a8110156127ca576127da565b6127d381612836565b91506127e6565b6127e381612878565b91505b50919050565b600060006128016127fc846129dc565b6129dc565b9050607760020a81101561281457612824565b61281d81612878565b9150612830565b61282d81612836565b91505b50919050565b60006000612843836129dc565b9050607860020a81101561285657612866565b61285f816128c2565b9150612872565b61286f81612904565b91505b50919050565b6000600061288d612888846129dc565b6129dc565b9050607860020a8110156128a0576128b0565b6128a981612904565b91506128bc565b6128b9816128c2565b91505b50919050565b600060006128cf836129dc565b9050607960020a8110156128e2576128f2565b6128eb8161294e565b91506128fe565b6128fb81611d3e565b91505b50919050565b60006000612919612914846129dc565b6129dc565b9050607960020a81101561292c5761293c565b61293581611d3e565b9150612948565b6129458161294e565b91505b50919050565b6000600061295b836129dc565b9050607a60020a81101561296e5761297e565b61297781613227565b915061298a565b61298781613269565b91505b50919050565b6000600061299d836129dc565b9050604e60020a8110156129b0576129c0565b6129b981612a7f565b91506129cc565b6129c981612a3d565b91505b50919050565b6000819050919050565b600060007f5851f42d4c957f2c0000000000000000000000000000000000000000000000019050828102600101915050919050565b6000612a1c826129d2565b9050919050565b6000612a36612a31836129dc565b6129d2565b9050919050565b60006000612a4a836129dc565b9050604f60020a811015612a5d57612a6d565b612a6681612ac9565b9150612a79565b612a7681612b0b565b91505b50919050565b60006000612a94612a8f846129dc565b6129dc565b9050604f60020a811015612aa757612ab7565b612ab081612b0b565b9150612ac3565b612ac081612ac9565b91505b50919050565b60006000612ad6836129dc565b9050605060020a811015612ae957612af9565b612af281612b55565b9150612b05565b612b0281612b97565b91505b50919050565b60006000612b20612b1b846129dc565b6129dc565b9050605060020a811015612b3357612b43565b612b3c81612b97565b9150612b4f565b612b4c81612b55565b91505b50919050565b60006000612b62836129dc565b9050605160020a811015612b7557612b85565b612b7e81612be1565b9150612b91565b612b8e81612c23565b91505b50919050565b60006000612bac612ba7846129dc565b6129dc565b9050605160020a811015612bbf57612bcf565b612bc881612c23565b9150612bdb565b612bd881612be1565b91505b50919050565b60006000612bee836129dc565b9050605260020a811015612c0157612c11565b612c0a81612c6d565b9150612c1d565b612c1a81612caf565b91505b50919050565b60006000612c38612c33846129dc565b6129dc565b9050605260020a811015612c4b57612c5b565b612c5481612caf565b9150612c67565b612c6481612c6d565b91505b50919050565b60006000612c7a836129dc565b9050605360020a811015612c8d57612c9d565b612c9681612cf9565b9150612ca9565b612ca681612d3b565b91505b50919050565b60006000612cc4612cbf846129dc565b6129dc565b9050605360020a811015612cd757612ce7565b612ce081612d3b565b9150612cf3565b612cf081612cf9565b91505b50919050565b60006000612d06836129dc565b9050605460020a811015612d1957612d29565b612d2281612d85565b9150612d35565b612d3281612dc7565b91505b50919050565b60006000612d50612d4b846129dc565b6129dc565b9050605460020a811015612d6357612d73565b612d6c81612dc7565b9150612d7f565b612d7c81612d85565b91505b50919050565b60006000612d92836129dc565b9050605560020a811015612da557612db5565b612dae81612e11565b9150612dc1565b612dbe81612e53565b91505b50919050565b60006000612ddc612dd7846129dc565b6129dc565b9050605560020a811015612def57612dff565b612df881612e53565b9150612e0b565b612e0881612e11565b91505b50919050565b60006000612e1e836129dc565b9050605660020a811015612e3157612e41565b612e3a81612e9d565b9150612e4d565b612e4a81612edf565b91505b50919050565b60006000612e68612e63846129dc565b6129dc565b9050605660020a811015612e7b57612e8b565b612e8481612edf565b9150612e97565b612e9481612e9d565b91505b50919050565b60006000612eaa836129dc565b9050605760020a811015612ebd57612ecd565b612ec681612f29565b9150612ed9565b612ed681612f6b565b91505b50919050565b60006000612ef4612eef846129dc565b6129dc565b9050605760020a811015612f0757612f17565b612f1081612f6b565b9150612f23565b612f2081612f29565b91505b50919050565b60006000612f36836129dc565b9050605860020a811015612f4957612f59565b612f5281612fb5565b9150612f65565b612f6281612ff7565b91505b50919050565b60006000612f80612f7b846129dc565b6129dc565b9050605860020a811015612f9357612fa3565b612f9c81612ff7565b9150612faf565b612fac81612fb5565b91505b50919050565b60006000612fc2836129dc565b9050605960020a811015612fd557612fe5565b612fde81613041565b9150612ff1565b612fee81613083565b91505b50919050565b6000600061300c613007846129dc565b6129dc565b9050605960020a81101561301f5761302f565b61302881613083565b915061303b565b61303881613041565b91505b50919050565b6000600061304e836129dc565b9050605a60020a81101561306157613071565b61306a816130cd565b915061307d565b61307a8161310f565b91505b50919050565b60006000613098613093846129dc565b6129dc565b9050605a60020a8110156130ab576130bb565b6130b48161310f565b91506130c7565b6130c4816130cd565b91505b50919050565b600060006130da836129dc565b9050605b60020a8110156130ed576130fd565b6130f681613159565b9150613109565b6131068161319b565b91505b50919050565b6000600061312461311f846129dc565b6129dc565b9050605b60020a81101561313757613147565b6131408161319b565b9150613153565b61315081613159565b91505b50919050565b60006000613166836129dc565b9050605c60020a81101561317957613189565b613182816131e5565b9150613195565b6131928161196a565b91505b50919050565b600060006131b06131ab846129dc565b6129dc565b9050605c60020a8110156131c3576131d3565b6131cc8161196a565b91506131df565b6131dc816131e5565b91505b50919050565b600060006131f2836129dc565b9050605d60020a81101561320557613215565b61320e816119b4565b9150613221565b61321e816119f6565b91505b50919050565b60006000613234836129dc565b9050607b60020a81101561324757613257565b613250816132b3565b9150613263565b613260816132f5565b91505b50919050565b6000600061327e613279846129dc565b6129dc565b9050607b60020a811015613291576132a1565b61329a816132f5565b91506132ad565b6132aa816132b3565b91505b50919050565b600060006132c0836129dc565b9050607c60020a8110156132d3576132e3565b6132dc8161333f565b91506132ef565b6132ec81613381565b91505b50919050565b6000600061330a613305846129dc565b6129dc565b9050607c60020a81101561331d5761332d565b61332681613381565b9150613339565b6133368161333f565b91505b50919050565b6000600061334c836129dc565b9050607d60020a81101561335f5761336f565b613368816133cb565b915061337b565b6133788161340d565b91505b50919050565b60006000613396613391846129dc565b6129dc565b9050607d60020a8110156133a9576133b9565b6133b28161340d565b91506133c5565b6133c2816133cb565b91505b50919050565b600060006133d8836129dc565b9050607e60020a8110156133eb576133fb565b6133f481613457565b9150613407565b61340481613499565b91505b50919050565b6000600061342261341d846129dc565b6129dc565b9050607e60020a81101561343557613445565b61343e81613499565b9150613451565b61344e81613457565b91505b50919050565b60006000613464836129dc565b9050607f60020a81101561347757613487565b613480816134e3565b9150613493565b61349081613525565b91505b50919050565b600060006134ae6134a9846129dc565b6129dc565b9050607f60020a8110156134c1576134d1565b6134ca81613525565b91506134dd565b6134da816134e3565b91505b50919050565b600060006134f0836129dc565b9050608060020a81101561350357613513565b61350c8161356f565b915061351f565b61351c816135b1565b91505b50919050565b6000600061353a613535846129dc565b6129dc565b9050608060020a81101561354d5761355d565b613556816135b1565b9150613569565b6135668161356f565b91505b50919050565b6000600061357c836129dc565b9050608160020a81101561358f5761359f565b613598816135fb565b91506135ab565b6135a88161363d565b91505b50919050565b600060006135c66135c1846129dc565b6129dc565b9050608160020a8110156135d9576135e9565b6135e28161363d565b91506135f5565b6135f2816135fb565b91505b50919050565b60006000613608836129dc565b9050608260020a81101561361b5761362b565b61362481613687565b9150613637565b613634816136c9565b91505b50919050565b6000600061365261364d846129dc565b6129dc565b9050608260020a81101561366557613675565b61366e816136c9565b9150613681565b61367e81613687565b91505b50919050565b60006000613694836129dc565b9050608360020a8110156136a7576136b7565b6136b081613713565b91506136c3565b6136c081613755565b91505b50919050565b600060006136de6136d9846129dc565b6129dc565b9050608360020a8110156136f157613701565b6136fa81613755565b915061370d565b61370a81613713565b91505b50919050565b60006000613720836129dc565b9050608460020a81101561373357613743565b61373c8161379f565b915061374f565b61374c816137e1565b91505b50919050565b6000600061376a613765846129dc565b6129dc565b9050608460020a81101561377d5761378d565b613786816137e1565b9150613799565b6137968161379f565b91505b50919050565b600060006137ac836129dc565b9050608560020a8110156137bf576137cf565b6137c88161382b565b91506137db565b6137d88161386d565b91505b50919050565b600060006137f66137f1846129dc565b6129dc565b9050608560020a81101561380957613819565b6138128161386d565b9150613825565b6138228161382b565b91505b50919050565b60006000613838836129dc565b9050608660020a81101561384b5761385b565b613854816138b7565b9150613867565b613864816138f9565b91505b50919050565b6000600061388261387d846129dc565b6129dc565b9050608660020a811015613895576138a5565b61389e816138f9565b91506138b1565b6138ae816138b7565b91505b50919050565b600060006138c4836129dc565b9050608760020a8110156138d7576138e7565b6138e081613943565b91506138f3565b6138f081613985565b91505b50919050565b6000600061390e613909846129dc565b6129dc565b9050608760020a81101561392157613931565b61392a81613985565b915061393d565b61393a81613943565b91505b50919050565b60006000613950836129dc565b9050608860020a81101561396357613973565b61396c816139cf565b915061397f565b61397c81613a11565b91505b50919050565b6000600061399a613995846129dc565b6129dc565b9050608860020a8110156139ad576139bd565b6139b681613a11565b91506139c9565b6139c6816139cf565b91505b50919050565b600060006139dc836129dc565b9050608960020a8110156139ef576139ff565b6139f881613a5b565b9150613a0b565b613a0881613a9d565b91505b50919050565b60006000613a26613a21846129dc565b6129dc565b9050608960020a811015613a3957613a49565b613a4281613a9d565b9150613a55565b613a5281613a5b565b91505b50919050565b60006000613a68836129dc565b9050608a60020a811015613a7b57613a8b565b613a8481613ae7565b9150613a97565b613a9481613b29565b91505b50919050565b60006000613ab2613aad846129dc565b6129dc565b9050608a60020a811015613ac557613ad5565b613ace81613b29565b9150613ae1565b613ade81613ae7565b91505b50919050565b60006000613af4836129dc565b9050608b60020a811015613b0757613b17565b613b1081613b73565b9150613b23565b613b2081613bb5565b91505b50919050565b60006000613b3e613b39846129dc565b6129dc565b9050608b60020a811015613b5157613b61565b613b5a81613bb5565b9150613b6d565b613b6a81613b73565b91505b50919050565b60006000613b80836129dc565b9050608c60020a811015613b9357613ba3565b613b9c81613bff565b9150613baf565b613bac81613c41565b91505b50919050565b60006000613bca613bc5846129dc565b6129dc565b9050608c60020a811015613bdd57613bed565b613be681613c41565b9150613bf9565b613bf681613bff565b91505b50919050565b60006000613c0c836129dc565b9050608d60020a811015613c1f57613c2f565b613c2881613c8b565b9150613c3b565b613c3881613ccd565b91505b50919050565b60006000613c56613c51846129dc565b6129dc565b9050608d60020a811015613c6957613c79565b613c7281613ccd565b9150613c85565b613c8281613c8b565b91505b50919050565b60006000613c98836129dc565b9050608e60020a811015613cab57613cbb565b613cb481613d17565b9150613cc7565b613cc481613d59565b91505b50919050565b60006000613ce2613cdd846129dc565b6129dc565b9050608e60020a811015613cf557613d05565b613cfe81613d59565b9150613d11565b613d0e81613d17565b91505b50919050565b60006000613d24836129dc565b9050608f60020a811015613d3757613d47565b613d4081613da3565b9150613d53565b613d5081613de5565b91505b50919050565b60006000613d6e613d69846129dc565b6129dc565b9050608f60020a811015613d8157613d91565b613d8a81613de5565b9150613d9d565b613d9a81613da3565b91505b50919050565b60006000613db0836129dc565b9050609060020a811015613dc357613dd3565b613dcc81613e2f565b9150613ddf565b613ddc81613e71565b91505b50919050565b60006000613dfa613df5846129dc565b6129dc565b9050609060020a811015613e0d57613e1d565b613e1681613e71565b9150613e29565b613e2681613e2f565b91505b50919050565b60006000613e3c836129dc565b9050609160020a811015613e4f57613e5f565b613e5881613ebb565b9150613e6b565b613e6881613efd565b91505b50919050565b60006000613e86613e81846129dc565b6129dc565b9050609160020a811015613e9957613ea9565b613ea281613efd565b9150613eb5565b613eb281613ebb565b91505b50919050565b60006000613ec8836129dc565b9050609260020a811015613edb57613eeb565b613ee481613f47565b9150613ef7565b613ef481613f89565b91505b50919050565b60006000613f12613f0d846129dc565b6129dc565b9050609260020a811015613f2557613f35565b613f2e81613f89565b9150613f41565b613f3e81613f47565b91505b50919050565b60006000613f54836129dc565b9050609360020a811015613f6757613f77565b613f7081613fd3565b9150613f83565b613f8081614015565b91505b50919050565b60006000613f9e613f99846129dc565b6129dc565b9050609360020a811015613fb157613fc1565b613fba81614015565b9150613fcd565b613fca81613fd3565b91505b50919050565b60006000613fe0836129dc565b9050609460020a811015613ff357614003565b613ffc8161405f565b915061400f565b61400c816140a1565b91505b50919050565b6000600061402a614025846129dc565b6129dc565b9050609460020a81101561403d5761404d565b614046816140a1565b9150614059565b6140568161405f565b91505b50919050565b6000600061406c836129dc565b9050609560020a81101561407f5761408f565b614088816140eb565b915061409b565b6140988161412d565b91505b50919050565b600060006140b66140b1846129dc565b6129dc565b9050609560020a8110156140c9576140d9565b6140d28161412d565b91506140e5565b6140e2816140eb565b91505b50919050565b600060006140f8836129dc565b9050609660020a81101561410b5761411b565b61411481614177565b9150614127565b614124816141b9565b91505b50919050565b6000600061414261413d846129dc565b6129dc565b9050609660020a81101561415557614165565b61415e816141b9565b9150614171565b61416e81614177565b91505b50919050565b60006000614184836129dc565b9050609760020a811015614197576141a7565b6141a081614203565b91506141b3565b6141b081614245565b91505b50919050565b600060006141ce6141c9846129dc565b6129dc565b9050609760020a8110156141e1576141f1565b6141ea81614245565b91506141fd565b6141fa81614203565b91505b50919050565b60006000614210836129dc565b9050609860020a81101561422357614233565b61422c8161428f565b915061423f565b61423c816142d1565b91505b50919050565b6000600061425a614255846129dc565b6129dc565b9050609860020a81101561426d5761427d565b614276816142d1565b9150614289565b6142868161428f565b91505b50919050565b6000600061429c836129dc565b9050609960020a8110156142af576142bf565b6142b88161431b565b91506142cb565b6142c88161435d565b91505b50919050565b600060006142e66142e1846129dc565b6129dc565b9050609960020a8110156142f957614309565b6143028161435d565b9150614315565b6143128161431b565b91505b50919050565b60006000614328836129dc565b9050609a60020a81101561433b5761434b565b614344816143a7565b9150614357565b614354816143e9565b91505b50919050565b6000600061437261436d846129dc565b6129dc565b9050609a60020a81101561438557614395565b61438e816143e9565b91506143a1565b61439e816143a7565b91505b50919050565b600060006143b4836129dc565b9050609b60020a8110156143c7576143d7565b6143d081614433565b91506143e3565b6143e081614475565b91505b50919050565b600060006143fe6143f9846129dc565b6129dc565b9050609b60020a81101561441157614421565b61441a81614475565b915061442d565b61442a81614433565b91505b50919050565b60006000614440836129dc565b9050609c60020a81101561445357614463565b61445c816144bf565b915061446f565b61446c81614501565b91505b50919050565b6000600061448a614485846129dc565b6129dc565b9050609c60020a81101561449d576144ad565b6144a681614501565b91506144b9565b6144b6816144bf565b91505b50919050565b600060006144cc836129dc565b9050609d60020a8110156144df576144ef565b6144e88161454b565b91506144fb565b6144f88161458d565b91505b50919050565b60006000614516614511846129dc565b6129dc565b9050609d60020a81101561452957614539565b6145328161458d565b9150614545565b6145428161454b565b91505b50919050565b60006000614558836129dc565b9050609e60020a81101561456b5761457b565b614574816145d7565b9150614587565b61458481614619565b91505b50919050565b600060006145a261459d846129dc565b6129dc565b9050609e60020a8110156145b5576145c5565b6145be81614619565b91506145d1565b6145ce816145d7565b91505b50919050565b600060006145e4836129dc565b9050609f60020a8110156145f757614607565b61460081614663565b9150614613565b614610816146a5565b91505b50919050565b6000600061462e614629846129dc565b6129dc565b9050609f60020a81101561464157614651565b61464a816146a5565b915061465d565b61465a81614663565b91505b50919050565b60006000614670836129dc565b905060a060020a81101561468357614693565b61468c816146ef565b915061469f565b61469c81614731565b91505b50919050565b600060006146ba6146b5846129dc565b6129dc565b905060a060020a8110156146cd576146dd565b6146d681614731565b91506146e9565b6146e6816146ef565b91505b50919050565b600060006146fc836129dc565b905060a160020a81101561470f5761471f565b6147188161477b565b915061472b565b614728816147bd565b91505b50919050565b60006000614746614741846129dc565b6129dc565b905060a160020a81101561475957614769565b614762816147bd565b9150614775565b6147728161477b565b91505b50919050565b60006000614788836129dc565b905060a260020a81101561479b576147ab565b6147a481614807565b91506147b7565b6147b481614849565b91505b50919050565b600060006147d26147cd846129dc565b6129dc565b905060a260020a8110156147e5576147f5565b6147ee81614849565b9150614801565b6147fe81614807565b91505b50919050565b60006000614814836129dc565b905060a360020a81101561482757614837565b61483081614893565b9150614843565b614840816148d5565b91505b50919050565b6000600061485e614859846129dc565b6129dc565b905060a360020a81101561487157614881565b61487a816148d5565b915061488d565b61488a81614893565b91505b50919050565b600060006148a0836129dc565b905060a460020a8110156148b3576148c3565b6148bc8161491f565b91506148cf565b6148cc81614961565b91505b50919050565b600060006148ea6148e5846129dc565b6129dc565b905060a460020a8110156148fd5761490d565b61490681614961565b9150614919565b6149168161491f565b91505b50919050565b6000600061492c836129dc565b905060a560020a81101561493f5761494f565b614948816149ab565b915061495b565b614958816149ed565b91505b50919050565b60006000614976614971846129dc565b6129dc565b905060a560020a81101561498957614999565b614992816149ed565b91506149a5565b6149a2816149ab565b91505b50919050565b600060006149b8836129dc565b905060a660020a8110156149cb576149db565b6149d481614a37565b91506149e7565b6149e481614a79565b91505b50919050565b60006000614a026149fd846129dc565b6129dc565b905060a660020a811015614a1557614a25565b614a1e81614a79565b9150614a31565b614a2e81614a37565b91505b50919050565b60006000614a44836129dc565b905060a760020a811015614a5757614a67565b614a6081614ac3565b9150614a73565b614a7081614b05565b91505b50919050565b60006000614a8e614a89846129dc565b6129dc565b905060a760020a811015614aa157614ab1565b614aaa81614b05565b9150614abd565b614aba81614ac3565b91505b50919050565b60006000614ad0836129dc565b905060a860020a811015614ae357614af3565b614aec81614b4f565b9150614aff565b614afc81614b91565b91505b50919050565b60006000614b1a614b15846129dc565b6129dc565b905060a860020a811015614b2d57614b3d565b614b3681614b91565b9150614b49565b614b4681614b4f565b91505b50919050565b60006000614b5c836129dc565b905060a960020a811015614b6f57614b7f565b614b7881614bdb565b9150614b8b565b614b8881614c1d565b91505b50919050565b60006000614ba6614ba1846129dc565b6129dc565b905060a960020a811015614bb957614bc9565b614bc281614c1d565b9150614bd5565b614bd281614bdb565b91505b50919050565b60006000614be8836129dc565b905060aa60020a811015614bfb57614c0b565b614c0481614c67565b9150614c17565b614c1481614ca9565b91505b50919050565b60006000614c32614c2d846129dc565b6129dc565b905060aa60020a811015614c4557614c55565b614c4e81614ca9565b9150614c61565b614c5e81614c67565b91505b50919050565b60006000614c74836129dc565b905060ab60020a811015614c8757614c97565b614c9081614cf3565b9150614ca3565b614ca081614d35565b91505b50919050565b60006000614cbe614cb9846129dc565b6129dc565b905060ab60020a811015614cd157614ce1565b614cda81614d35565b9150614ced565b614cea81614cf3565b91505b50919050565b60006000614d00836129dc565b905060ac60020a811015614d1357614d23565b614d1c81614d7f565b9150614d2f565b614d2c81614dc1565b91505b50919050565b60006000614d4a614d45846129dc565b6129dc565b905060ac60020a811015614d5d57614d6d565b614d6681614dc1565b9150614d79565b614d7681614d7f565b91505b50919050565b60006000614d8c836129dc565b905060ad60020a811015614d9f57614daf565b614da881614e0b565b9150614dbb565b614db881614e4d565b91505b50919050565b60006000614dd6614dd1846129dc565b6129dc565b905060ad60020a811015614de957614df9565b614df281614e4d565b9150614e05565b614e0281614e0b565b91505b50919050565b60006000614e18836129dc565b905060ae60020a811015614e2b57614e3b565b614e3481614e97565b9150614e47565b614e4481614ed9565b91505b50919050565b60006000614e62614e5d846129dc565b6129dc565b905060ae60020a811015614e7557614e85565b614e7e81614ed9565b9150614e91565b614e8e81614e97565b91505b50919050565b60006000614ea4836129dc565b905060af60020a811015614eb757614ec7565b614ec081614f23565b9150614ed3565b614ed081614f65565b91505b50919050565b60006000614eee614ee9846129dc565b6129dc565b905060af60020a811015614f0157614f11565b614f0a81614f65565b9150614f1d565b614f1a81614f23565b91505b50919050565b60006000614f30836129dc565b905060b060020a811015614f4357614f53565b614f4c81614faf565b9150614f5f565b614f5c81614ff1565b91505b50919050565b60006000614f7a614f75846129dc565b6129dc565b905060b060020a811015614f8d57614f9d565b614f9681614ff1565b9150614fa9565b614fa681614faf565b91505b50919050565b60006000614fbc836129dc565b905060b160020a811015614fcf57614fdf565b614fd881612a11565b9150614feb565b614fe881612a23565b91505b50919050565b60006000615006615001846129dc565b6129dc565b905060b160020a81101561501957615029565b61502281612a23565b9150615035565b61503281612a11565b91505b5091905056", "storage": {} } }, From 6745e188c11c700a89828e546b2bbe79c5760e51 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 17 Feb 2015 18:05:41 +0100 Subject: [PATCH 124/201] JSON-RPC transactionCount && uncleCount, fixed #1027 --- libethereum/Client.cpp | 14 ++++++++ libethereum/Client.h | 2 ++ libethereum/Interface.h | 2 ++ libweb3jsonrpc/WebThreeStubServerBase.cpp | 20 +++++++++++ libweb3jsonrpc/WebThreeStubServerBase.h | 4 +++ libweb3jsonrpc/abstractwebthreestubserver.h | 24 +++++++++++++ libweb3jsonrpc/spec.json | 4 +++ mix/MixClient.cpp | 14 ++++++++ mix/MixClient.h | 2 ++ test/webthreestubclient.h | 40 +++++++++++++++++++++ 10 files changed, 126 insertions(+) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 4a49812df..d72762f36 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -714,6 +714,20 @@ BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const return BlockInfo(); } +unsigned Client::transactionCount(h256 _blockHash) const +{ + auto bl = m_bc.block(_blockHash); + RLP b(bl); + return b[1].itemCount(); +} + +unsigned Client::uncleCount(h256 _blockHash) const +{ + auto bl = m_bc.block(_blockHash); + RLP b(bl); + return b[2].itemCount(); +} + LocalisedLogEntries Client::logs(LogFilter const& _f) const { LocalisedLogEntries ret; diff --git a/libethereum/Client.h b/libethereum/Client.h index cb4488b17..f4ab5ce76 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -229,6 +229,8 @@ public: virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); } virtual Transaction transaction(h256 _blockHash, unsigned _i) const; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const; + virtual unsigned transactionCount(h256 _blockHash) const; + virtual unsigned uncleCount(h256 _blockHash) const; /// Differences between transactions. using Interface::diff; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 09a134f1f..847c181e0 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -103,6 +103,8 @@ public: virtual BlockDetails blockDetails(h256 _hash) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0; + virtual unsigned transactionCount(h256 _blockHash) const = 0; + virtual unsigned uncleCount(h256 _blockHash) const = 0; // [EXTRA API]: diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 27b8268da..20efdc66b 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -367,6 +367,26 @@ double WebThreeStubServerBase::eth_countAt(string const& _address) return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault()); } +double WebThreeStubServerBase::eth_transactionCountByHash(std::string const& _hash) +{ + return client()->transactionCount(jsToFixed<32>(_hash)); +} + +double WebThreeStubServerBase::eth_transactionCountByNumber(int _number) +{ + return client()->transactionCount(client()->hashFromNumber(_number)); +} + +double WebThreeStubServerBase::eth_uncleCountByHash(std::string const& _hash) +{ + return client()->transactionCount(jsToFixed<32>(_hash)); +} + +double WebThreeStubServerBase::eth_uncleCountByNumber(int _number) +{ + return client()->transactionCount(client()->hashFromNumber(_number)); +} + int WebThreeStubServerBase::eth_defaultBlock() { return client()->getDefault(); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 005ac4130..368acb33d 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -76,6 +76,10 @@ public: virtual std::string eth_coinbase(); virtual Json::Value eth_compilers(); virtual double eth_countAt(std::string const& _address); + virtual double eth_transactionCountByHash(std::string const& _hash); + virtual double eth_transactionCountByNumber(int _number); + virtual double eth_uncleCountByHash(std::string const& _hash); + virtual double eth_uncleCountByNumber(int _number); virtual int eth_defaultBlock(); virtual std::string eth_gasPrice(); virtual Json::Value eth_filterLogs(int _id); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 5bade41f6..dc3cea392 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -29,6 +29,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_stateAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_stateAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_storageAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_storageAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_countAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_countAtI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_transactionCountByHashI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_transactionCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_transactionCountByNumberI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleCountByHash", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_uncleCountByHashI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_uncleCountByNumber", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_REAL, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_uncleCountByNumberI); this->bindAndAddMethod(jsonrpc::Procedure("eth_codeAt", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_codeAtI); this->bindAndAddMethod(jsonrpc::Procedure("eth_transact", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_transactI); this->bindAndAddMethod(jsonrpc::Procedure("eth_call", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_callI); @@ -141,6 +145,22 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_countAt(request[0u].asString()); } + inline virtual void eth_transactionCountByHashI(const Json::Value &request, Json::Value &response) + { + response = this->eth_transactionCountByHash(request[0u].asString()); + } + inline virtual void eth_transactionCountByNumberI(const Json::Value &request, Json::Value &response) + { + response = this->eth_transactionCountByNumber(request[0u].asInt()); + } + inline virtual void eth_uncleCountByHashI(const Json::Value &request, Json::Value &response) + { + response = this->eth_uncleCountByHash(request[0u].asString()); + } + inline virtual void eth_uncleCountByNumberI(const Json::Value &request, Json::Value &response) + { + response = this->eth_uncleCountByNumber(request[0u].asInt()); + } inline virtual void eth_codeAtI(const Json::Value &request, Json::Value &response) { response = this->eth_codeAt(request[0u].asString()); @@ -298,6 +318,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("eth_transactionCountByHash",p); + if (result.isDouble()) + return result.asDouble(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + double eth_transactionCountByNumber(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_transactionCountByNumber",p); + if (result.isDouble()) + return result.asDouble(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + double eth_uncleCountByHash(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_uncleCountByHash",p); + if (result.isDouble()) + return result.asDouble(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + double eth_uncleCountByNumber(int param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_uncleCountByNumber",p); + if (result.isDouble()) + return result.asDouble(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } std::string eth_codeAt(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; From b9a6fb71582e4d9ebf45730e6a937a78556ff183 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 17 Feb 2015 19:30:14 +0100 Subject: [PATCH 125/201] Warnings fix. --- alethzero/Context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alethzero/Context.h b/alethzero/Context.h index a2fb1a130..098690455 100644 --- a/alethzero/Context.h +++ b/alethzero/Context.h @@ -29,7 +29,7 @@ class QComboBox; -namespace dev { namespace eth { class StateDiff; } } +namespace dev { namespace eth { struct StateDiff; } } #define Small "font-size: small; " #define Mono "font-family: Ubuntu Mono, Monospace, Lucida Console, Courier New; font-weight: bold; " From 4fbeff27d613a4e13452489acd6cfc5e94e8f620 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Tue, 17 Feb 2015 20:00:30 +0100 Subject: [PATCH 126/201] 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 ecb12f65f6e8acb35e06806c30198598e5925c77 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 17 Feb 2015 21:06:42 +0100 Subject: [PATCH 127/201] Add new feature in App deployment --- CMakeLists.txt | 1 + libminizip/CMakeLists.txt | 39 + libminizip/crypt.h | 131 +++ libminizip/ioapi.c | 235 ++++ libminizip/ioapi.h | 200 ++++ libminizip/iowin32.c | 389 +++++++ libminizip/iowin32.h | 28 + libminizip/miniunz.c | 648 +++++++++++ libminizip/minizip.c | 507 ++++++++ libminizip/mztools.c | 281 +++++ libminizip/mztools.h | 31 + libminizip/unzip.c | 2125 ++++++++++++++++++++++++++++++++++ libminizip/unzip.h | 437 +++++++ libminizip/zip.c | 2004 ++++++++++++++++++++++++++++++++ libminizip/zip.h | 362 ++++++ mix/FileIo.cpp | 69 +- mix/FileIo.h | 24 +- mix/qml/DeploymentDialog.qml | 88 ++ mix/qml/ProjectModel.qml | 8 + mix/qml/js/ProjectModel.js | 39 + mix/res.qrc | 1 + 21 files changed, 7625 insertions(+), 22 deletions(-) create mode 100644 libminizip/CMakeLists.txt create mode 100644 libminizip/crypt.h create mode 100644 libminizip/ioapi.c create mode 100644 libminizip/ioapi.h create mode 100644 libminizip/iowin32.c create mode 100644 libminizip/iowin32.h create mode 100644 libminizip/miniunz.c create mode 100644 libminizip/minizip.c create mode 100644 libminizip/mztools.c create mode 100644 libminizip/mztools.h create mode 100644 libminizip/unzip.c create mode 100644 libminizip/unzip.h create mode 100644 libminizip/zip.c create mode 100644 libminizip/zip.h create mode 100644 mix/qml/DeploymentDialog.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cd7a80c4..6b20a8029 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,6 +167,7 @@ add_subdirectory(libethereum) add_subdirectory(libwebthree) add_subdirectory(test) add_subdirectory(eth) +add_subdirectory(libminizip) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/libminizip/CMakeLists.txt b/libminizip/CMakeLists.txt new file mode 100644 index 000000000..10222006e --- /dev/null +++ b/libminizip/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_policy(SET CMP0015 NEW) +# this policy was introduced in cmake 3.0 +# remove if, once 3.0 will be used on unix +if (${CMAKE_MAJOR_VERSION} GREATER 2) + # old policy do not use MACOSX_RPATH + cmake_policy(SET CMP0042 OLD) +endif() +set(CMAKE_AUTOMOC OFF) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") + +aux_source_directory(. SRC_LIST) + +include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(..) + + +file(GLOB HEADERS "*.h") + +if (ETH_STATIC) + add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) +else() + add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) +endif() + + + +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} evm) +target_link_libraries(${EXECUTABLE} lll) +target_link_libraries(${EXECUTABLE} whisper) +target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethcore) +target_link_libraries(${EXECUTABLE} devcrypto) +target_link_libraries(${EXECUTABLE} secp256k1) + +install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) +install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) + diff --git a/libminizip/crypt.h b/libminizip/crypt.h new file mode 100644 index 000000000..a01d08d93 --- /dev/null +++ b/libminizip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const unsigned long* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/libminizip/ioapi.c b/libminizip/ioapi.c new file mode 100644 index 000000000..49958f61f --- /dev/null +++ b/libminizip/ioapi.c @@ -0,0 +1,235 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if (defined(_WIN32)) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == ((uLong)-1)) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen64((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = ftello64((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/libminizip/ioapi.h b/libminizip/ioapi.h new file mode 100644 index 000000000..8309c4cf8 --- /dev/null +++ b/libminizip/ioapi.h @@ -0,0 +1,200 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libminizip/iowin32.c b/libminizip/iowin32.c new file mode 100644 index 000000000..6a2a883be --- /dev/null +++ b/libminizip/iowin32.c @@ -0,0 +1,389 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); +uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); +long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); +int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + + +static void win32_translate_open_mode(int mode, + DWORD* lpdwDesiredAccess, + DWORD* lpdwCreationDisposition, + DWORD* lpdwShareMode, + DWORD* lpdwFlagsAndAttributes) +{ + *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + *lpdwDesiredAccess = GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + *lpdwShareMode = FILE_SHARE_READ; + } + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + } + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = CREATE_ALWAYS; + } +} + +static voidpf win32_build_iowin(HANDLE hFile) +{ + voidpf ret=NULL; + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + + if (ret==NULL) + CloseHandle(hFile); + else + *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + +voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + + +uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + +long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)dwSet; + } + return ret; +} + +ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret= (ZPOS64_T)-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + if (hFile) + { + LARGE_INTEGER li; + li.QuadPart = 0; + li.u.LowPart = SetFilePointer(hFile, li.u.LowPart, &li.u.HighPart, FILE_CURRENT); + if ( (li.LowPart == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = (ZPOS64_T)-1; + } + else + ret=li.QuadPart; + } + return ret; +} + + +long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + long ret=-1; + + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile) + { + LARGE_INTEGER* li = (LARGE_INTEGER*)&offset; + DWORD dwSet = SetFilePointer(hFile, li->u.LowPart, &li->u.HighPart, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/libminizip/iowin32.h b/libminizip/iowin32.h new file mode 100644 index 000000000..0ca0969a7 --- /dev/null +++ b/libminizip/iowin32.h @@ -0,0 +1,28 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/libminizip/miniunz.c b/libminizip/miniunz.c new file mode 100644 index 000000000..9ed009fbd --- /dev/null +++ b/libminizip/miniunz.c @@ -0,0 +1,648 @@ +/* + miniunz.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + +#ifndef _WIN32 + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +#else +# include +# include +#endif + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef _WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef _WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef _WIN32 + ret = _mkdir(dirname); +#else +#ifdef unix + ret = mkdir (dirname,0775); +#endif +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + +void Display64BitsSize(ZPOS64_T n, int size_char) +{ + /* to avoid compatibility problem , we do here the conversion */ + char number[21]; + int offset=19; + int pos_string = 19; + number[20]=0; + for (;;) { + number[offset]=(char)((n%10)+'0'); + if (number[offset] != '0') + pos_string=offset; + n/=10; + if (offset==0) + break; + offset--; + } + { + int size_display_string = 19-pos_string; + while (size_char > size_display_string) + { + size_char--; + printf(" "); + } + } + + printf("%s",&number[pos_string]); +} + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info64 gi; + int err; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } + else + string_method="Unkn. "; + + Display64BitsSize(file_info.uncompressed_size,7); + printf(" %6s%c",string_method,charCrypt); + Display64BitsSize(file_info.compressed_size,7); + printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen64(write_filename,"wb"); + + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=fopen64(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info64 gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "zip.h" + +#ifdef _WIN32 + #define USEWIN32IOAPI + #include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef _WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen64(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); + printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n\n" \ + " -j exclude path. store only the file name.\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen64(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n", filenameinzip, calculate_crc); + return err; +} + +int isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = fopen64(filename, "rb"); + + if(pFile != NULL) + { + int n = fseeko64(pFile, 0, SEEK_END); + + pos = ftello64(pFile); + + printf("File : %s is %lld bytes\n", filename, pos); + + if(pos >= 0xffffffff) + largeFile = 1; + + fclose(pFile); + } + + return largeFile; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + +/* + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); +*/ + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + zip64 = isLargeFile(filenameinzip); + + /* The path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile, zip64); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = fopen64(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} diff --git a/libminizip/mztools.c b/libminizip/mztools.c new file mode 100644 index 000000000..f9092e65a --- /dev/null +++ b/libminizip/mztools.c @@ -0,0 +1,281 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/libminizip/mztools.h b/libminizip/mztools.h new file mode 100644 index 000000000..88b34592b --- /dev/null +++ b/libminizip/mztools.h @@ -0,0 +1,31 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/libminizip/unzip.c b/libminizip/unzip.c new file mode 100644 index 000000000..7617f41f1 --- /dev/null +++ b/libminizip/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == (unsigned long)-1) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if (err==UNZ_OK) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/libminizip/unzip.h b/libminizip/unzip.h new file mode 100644 index 000000000..3183968b7 --- /dev/null +++ b/libminizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/libminizip/zip.c b/libminizip/zip.c new file mode 100644 index 000000000..3c34fc8bd --- /dev/null +++ b/libminizip/zip.c @@ -0,0 +1,2004 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/libminizip/zip.h b/libminizip/zip.h new file mode 100644 index 000000000..88feecc84 --- /dev/null +++ b/libminizip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib/zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 818d8c887..5298cde62 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file FileIo.cpp * @author Arkadiy Paronyan arkadiy@ethdev.com @@ -25,6 +25,8 @@ #include #include #include +#include +#include "libminizip/zip.h" #include "FileIo.h" using namespace dev::mix; @@ -101,3 +103,48 @@ bool FileIo::fileExists(QString const& _url) QFile file(url.path()); return file.exists(); } + +QString compress(QString const& _manifest, QString const& _folder) +{ + zipFile compressed = zipOpen(_folder + "\dapp.zip", APPEND_STATUS_CREATE); + zip_fileinfo zfiManifest = { 0 }; + bool res = zipOpenNewFileInZip(compressed, "manifest.json", + &zfiManifest, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION); + if (res) + { + zipWriteInFileInZip(compressed, _manifest , _manifest.size()); + zipCloseFileInZip(compressed); + } + + QDirIterator dirIt(_folder, QDirIterator::Subdirectories); + while (dirIt.hasNext()) + { + dirIt.next(); + QFile file(dirIt.filePath()); + QByteArray _a; + while (!file.atEnd()) + { + QByteArray line = file.readLine(); + _a.insert(_a, line.begin(), line.end()); + } + zip_fileinfo zfi = { 0 }; + res = zipOpenNewFileInZip(compressed, QFileInfo(dirIt.filePath()).fileName().toStdString(), + &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION); + if (res) + { + zipWriteInFileInZip(compressed, _a, _a.size()); + zipCloseFileInZip(compressed); + } + file.close(); + } + + QFile zip(_folder + "\dapp.zip"); + QByteArray aZip; + while (!zip.atEnd()) + { + QByteArray line = zip.readLine(); + aZip.insert(aZip, line.begin(), line.end()); + } + dev::h256 h = dev::sha3(aZip); + return toHex(h.ref()); +} diff --git a/mix/FileIo.h b/mix/FileIo.h index 08d49e099..f534b4be0 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file FileIo.h * @author Arkadiy Paronyan arkadiy@ethdev.com @@ -52,6 +52,8 @@ public: Q_INVOKABLE void moveFile(QString const& _sourceUrl, QString const& _destUrl); /// Check if file exists Q_INVOKABLE bool fileExists(QString const& _url); + /// Compress a folder, @returns sha3 of the compressed file. + Q_INVOKABLE QString compress(QString const& _manifest, QString const& _folder); private: QString getHomePath() const; diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml new file mode 100644 index 000000000..56d9069cf --- /dev/null +++ b/mix/qml/DeploymentDialog.qml @@ -0,0 +1,88 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 +import QtQuick.Controls.Styles 1.3 +import org.ethereum.qml.QEther 1.0 +import "js/TransactionHelper.js" as TransactionHelper +import "." + +Window { + id: modalTransactionDialog + modality: Qt.ApplicationModal + width: 520 + height: 300 + visible: false + property alias applicationUrlEth: applicationUrlEth.text + property alias applicationUrlHttp: applicationUrlHttp.text + + signal accepted + + function close() + { + visible = false; + } + + function open() + { + visible = true; + } + + ColumnLayout + { + anchors.fill: parent + RowLayout + { + height: 40 + DefaultLabel + { + text: qsTr("Fill in eth application URL") + } + + Rectangle + { + TextField + { + id: applicationUrlEth + } + } + } + + RowLayout + { + height: 40 + DefaultLabel + { + text: qsTr("Fill in http application URL") + } + + Rectangle + { + TextField + { + id: applicationUrlHttp + } + } + } + + RowLayout + { + anchors.bottom: parent.bottom + anchors.right: parent.right; + + Button { + text: qsTr("OK"); + onClicked: { + close(); + accepted(); + } + } + Button { + text: qsTr("Cancel"); + onClicked: close(); + } + } + } + + +} diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index e74be7a9b..fa174053a 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -100,6 +100,14 @@ Item { } } + DeploymentDialog + { + id: deploymentDialog + onAccepted: { + ProjectModelCode.startDeployProject() + } + } + ListModel { id: projectListModel } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index be6c07c5b..fcaa7914f 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -262,11 +262,17 @@ function deployProject(force) { return; } + deploymentDialog.open(); +} + +function startDeployProject() +{ var date = new Date(); var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); var jsonRpcUrl = "http://localhost:8080"; console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); deploymentStarted(); + var code = codeModel.codeHex var rpcRequest = JSON.stringify({ jsonrpc: "2.0", @@ -302,6 +308,11 @@ function finalizeDeployment(deploymentId, address) { //create a dir for frontend files and copy them var deploymentDir = projectPath + deploymentId + "/"; fileIo.makeDir(deploymentDir); + var manifest = { + previous: 'jgjgj67576576576567ytjy', + first: 'ds564rh5656hhfghfg', + entries: [] + }; for (var i = 0; i < projectListModel.count; i++) { var doc = projectListModel.get(i); if (doc.isContract) @@ -324,6 +335,11 @@ function finalizeDeployment(deploymentId, address) { } else fileIo.copyFile(doc.path, deploymentDir + doc.fileName); + var jsonFile = { + path: '/' + doc.fileName, + file: '/' + doc.fileName + } + manifest.entries.push(jsonFile); } //write deployment js var contractAccessor = "contracts[\"" + codeModel.code.contract.name + "\"]"; @@ -342,5 +358,28 @@ function finalizeDeployment(deploymentId, address) { fileIo.copyFile("qrc:///js/webthree.js", deploymentDir + "ethereum.js"); deploymentAddress = address; saveProject(); + + var hash = fileIo.compress(JSON.stringify(manifest), deploymentDir); + //Call Registry + var applicationUrlEth = deploymentDialog.applicationUrlEth; + var applicationUrlHttp = deploymentDialog.applicationUrlHttp; + applicationUrlEth = formatAppUrl(applicationEth); deploymentComplete(); } + +function formatAppUrl(url) +{ + var slash = url.indexof("/"); + var dot = url.indexof("."); + if ((slash === -1 && dot === -1) || dot > slash) + return url; + else + { + var split = url.split("/"); + var dotted = split[0].split("."); + var main = ""; + for (var k in dotted) + main += dotted[k] + '/' + main; + return main; + } +} diff --git a/mix/res.qrc b/mix/res.qrc index 0acf9f39e..4b92d4f67 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -99,5 +99,6 @@ qml/Style.qml qml/WebPreviewStyle.qml qml/img/available_updates.png + qml/DeploymentDialog.qml From 307e42a6c30148dde6d3be474b1960282f4e48b2 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 17 Feb 2015 16:19:11 +0100 Subject: [PATCH 128/201] 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 129/201] 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 130/201] 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 131/201] 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 132/201] 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 133/201] 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 a64147875f702e34455351f47c44737eb8217d47 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 Feb 2015 01:35:33 +0100 Subject: [PATCH 134/201] While deploying: - Register to Registrar contract. - Package dapp. --- CMakeLists.txt | 1 - libminizip/CMakeLists.txt | 39 - libminizip/crypt.h | 131 --- libminizip/ioapi.c | 235 ---- libminizip/ioapi.h | 200 ---- libminizip/iowin32.c | 389 ------- libminizip/iowin32.h | 28 - libminizip/miniunz.c | 648 ----------- libminizip/minizip.c | 507 -------- libminizip/mztools.c | 281 ----- libminizip/mztools.h | 31 - libminizip/unzip.c | 2125 ---------------------------------- libminizip/unzip.h | 437 ------- libminizip/zip.c | 2004 -------------------------------- libminizip/zip.h | 362 ------ mix/FileIo.cpp | 79 +- mix/FileIo.h | 3 +- mix/QVariableDefinition.h | 2 + mix/qml/DeploymentDialog.qml | 96 +- mix/qml/ProjectModel.qml | 5 +- mix/qml/Style.qml | 1 + mix/qml/js/ProjectModel.js | 137 ++- mix/qml/js/QEtherHelper.js | 16 + 23 files changed, 231 insertions(+), 7526 deletions(-) delete mode 100644 libminizip/CMakeLists.txt delete mode 100644 libminizip/crypt.h delete mode 100644 libminizip/ioapi.c delete mode 100644 libminizip/ioapi.h delete mode 100644 libminizip/iowin32.c delete mode 100644 libminizip/iowin32.h delete mode 100644 libminizip/miniunz.c delete mode 100644 libminizip/minizip.c delete mode 100644 libminizip/mztools.c delete mode 100644 libminizip/mztools.h delete mode 100644 libminizip/unzip.c delete mode 100644 libminizip/unzip.h delete mode 100644 libminizip/zip.c delete mode 100644 libminizip/zip.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b20a8029..0cd7a80c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,7 +167,6 @@ add_subdirectory(libethereum) add_subdirectory(libwebthree) add_subdirectory(test) add_subdirectory(eth) -add_subdirectory(libminizip) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/libminizip/CMakeLists.txt b/libminizip/CMakeLists.txt deleted file mode 100644 index 10222006e..000000000 --- a/libminizip/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -cmake_policy(SET CMP0015 NEW) -# this policy was introduced in cmake 3.0 -# remove if, once 3.0 will be used on unix -if (${CMAKE_MAJOR_VERSION} GREATER 2) - # old policy do not use MACOSX_RPATH - cmake_policy(SET CMP0042 OLD) -endif() -set(CMAKE_AUTOMOC OFF) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") - -aux_source_directory(. SRC_LIST) - -include_directories(${LEVELDB_INCLUDE_DIRS}) -include_directories(..) - - -file(GLOB HEADERS "*.h") - -if (ETH_STATIC) - add_library(${EXECUTABLE} STATIC ${SRC_LIST} ${HEADERS}) -else() - add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS}) -endif() - - - -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} evm) -target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} whisper) -target_link_libraries(${EXECUTABLE} p2p) -target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} devcrypto) -target_link_libraries(${EXECUTABLE} secp256k1) - -install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) -install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) - diff --git a/libminizip/crypt.h b/libminizip/crypt.h deleted file mode 100644 index a01d08d93..000000000 --- a/libminizip/crypt.h +++ /dev/null @@ -1,131 +0,0 @@ -/* crypt.h -- base code for crypt/uncrypt ZIPfile - - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This code is a modified version of crypting code in Infozip distribution - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - - If you don't need crypting in your application, just define symbols - NOCRYPT and NOUNCRYPT. - - This code support the "Traditional PKWARE Encryption". - - The new AES encryption added on Zip format by Winzip (see the page - http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong - Encryption is not supported. -*/ - -#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) - -/*********************************************************************** - * Return the next byte in the pseudo-random sequence - */ -static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) -{ - unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an - * unpredictable manner on 16-bit systems; not a problem - * with any known compiler so far, though */ - - temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; - return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -} - -/*********************************************************************** - * Update the encryption keys with the next byte of plain text - */ -static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) -{ - (*(pkeys+0)) = CRC32((*(pkeys+0)), c); - (*(pkeys+1)) += (*(pkeys+0)) & 0xff; - (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; - { - register int keyshift = (int)((*(pkeys+1)) >> 24); - (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); - } - return c; -} - - -/*********************************************************************** - * Initialize the encryption keys and the random header according to - * the given password. - */ -static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) -{ - *(pkeys+0) = 305419896L; - *(pkeys+1) = 591751049L; - *(pkeys+2) = 878082192L; - while (*passwd != '\0') { - update_keys(pkeys,pcrc_32_tab,(int)*passwd); - passwd++; - } -} - -#define zdecode(pkeys,pcrc_32_tab,c) \ - (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) - -#define zencode(pkeys,pcrc_32_tab,c,t) \ - (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) - -#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED - -#define RAND_HEAD_LEN 12 - /* "last resort" source for second part of crypt seed pattern */ -# ifndef ZCR_SEED2 -# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ -# endif - -static int crypthead(const char* passwd, /* password string */ - unsigned char* buf, /* where to write header */ - int bufSize, - unsigned long* pkeys, - const unsigned long* pcrc_32_tab, - unsigned long crcForCrypting) -{ - int n; /* index in random header */ - int t; /* temporary */ - int c; /* random byte */ - unsigned char header[RAND_HEAD_LEN-2]; /* random header */ - static unsigned calls = 0; /* ensure different random header each time */ - - if (bufSize> 7) & 0xff; - header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); - } - /* Encrypt random header (last two bytes is high word of crc) */ - init_keys(passwd, pkeys, pcrc_32_tab); - for (n = 0; n < RAND_HEAD_LEN-2; n++) - { - buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); - } - buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); - buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); - return n; -} - -#endif diff --git a/libminizip/ioapi.c b/libminizip/ioapi.c deleted file mode 100644 index 49958f61f..000000000 --- a/libminizip/ioapi.c +++ /dev/null @@ -1,235 +0,0 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - -*/ - -#if (defined(_WIN32)) - #define _CRT_SECURE_NO_WARNINGS -#endif - -#include "ioapi.h" - -voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) -{ - if (pfilefunc->zfile_func64.zopen64_file != NULL) - return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); - else - { - return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); - } -} - -long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) -{ - if (pfilefunc->zfile_func64.zseek64_file != NULL) - return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); - else - { - uLong offsetTruncated = (uLong)offset; - if (offsetTruncated != offset) - return -1; - else - return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); - } -} - -ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) -{ - if (pfilefunc->zfile_func64.zseek64_file != NULL) - return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); - else - { - uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); - if ((tell_uLong) == ((uLong)-1)) - return (ZPOS64_T)-1; - else - return tell_uLong; - } -} - -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) -{ - p_filefunc64_32->zfile_func64.zopen64_file = NULL; - p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; - p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; - p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; - p_filefunc64_32->zfile_func64.ztell64_file = NULL; - p_filefunc64_32->zfile_func64.zseek64_file = NULL; - p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; - p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; - p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; - p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; -} - - - -static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); -static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); -static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); -static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); -static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); - -static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) -{ - FILE* file = NULL; - const char* mode_fopen = NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - mode_fopen = "rb"; - else - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - mode_fopen = "r+b"; - else - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - mode_fopen = "wb"; - - if ((filename!=NULL) && (mode_fopen != NULL)) - file = fopen(filename, mode_fopen); - return file; -} - -static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) -{ - FILE* file = NULL; - const char* mode_fopen = NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - mode_fopen = "rb"; - else - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - mode_fopen = "r+b"; - else - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - mode_fopen = "wb"; - - if ((filename!=NULL) && (mode_fopen != NULL)) - file = fopen64((const char*)filename, mode_fopen); - return file; -} - - -static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) -{ - uLong ret; - ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); - return ret; -} - -static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) -{ - uLong ret; - ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); - return ret; -} - -static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) -{ - long ret; - ret = ftell((FILE *)stream); - return ret; -} - - -static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) -{ - ZPOS64_T ret; - ret = ftello64((FILE *)stream); - return ret; -} - -static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) -{ - int fseek_origin=0; - long ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - fseek_origin = SEEK_CUR; - break; - case ZLIB_FILEFUNC_SEEK_END : - fseek_origin = SEEK_END; - break; - case ZLIB_FILEFUNC_SEEK_SET : - fseek_origin = SEEK_SET; - break; - default: return -1; - } - ret = 0; - if (fseek((FILE *)stream, offset, fseek_origin) != 0) - ret = -1; - return ret; -} - -static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) -{ - int fseek_origin=0; - long ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - fseek_origin = SEEK_CUR; - break; - case ZLIB_FILEFUNC_SEEK_END : - fseek_origin = SEEK_END; - break; - case ZLIB_FILEFUNC_SEEK_SET : - fseek_origin = SEEK_SET; - break; - default: return -1; - } - ret = 0; - - if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) - ret = -1; - - return ret; -} - - -static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) -{ - int ret; - ret = fclose((FILE *)stream); - return ret; -} - -static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) -{ - int ret; - ret = ferror((FILE *)stream); - return ret; -} - -void fill_fopen_filefunc (pzlib_filefunc_def) - zlib_filefunc_def* pzlib_filefunc_def; -{ - pzlib_filefunc_def->zopen_file = fopen_file_func; - pzlib_filefunc_def->zread_file = fread_file_func; - pzlib_filefunc_def->zwrite_file = fwrite_file_func; - pzlib_filefunc_def->ztell_file = ftell_file_func; - pzlib_filefunc_def->zseek_file = fseek_file_func; - pzlib_filefunc_def->zclose_file = fclose_file_func; - pzlib_filefunc_def->zerror_file = ferror_file_func; - pzlib_filefunc_def->opaque = NULL; -} - -void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen64_file = fopen64_file_func; - pzlib_filefunc_def->zread_file = fread_file_func; - pzlib_filefunc_def->zwrite_file = fwrite_file_func; - pzlib_filefunc_def->ztell64_file = ftell64_file_func; - pzlib_filefunc_def->zseek64_file = fseek64_file_func; - pzlib_filefunc_def->zclose_file = fclose_file_func; - pzlib_filefunc_def->zerror_file = ferror_file_func; - pzlib_filefunc_def->opaque = NULL; -} diff --git a/libminizip/ioapi.h b/libminizip/ioapi.h deleted file mode 100644 index 8309c4cf8..000000000 --- a/libminizip/ioapi.h +++ /dev/null @@ -1,200 +0,0 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - Changes - - Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) - Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. - More if/def section may be needed to support other platforms - Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. - (but you should use iowin32.c for windows instead) - -*/ - -#ifndef _ZLIBIOAPI64_H -#define _ZLIBIOAPI64_H - -#if (!defined(_WIN32)) && (!defined(WIN32)) - - // Linux needs this to support file operation on files larger then 4+GB - // But might need better if/def to select just the platforms that needs them. - - #ifndef __USE_FILE_OFFSET64 - #define __USE_FILE_OFFSET64 - #endif - #ifndef __USE_LARGEFILE64 - #define __USE_LARGEFILE64 - #endif - #ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE - #endif - #ifndef _FILE_OFFSET_BIT - #define _FILE_OFFSET_BIT 64 - #endif -#endif - -#include -#include -#include "zlib.h" - -#if defined(USE_FILE32API) -#define fopen64 fopen -#define ftello64 ftell -#define fseeko64 fseek -#else -#ifdef _MSC_VER - #define fopen64 fopen - #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) - #define ftello64 _ftelli64 - #define fseeko64 _fseeki64 - #else // old MSC - #define ftello64 ftell - #define fseeko64 fseek - #endif -#endif -#endif - -/* -#ifndef ZPOS64_T - #ifdef _WIN32 - #define ZPOS64_T fpos_t - #else - #include - #define ZPOS64_T uint64_t - #endif -#endif -*/ - -#ifdef HAVE_MINIZIP64_CONF_H -#include "mz64conf.h" -#endif - -/* a type choosen by DEFINE */ -#ifdef HAVE_64BIT_INT_CUSTOM -typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; -#else -#ifdef HAS_STDINT_H -#include "stdint.h" -typedef uint64_t ZPOS64_T; -#else - - -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef unsigned __int64 ZPOS64_T; -#else -typedef unsigned long long int ZPOS64_T; -#endif -#endif -#endif - - - -#ifdef __cplusplus -extern "C" { -#endif - - -#define ZLIB_FILEFUNC_SEEK_CUR (1) -#define ZLIB_FILEFUNC_SEEK_END (2) -#define ZLIB_FILEFUNC_SEEK_SET (0) - -#define ZLIB_FILEFUNC_MODE_READ (1) -#define ZLIB_FILEFUNC_MODE_WRITE (2) -#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) - -#define ZLIB_FILEFUNC_MODE_EXISTING (4) -#define ZLIB_FILEFUNC_MODE_CREATE (8) - - -#ifndef ZCALLBACK - #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) - #define ZCALLBACK CALLBACK - #else - #define ZCALLBACK - #endif -#endif - - - - -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); -typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); - -typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); - - -/* here is the "old" 32 bits structure structure */ -typedef struct zlib_filefunc_def_s -{ - open_file_func zopen_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell_file_func ztell_file; - seek_file_func zseek_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc_def; - -typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); - -typedef struct zlib_filefunc64_def_s -{ - open64_file_func zopen64_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell64_file_func ztell64_file; - seek64_file_func zseek64_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc64_def; - -void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); - -/* now internal definition, only for zip.c and unzip.h */ -typedef struct zlib_filefunc64_32_def_s -{ - zlib_filefunc64_def zfile_func64; - open_file_func zopen32_file; - tell_file_func ztell32_file; - seek_file_func zseek32_file; -} zlib_filefunc64_32_def; - - -#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) -#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) -//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) -//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) -#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) -#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) - -voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); -long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); -ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); - -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); - -#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) -#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) -#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libminizip/iowin32.c b/libminizip/iowin32.c deleted file mode 100644 index 6a2a883be..000000000 --- a/libminizip/iowin32.c +++ /dev/null @@ -1,389 +0,0 @@ -/* iowin32.c -- IO base function header for compress/uncompress .zip - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - -*/ - -#include - -#include "zlib.h" -#include "ioapi.h" -#include "iowin32.h" - -#ifndef INVALID_HANDLE_VALUE -#define INVALID_HANDLE_VALUE (0xFFFFFFFF) -#endif - -#ifndef INVALID_SET_FILE_POINTER -#define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif - -voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); -uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); -long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); -int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); - -typedef struct -{ - HANDLE hf; - int error; -} WIN32FILE_IOWIN; - - -static void win32_translate_open_mode(int mode, - DWORD* lpdwDesiredAccess, - DWORD* lpdwCreationDisposition, - DWORD* lpdwShareMode, - DWORD* lpdwFlagsAndAttributes) -{ - *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; - - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - { - *lpdwDesiredAccess = GENERIC_READ; - *lpdwCreationDisposition = OPEN_EXISTING; - *lpdwShareMode = FILE_SHARE_READ; - } - else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - { - *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; - *lpdwCreationDisposition = OPEN_EXISTING; - } - else if (mode & ZLIB_FILEFUNC_MODE_CREATE) - { - *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; - *lpdwCreationDisposition = CREATE_ALWAYS; - } -} - -static voidpf win32_build_iowin(HANDLE hFile) -{ - voidpf ret=NULL; - - if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) - { - WIN32FILE_IOWIN w32fiow; - w32fiow.hf = hFile; - w32fiow.error = 0; - ret = malloc(sizeof(WIN32FILE_IOWIN)); - - if (ret==NULL) - CloseHandle(hFile); - else - *((WIN32FILE_IOWIN*)ret) = w32fiow; - } - return ret; -} - -voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) -{ - const char* mode_fopen = NULL; - DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; - HANDLE hFile = NULL; - - win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); - - if ((filename!=NULL) && (dwDesiredAccess != 0)) - hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); - - return win32_build_iowin(hFile); -} - - -voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) -{ - const char* mode_fopen = NULL; - DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; - HANDLE hFile = NULL; - - win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); - - if ((filename!=NULL) && (dwDesiredAccess != 0)) - hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); - - return win32_build_iowin(hFile); -} - - -voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) -{ - const char* mode_fopen = NULL; - DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; - HANDLE hFile = NULL; - - win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); - - if ((filename!=NULL) && (dwDesiredAccess != 0)) - hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); - - return win32_build_iowin(hFile); -} - - -voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) -{ - const char* mode_fopen = NULL; - DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; - HANDLE hFile = NULL; - - win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); - - if ((filename!=NULL) && (dwDesiredAccess != 0)) - hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); - - return win32_build_iowin(hFile); -} - - -uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) -{ - uLong ret=0; - HANDLE hFile = NULL; - if (stream!=NULL) - hFile = ((WIN32FILE_IOWIN*)stream) -> hf; - - if (hFile != NULL) - { - if (!ReadFile(hFile, buf, size, &ret, NULL)) - { - DWORD dwErr = GetLastError(); - if (dwErr == ERROR_HANDLE_EOF) - dwErr = 0; - ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; - } - } - - return ret; -} - - -uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) -{ - uLong ret=0; - HANDLE hFile = NULL; - if (stream!=NULL) - hFile = ((WIN32FILE_IOWIN*)stream) -> hf; - - if (hFile != NULL) - { - if (!WriteFile(hFile, buf, size, &ret, NULL)) - { - DWORD dwErr = GetLastError(); - if (dwErr == ERROR_HANDLE_EOF) - dwErr = 0; - ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; - } - } - - return ret; -} - -long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) -{ - long ret=-1; - HANDLE hFile = NULL; - if (stream!=NULL) - hFile = ((WIN32FILE_IOWIN*)stream) -> hf; - if (hFile != NULL) - { - DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); - if (dwSet == INVALID_SET_FILE_POINTER) - { - DWORD dwErr = GetLastError(); - ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; - ret = -1; - } - else - ret=(long)dwSet; - } - return ret; -} - -ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) -{ - ZPOS64_T ret= (ZPOS64_T)-1; - HANDLE hFile = NULL; - if (stream!=NULL) - hFile = ((WIN32FILE_IOWIN*)stream)->hf; - - if (hFile) - { - LARGE_INTEGER li; - li.QuadPart = 0; - li.u.LowPart = SetFilePointer(hFile, li.u.LowPart, &li.u.HighPart, FILE_CURRENT); - if ( (li.LowPart == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) - { - DWORD dwErr = GetLastError(); - ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; - ret = (ZPOS64_T)-1; - } - else - ret=li.QuadPart; - } - return ret; -} - - -long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) -{ - DWORD dwMoveMethod=0xFFFFFFFF; - HANDLE hFile = NULL; - - long ret=-1; - if (stream!=NULL) - hFile = ((WIN32FILE_IOWIN*)stream) -> hf; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - dwMoveMethod = FILE_CURRENT; - break; - case ZLIB_FILEFUNC_SEEK_END : - dwMoveMethod = FILE_END; - break; - case ZLIB_FILEFUNC_SEEK_SET : - dwMoveMethod = FILE_BEGIN; - break; - default: return -1; - } - - if (hFile != NULL) - { - DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); - if (dwSet == INVALID_SET_FILE_POINTER) - { - DWORD dwErr = GetLastError(); - ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; - ret = -1; - } - else - ret=0; - } - return ret; -} - -long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) -{ - DWORD dwMoveMethod=0xFFFFFFFF; - HANDLE hFile = NULL; - long ret=-1; - - if (stream!=NULL) - hFile = ((WIN32FILE_IOWIN*)stream)->hf; - - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - dwMoveMethod = FILE_CURRENT; - break; - case ZLIB_FILEFUNC_SEEK_END : - dwMoveMethod = FILE_END; - break; - case ZLIB_FILEFUNC_SEEK_SET : - dwMoveMethod = FILE_BEGIN; - break; - default: return -1; - } - - if (hFile) - { - LARGE_INTEGER* li = (LARGE_INTEGER*)&offset; - DWORD dwSet = SetFilePointer(hFile, li->u.LowPart, &li->u.HighPart, dwMoveMethod); - if (dwSet == INVALID_SET_FILE_POINTER) - { - DWORD dwErr = GetLastError(); - ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; - ret = -1; - } - else - ret=0; - } - return ret; -} - -int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) -{ - int ret=-1; - - if (stream!=NULL) - { - HANDLE hFile; - hFile = ((WIN32FILE_IOWIN*)stream) -> hf; - if (hFile != NULL) - { - CloseHandle(hFile); - ret=0; - } - free(stream); - } - return ret; -} - -int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) -{ - int ret=-1; - if (stream!=NULL) - { - ret = ((WIN32FILE_IOWIN*)stream) -> error; - } - return ret; -} - -void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen_file = win32_open_file_func; - pzlib_filefunc_def->zread_file = win32_read_file_func; - pzlib_filefunc_def->zwrite_file = win32_write_file_func; - pzlib_filefunc_def->ztell_file = win32_tell_file_func; - pzlib_filefunc_def->zseek_file = win32_seek_file_func; - pzlib_filefunc_def->zclose_file = win32_close_file_func; - pzlib_filefunc_def->zerror_file = win32_error_file_func; - pzlib_filefunc_def->opaque = NULL; -} - -void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen64_file = win32_open64_file_func; - pzlib_filefunc_def->zread_file = win32_read_file_func; - pzlib_filefunc_def->zwrite_file = win32_write_file_func; - pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; - pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; - pzlib_filefunc_def->zclose_file = win32_close_file_func; - pzlib_filefunc_def->zerror_file = win32_error_file_func; - pzlib_filefunc_def->opaque = NULL; -} - - -void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; - pzlib_filefunc_def->zread_file = win32_read_file_func; - pzlib_filefunc_def->zwrite_file = win32_write_file_func; - pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; - pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; - pzlib_filefunc_def->zclose_file = win32_close_file_func; - pzlib_filefunc_def->zerror_file = win32_error_file_func; - pzlib_filefunc_def->opaque = NULL; -} - - -void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; - pzlib_filefunc_def->zread_file = win32_read_file_func; - pzlib_filefunc_def->zwrite_file = win32_write_file_func; - pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; - pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; - pzlib_filefunc_def->zclose_file = win32_close_file_func; - pzlib_filefunc_def->zerror_file = win32_error_file_func; - pzlib_filefunc_def->opaque = NULL; -} diff --git a/libminizip/iowin32.h b/libminizip/iowin32.h deleted file mode 100644 index 0ca0969a7..000000000 --- a/libminizip/iowin32.h +++ /dev/null @@ -1,28 +0,0 @@ -/* iowin32.h -- IO base function header for compress/uncompress .zip - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - -*/ - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); -void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); - -#ifdef __cplusplus -} -#endif diff --git a/libminizip/miniunz.c b/libminizip/miniunz.c deleted file mode 100644 index 9ed009fbd..000000000 --- a/libminizip/miniunz.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - miniunz.c - Version 1.1, February 14h, 2010 - sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications of Unzip for Zip64 - Copyright (C) 2007-2008 Even Rouault - - Modifications for Zip64 support on both zip and unzip - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) -*/ - -#ifndef _WIN32 - #ifndef __USE_FILE_OFFSET64 - #define __USE_FILE_OFFSET64 - #endif - #ifndef __USE_LARGEFILE64 - #define __USE_LARGEFILE64 - #endif - #ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE - #endif - #ifndef _FILE_OFFSET_BIT - #define _FILE_OFFSET_BIT 64 - #endif -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef unix -# include -# include -#else -# include -# include -#endif - -#include "unzip.h" - -#define CASESENSITIVITY (0) -#define WRITEBUFFERSIZE (8192) -#define MAXFILENAME (256) - -#ifdef _WIN32 -#define USEWIN32IOAPI -#include "iowin32.h" -#endif -/* - mini unzip, demo of unzip package - - usage : - Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] - - list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT - if it exists -*/ - - -/* change_file_date : change the date/time of a file - filename : the filename of the file where date/time must be modified - dosdate : the new date at the MSDos format (4 bytes) - tmu_date : the SAME new date at the tm_unz format */ -void change_file_date(filename,dosdate,tmu_date) - const char *filename; - uLong dosdate; - tm_unz tmu_date; -{ -#ifdef _WIN32 - HANDLE hFile; - FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; - - hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, - 0,NULL,OPEN_EXISTING,0,NULL); - GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); - DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); - LocalFileTimeToFileTime(&ftLocal,&ftm); - SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); - CloseHandle(hFile); -#else -#ifdef unix - struct utimbuf ut; - struct tm newdate; - newdate.tm_sec = tmu_date.tm_sec; - newdate.tm_min=tmu_date.tm_min; - newdate.tm_hour=tmu_date.tm_hour; - newdate.tm_mday=tmu_date.tm_mday; - newdate.tm_mon=tmu_date.tm_mon; - if (tmu_date.tm_year > 1900) - newdate.tm_year=tmu_date.tm_year - 1900; - else - newdate.tm_year=tmu_date.tm_year ; - newdate.tm_isdst=-1; - - ut.actime=ut.modtime=mktime(&newdate); - utime(filename,&ut); -#endif -#endif -} - - -/* mymkdir and change_file_date are not 100 % portable - As I don't know well Unix, I wait feedback for the unix portion */ - -int mymkdir(dirname) - const char* dirname; -{ - int ret=0; -#ifdef _WIN32 - ret = _mkdir(dirname); -#else -#ifdef unix - ret = mkdir (dirname,0775); -#endif -#endif - return ret; -} - -int makedir (newdir) - char *newdir; -{ - char *buffer ; - char *p; - int len = (int)strlen(newdir); - - if (len <= 0) - return 0; - - buffer = (char*)malloc(len+1); - if (buffer==NULL) - { - printf("Error allocating memory\n"); - return UNZ_INTERNALERROR; - } - strcpy(buffer,newdir); - - if (buffer[len-1] == '/') { - buffer[len-1] = '\0'; - } - if (mymkdir(buffer) == 0) - { - free(buffer); - return 1; - } - - p = buffer+1; - while (1) - { - char hold; - - while(*p && *p != '\\' && *p != '/') - p++; - hold = *p; - *p = 0; - if ((mymkdir(buffer) == -1) && (errno == ENOENT)) - { - printf("couldn't create directory %s\n",buffer); - free(buffer); - return 0; - } - if (hold == 0) - break; - *p++ = hold; - } - free(buffer); - return 1; -} - -void do_banner() -{ - printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); - printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); -} - -void do_help() -{ - printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ - " -e Extract without pathname (junk paths)\n" \ - " -x Extract with pathname\n" \ - " -v list files\n" \ - " -l list files\n" \ - " -d directory to extract into\n" \ - " -o overwrite files without prompting\n" \ - " -p extract crypted file using password\n\n"); -} - -void Display64BitsSize(ZPOS64_T n, int size_char) -{ - /* to avoid compatibility problem , we do here the conversion */ - char number[21]; - int offset=19; - int pos_string = 19; - number[20]=0; - for (;;) { - number[offset]=(char)((n%10)+'0'); - if (number[offset] != '0') - pos_string=offset; - n/=10; - if (offset==0) - break; - offset--; - } - { - int size_display_string = 19-pos_string; - while (size_char > size_display_string) - { - size_char--; - printf(" "); - } - } - - printf("%s",&number[pos_string]); -} - -int do_list(uf) - unzFile uf; -{ - uLong i; - unz_global_info64 gi; - int err; - - err = unzGetGlobalInfo64(uf,&gi); - if (err!=UNZ_OK) - printf("error %d with zipfile in unzGetGlobalInfo \n",err); - printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); - printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); - for (i=0;i0) - ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); - - /* display a '*' if the file is crypted */ - if ((file_info.flag & 1) != 0) - charCrypt='*'; - - if (file_info.compression_method==0) - string_method="Stored"; - else - if (file_info.compression_method==Z_DEFLATED) - { - uInt iLevel=(uInt)((file_info.flag & 0x6)/2); - if (iLevel==0) - string_method="Defl:N"; - else if (iLevel==1) - string_method="Defl:X"; - else if ((iLevel==2) || (iLevel==3)) - string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ - } - else - if (file_info.compression_method==Z_BZIP2ED) - { - string_method="BZip2 "; - } - else - string_method="Unkn. "; - - Display64BitsSize(file_info.uncompressed_size,7); - printf(" %6s%c",string_method,charCrypt); - Display64BitsSize(file_info.compressed_size,7); - printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", - ratio, - (uLong)file_info.tmu_date.tm_mon + 1, - (uLong)file_info.tmu_date.tm_mday, - (uLong)file_info.tmu_date.tm_year % 100, - (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, - (uLong)file_info.crc,filename_inzip); - if ((i+1)='a') && (rep<='z')) - rep -= 0x20; - } - while ((rep!='Y') && (rep!='N') && (rep!='A')); - } - - if (rep == 'N') - skip = 1; - - if (rep == 'A') - *popt_overwrite=1; - } - - if ((skip==0) && (err==UNZ_OK)) - { - fout=fopen64(write_filename,"wb"); - - /* some zipfile don't contain directory alone before file */ - if ((fout==NULL) && ((*popt_extract_without_path)==0) && - (filename_withoutpath!=(char*)filename_inzip)) - { - char c=*(filename_withoutpath-1); - *(filename_withoutpath-1)='\0'; - makedir(write_filename); - *(filename_withoutpath-1)=c; - fout=fopen64(write_filename,"wb"); - } - - if (fout==NULL) - { - printf("error opening %s\n",write_filename); - } - } - - if (fout!=NULL) - { - printf(" extracting: %s\n",write_filename); - - do - { - err = unzReadCurrentFile(uf,buf,size_buf); - if (err<0) - { - printf("error %d with zipfile in unzReadCurrentFile\n",err); - break; - } - if (err>0) - if (fwrite(buf,err,1,fout)!=1) - { - printf("error in writing extracted file\n"); - err=UNZ_ERRNO; - break; - } - } - while (err>0); - if (fout) - fclose(fout); - - if (err==0) - change_file_date(write_filename,file_info.dosDate, - file_info.tmu_date); - } - - if (err==UNZ_OK) - { - err = unzCloseCurrentFile (uf); - if (err!=UNZ_OK) - { - printf("error %d with zipfile in unzCloseCurrentFile\n",err); - } - } - else - unzCloseCurrentFile(uf); /* don't lose the error */ - } - - free(buf); - return err; -} - - -int do_extract(uf,opt_extract_without_path,opt_overwrite,password) - unzFile uf; - int opt_extract_without_path; - int opt_overwrite; - const char* password; -{ - uLong i; - unz_global_info64 gi; - int err; - FILE* fout=NULL; - - err = unzGetGlobalInfo64(uf,&gi); - if (err!=UNZ_OK) - printf("error %d with zipfile in unzGetGlobalInfo \n",err); - - for (i=0;i -#include -#include -#include -#include -#include - -#ifdef unix -# include -# include -# include -# include -#else -# include -# include -#endif - -#include "zip.h" - -#ifdef _WIN32 - #define USEWIN32IOAPI - #include "iowin32.h" -#endif - - - -#define WRITEBUFFERSIZE (16384) -#define MAXFILENAME (256) - -#ifdef _WIN32 -uLong filetime(f, tmzip, dt) - char *f; /* name of file to get info on */ - tm_zip *tmzip; /* return value: access, modific. and creation times */ - uLong *dt; /* dostime */ -{ - int ret = 0; - { - FILETIME ftLocal; - HANDLE hFind; - WIN32_FIND_DATAA ff32; - - hFind = FindFirstFileA(f,&ff32); - if (hFind != INVALID_HANDLE_VALUE) - { - FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); - FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); - FindClose(hFind); - ret = 1; - } - } - return ret; -} -#else -#ifdef unix -uLong filetime(f, tmzip, dt) - char *f; /* name of file to get info on */ - tm_zip *tmzip; /* return value: access, modific. and creation times */ - uLong *dt; /* dostime */ -{ - int ret=0; - struct stat s; /* results of stat() */ - struct tm* filedate; - time_t tm_t=0; - - if (strcmp(f,"-")!=0) - { - char name[MAXFILENAME+1]; - int len = strlen(f); - if (len > MAXFILENAME) - len = MAXFILENAME; - - strncpy(name, f,MAXFILENAME-1); - /* strncpy doesnt append the trailing NULL, of the string is too long. */ - name[ MAXFILENAME ] = '\0'; - - if (name[len - 1] == '/') - name[len - 1] = '\0'; - /* not all systems allow stat'ing a file with / appended */ - if (stat(name,&s)==0) - { - tm_t = s.st_mtime; - ret = 1; - } - } - filedate = localtime(&tm_t); - - tmzip->tm_sec = filedate->tm_sec; - tmzip->tm_min = filedate->tm_min; - tmzip->tm_hour = filedate->tm_hour; - tmzip->tm_mday = filedate->tm_mday; - tmzip->tm_mon = filedate->tm_mon ; - tmzip->tm_year = filedate->tm_year; - - return ret; -} -#else -uLong filetime(f, tmzip, dt) - char *f; /* name of file to get info on */ - tm_zip *tmzip; /* return value: access, modific. and creation times */ - uLong *dt; /* dostime */ -{ - return 0; -} -#endif -#endif - - - - -int check_exist_file(filename) - const char* filename; -{ - FILE* ftestexist; - int ret = 1; - ftestexist = fopen64(filename,"rb"); - if (ftestexist==NULL) - ret = 0; - else - fclose(ftestexist); - return ret; -} - -void do_banner() -{ - printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); - printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); -} - -void do_help() -{ - printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ - " -o Overwrite existing file.zip\n" \ - " -a Append to existing file.zip\n" \ - " -0 Store only\n" \ - " -1 Compress faster\n" \ - " -9 Compress better\n\n" \ - " -j exclude path. store only the file name.\n\n"); -} - -/* calculate the CRC32 of a file, - because to encrypt a file, we need known the CRC32 of the file before */ -int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) -{ - unsigned long calculate_crc=0; - int err=ZIP_OK; - FILE * fin = fopen64(filenameinzip,"rb"); - unsigned long size_read = 0; - unsigned long total_read = 0; - if (fin==NULL) - { - err = ZIP_ERRNO; - } - - if (err == ZIP_OK) - do - { - err = ZIP_OK; - size_read = (int)fread(buf,1,size_buf,fin); - if (size_read < size_buf) - if (feof(fin)==0) - { - printf("error in reading %s\n",filenameinzip); - err = ZIP_ERRNO; - } - - if (size_read>0) - calculate_crc = crc32(calculate_crc,buf,size_read); - total_read += size_read; - - } while ((err == ZIP_OK) && (size_read>0)); - - if (fin) - fclose(fin); - - *result_crc=calculate_crc; - printf("file %s crc %lx\n", filenameinzip, calculate_crc); - return err; -} - -int isLargeFile(const char* filename) -{ - int largeFile = 0; - ZPOS64_T pos = 0; - FILE* pFile = fopen64(filename, "rb"); - - if(pFile != NULL) - { - int n = fseeko64(pFile, 0, SEEK_END); - - pos = ftello64(pFile); - - printf("File : %s is %lld bytes\n", filename, pos); - - if(pos >= 0xffffffff) - largeFile = 1; - - fclose(pFile); - } - - return largeFile; -} - -int main(argc,argv) - int argc; - char *argv[]; -{ - int i; - int opt_overwrite=0; - int opt_compress_level=Z_DEFAULT_COMPRESSION; - int opt_exclude_path=0; - int zipfilenamearg = 0; - char filename_try[MAXFILENAME+16]; - int zipok; - int err=0; - int size_buf=0; - void* buf=NULL; - const char* password=NULL; - - - do_banner(); - if (argc==1) - { - do_help(); - return 0; - } - else - { - for (i=1;i='0') && (c<='9')) - opt_compress_level = c-'0'; - if ((c=='j') || (c=='J')) - opt_exclude_path = 1; - - if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) - rep -= 0x20; - } - while ((rep!='Y') && (rep!='N') && (rep!='A')); - if (rep=='N') - zipok = 0; - if (rep=='A') - opt_overwrite = 2; - } - } - - if (zipok==1) - { - zipFile zf; - int errclose; -# ifdef USEWIN32IOAPI - zlib_filefunc64_def ffunc; - fill_win32_filefunc64A(&ffunc); - zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); -# else - zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); -# endif - - if (zf == NULL) - { - printf("error opening %s\n",filename_try); - err= ZIP_ERRNO; - } - else - printf("creating %s\n",filename_try); - - for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && - (strlen(argv[i]) == 2))) - { - FILE * fin; - int size_read; - const char* filenameinzip = argv[i]; - const char *savefilenameinzip; - zip_fileinfo zi; - unsigned long crcFile=0; - int zip64 = 0; - - zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = - zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; - zi.dosDate = 0; - zi.internal_fa = 0; - zi.external_fa = 0; - filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); - -/* - err = zipOpenNewFileInZip(zf,filenameinzip,&zi, - NULL,0,NULL,0,NULL / * comment * /, - (opt_compress_level != 0) ? Z_DEFLATED : 0, - opt_compress_level); -*/ - if ((password != NULL) && (err==ZIP_OK)) - err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); - - zip64 = isLargeFile(filenameinzip); - - /* The path name saved, should not include a leading slash. */ - /*if it did, windows/xp and dynazip couldn't read the zip file. */ - savefilenameinzip = filenameinzip; - while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) - { - savefilenameinzip++; - } - - /*should the zip file contain any path at all?*/ - if( opt_exclude_path ) - { - const char *tmpptr; - const char *lastslash = 0; - for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) - { - if( *tmpptr == '\\' || *tmpptr == '/') - { - lastslash = tmpptr; - } - } - if( lastslash != NULL ) - { - savefilenameinzip = lastslash+1; // base filename follows last slash. - } - } - - /**/ - err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, - NULL,0,NULL,0,NULL /* comment*/, - (opt_compress_level != 0) ? Z_DEFLATED : 0, - opt_compress_level,0, - /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - password,crcFile, zip64); - - if (err != ZIP_OK) - printf("error in opening %s in zipfile\n",filenameinzip); - else - { - fin = fopen64(filenameinzip,"rb"); - if (fin==NULL) - { - err=ZIP_ERRNO; - printf("error in opening %s for reading\n",filenameinzip); - } - } - - if (err == ZIP_OK) - do - { - err = ZIP_OK; - size_read = (int)fread(buf,1,size_buf,fin); - if (size_read < size_buf) - if (feof(fin)==0) - { - printf("error in reading %s\n",filenameinzip); - err = ZIP_ERRNO; - } - - if (size_read>0) - { - err = zipWriteInFileInZip (zf,buf,size_read); - if (err<0) - { - printf("error in writing %s in the zipfile\n", - filenameinzip); - } - - } - } while ((err == ZIP_OK) && (size_read>0)); - - if (fin) - fclose(fin); - - if (err<0) - err=ZIP_ERRNO; - else - { - err = zipCloseFileInZip(zf); - if (err!=ZIP_OK) - printf("error in closing %s in the zipfile\n", - filenameinzip); - } - } - } - errclose = zipClose(zf,NULL); - if (errclose != ZIP_OK) - printf("error in closing %s\n",filename_try); - } - else - { - do_help(); - } - - free(buf); - return 0; -} diff --git a/libminizip/mztools.c b/libminizip/mztools.c deleted file mode 100644 index f9092e65a..000000000 --- a/libminizip/mztools.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - Additional tools for Minizip - Code: Xavier Roche '2004 - License: Same as ZLIB (www.gzip.org) -*/ - -/* Code */ -#include -#include -#include -#include "zlib.h" -#include "unzip.h" - -#define READ_8(adr) ((unsigned char)*(adr)) -#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) -#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) - -#define WRITE_8(buff, n) do { \ - *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ -} while(0) -#define WRITE_16(buff, n) do { \ - WRITE_8((unsigned char*)(buff), n); \ - WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ -} while(0) -#define WRITE_32(buff, n) do { \ - WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ - WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ -} while(0) - -extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) -const char* file; -const char* fileOut; -const char* fileOutTmp; -uLong* nRecovered; -uLong* bytesRecovered; -{ - int err = Z_OK; - FILE* fpZip = fopen(file, "rb"); - FILE* fpOut = fopen(fileOut, "wb"); - FILE* fpOutCD = fopen(fileOutTmp, "wb"); - if (fpZip != NULL && fpOut != NULL) { - int entries = 0; - uLong totalBytes = 0; - char header[30]; - char filename[256]; - char extra[1024]; - int offset = 0; - int offsetCD = 0; - while ( fread(header, 1, 30, fpZip) == 30 ) { - int currentOffset = offset; - - /* File entry */ - if (READ_32(header) == 0x04034b50) { - unsigned int version = READ_16(header + 4); - unsigned int gpflag = READ_16(header + 6); - unsigned int method = READ_16(header + 8); - unsigned int filetime = READ_16(header + 10); - unsigned int filedate = READ_16(header + 12); - unsigned int crc = READ_32(header + 14); /* crc */ - unsigned int cpsize = READ_32(header + 18); /* compressed size */ - unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ - unsigned int fnsize = READ_16(header + 26); /* file name length */ - unsigned int extsize = READ_16(header + 28); /* extra field length */ - filename[0] = extra[0] = '\0'; - - /* Header */ - if (fwrite(header, 1, 30, fpOut) == 30) { - offset += 30; - } else { - err = Z_ERRNO; - break; - } - - /* Filename */ - if (fnsize > 0) { - if (fread(filename, 1, fnsize, fpZip) == fnsize) { - if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { - offset += fnsize; - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_STREAM_ERROR; - break; - } - - /* Extra field */ - if (extsize > 0) { - if (fread(extra, 1, extsize, fpZip) == extsize) { - if (fwrite(extra, 1, extsize, fpOut) == extsize) { - offset += extsize; - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_ERRNO; - break; - } - } - - /* Data */ - { - int dataSize = cpsize; - if (dataSize == 0) { - dataSize = uncpsize; - } - if (dataSize > 0) { - char* data = malloc(dataSize); - if (data != NULL) { - if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { - if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { - offset += dataSize; - totalBytes += dataSize; - } else { - err = Z_ERRNO; - } - } else { - err = Z_ERRNO; - } - free(data); - if (err != Z_OK) { - break; - } - } else { - err = Z_MEM_ERROR; - break; - } - } - } - - /* Central directory entry */ - { - char header[46]; - char* comment = ""; - int comsize = (int) strlen(comment); - WRITE_32(header, 0x02014b50); - WRITE_16(header + 4, version); - WRITE_16(header + 6, version); - WRITE_16(header + 8, gpflag); - WRITE_16(header + 10, method); - WRITE_16(header + 12, filetime); - WRITE_16(header + 14, filedate); - WRITE_32(header + 16, crc); - WRITE_32(header + 20, cpsize); - WRITE_32(header + 24, uncpsize); - WRITE_16(header + 28, fnsize); - WRITE_16(header + 30, extsize); - WRITE_16(header + 32, comsize); - WRITE_16(header + 34, 0); /* disk # */ - WRITE_16(header + 36, 0); /* int attrb */ - WRITE_32(header + 38, 0); /* ext attrb */ - WRITE_32(header + 42, currentOffset); - /* Header */ - if (fwrite(header, 1, 46, fpOutCD) == 46) { - offsetCD += 46; - - /* Filename */ - if (fnsize > 0) { - if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { - offsetCD += fnsize; - } else { - err = Z_ERRNO; - break; - } - } else { - err = Z_STREAM_ERROR; - break; - } - - /* Extra field */ - if (extsize > 0) { - if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { - offsetCD += extsize; - } else { - err = Z_ERRNO; - break; - } - } - - /* Comment field */ - if (comsize > 0) { - if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { - offsetCD += comsize; - } else { - err = Z_ERRNO; - break; - } - } - - - } else { - err = Z_ERRNO; - break; - } - } - - /* Success */ - entries++; - - } else { - break; - } - } - - /* Final central directory */ - { - int entriesZip = entries; - char header[22]; - char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; - int comsize = (int) strlen(comment); - if (entriesZip > 0xffff) { - entriesZip = 0xffff; - } - WRITE_32(header, 0x06054b50); - WRITE_16(header + 4, 0); /* disk # */ - WRITE_16(header + 6, 0); /* disk # */ - WRITE_16(header + 8, entriesZip); /* hack */ - WRITE_16(header + 10, entriesZip); /* hack */ - WRITE_32(header + 12, offsetCD); /* size of CD */ - WRITE_32(header + 16, offset); /* offset to CD */ - WRITE_16(header + 20, comsize); /* comment */ - - /* Header */ - if (fwrite(header, 1, 22, fpOutCD) == 22) { - - /* Comment field */ - if (comsize > 0) { - if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { - err = Z_ERRNO; - } - } - - } else { - err = Z_ERRNO; - } - } - - /* Final merge (file + central directory) */ - fclose(fpOutCD); - if (err == Z_OK) { - fpOutCD = fopen(fileOutTmp, "rb"); - if (fpOutCD != NULL) { - int nRead; - char buffer[8192]; - while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { - if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { - err = Z_ERRNO; - break; - } - } - fclose(fpOutCD); - } - } - - /* Close */ - fclose(fpZip); - fclose(fpOut); - - /* Wipe temporary file */ - (void)remove(fileOutTmp); - - /* Number of recovered entries */ - if (err == Z_OK) { - if (nRecovered != NULL) { - *nRecovered = entries; - } - if (bytesRecovered != NULL) { - *bytesRecovered = totalBytes; - } - } - } else { - err = Z_STREAM_ERROR; - } - return err; -} diff --git a/libminizip/mztools.h b/libminizip/mztools.h deleted file mode 100644 index 88b34592b..000000000 --- a/libminizip/mztools.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - Additional tools for Minizip - Code: Xavier Roche '2004 - License: Same as ZLIB (www.gzip.org) -*/ - -#ifndef _zip_tools_H -#define _zip_tools_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#include "unzip.h" - -/* Repair a ZIP file (missing central directory) - file: file to recover - fileOut: output file after recovery - fileOutTmp: temporary file name used for recovery -*/ -extern int ZEXPORT unzRepair(const char* file, - const char* fileOut, - const char* fileOutTmp, - uLong* nRecovered, - uLong* bytesRecovered); - -#endif diff --git a/libminizip/unzip.c b/libminizip/unzip.c deleted file mode 100644 index 7617f41f1..000000000 --- a/libminizip/unzip.c +++ /dev/null @@ -1,2125 +0,0 @@ -/* unzip.c -- IO for uncompress .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications of Unzip for Zip64 - Copyright (C) 2007-2008 Even Rouault - - Modifications for Zip64 support on both zip and unzip - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - - ------------------------------------------------------------------------------------ - Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of - compatibility with older software. The following is from the original crypt.c. - Code woven in by Terry Thorsen 1/2003. - - Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - - See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. - If, for some reason, all these files are missing, the Info-ZIP license - also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html - - crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - - ------------------------------------------------------------------------------------ - - Changes in unzip.c - - 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos - 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* - 2007-2008 - Even Rouault - Remove old C style function prototypes - 2007-2008 - Even Rouault - Add unzip support for ZIP64 - - Copyright (C) 2007-2008 Even Rouault - - - Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). - Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G - should only read the compressed/uncompressed size from the Zip64 format if - the size from normal header was 0xFFFFFFFF - Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant - Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) - Patch created by Daniel Borca - - Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer - - Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson - -*/ - - -#include -#include -#include - -#ifndef NOUNCRYPT - #define NOUNCRYPT -#endif - -#include "zlib.h" -#include "unzip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - - -#ifndef CASESENSITIVITYDEFAULT_NO -# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) -# define CASESENSITIVITYDEFAULT_NO -# endif -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (16384) -#endif - -#ifndef UNZ_MAXFILENAMEINZIP -#define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - -const char unz_copyright[] = - " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - -/* unz_file_info_interntal contain internal info about a file in zipfile*/ -typedef struct unz_file_info64_internal_s -{ - ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ -} unz_file_info64_internal; - - -/* file_in_zip_read_info_s contain internal information about a file in zipfile, - when reading and decompress it */ -typedef struct -{ - char *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - -#ifdef HAVE_BZIP2 - bz_stream bstream; /* bzLib stream structure for bziped */ -#endif - - ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ - uLong stream_initialised; /* flag set if stream structure is initialised*/ - - ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ - uInt size_local_extrafield;/* size of the local extra field */ - ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ - ZPOS64_T total_out_64; - - uLong crc32; /* crc32 of all data uncompressed */ - uLong crc32_wait; /* crc32 we must obtain after decompress all */ - ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ - ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ - zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - uLong compression_method; /* compression method (0==store) */ - ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - int raw; -} file_in_zip64_read_info_s; - - -/* unz64_s contain internal information about the zipfile -*/ -typedef struct -{ - zlib_filefunc64_32_def z_filefunc; - int is64bitOpenFunction; - voidpf filestream; /* io structore of the zipfile */ - unz_global_info64 gi; /* public global information */ - ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - ZPOS64_T num_file; /* number of the current file in the zipfile*/ - ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ - ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ - ZPOS64_T central_pos; /* position of the beginning of the central dir*/ - - ZPOS64_T size_central_dir; /* size of the central directory */ - ZPOS64_T offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info64 cur_file_info; /* public info about the current file in zip*/ - unz_file_info64_internal cur_file_info_internal; /* private info about it*/ - file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current - file if we are decompressing it */ - int encrypted; - - int isZip64; - -# ifndef NOUNCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; -# endif -} unz64_s; - - -#ifndef NOUNCRYPT -#include "crypt.h" -#endif - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - - -local int unz64local_getByte OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) -{ - unsigned char c; - int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return UNZ_OK; - } - else - { - if (ZERROR64(*pzlib_filefunc_def,filestream)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int unz64local_getShort OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX) -{ - uLong x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unz64local_getLong OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX) -{ - uLong x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unz64local_getLong64 OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - ZPOS64_T *pX)); - - -local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream, - ZPOS64_T *pX) -{ - ZPOS64_T x ; - int i = 0; - int err; - - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (ZPOS64_T)i; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<8; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<16; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<24; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<32; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<40; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<48; - - if (err==UNZ_OK) - err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); - x |= ((ZPOS64_T)i)<<56; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -/* My own strcmpi / strcasecmp */ -local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= 0x20; - if ((c2>='a') && (c2<='z')) - c2 -= 0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - -#ifdef CASESENSITIVITYDEFAULT_NO -#define CASESENSITIVITYDEFAULTVALUE 2 -#else -#define CASESENSITIVITYDEFAULTVALUE 1 -#endif - -#ifndef STRCMPCASENOSENTIVEFUNCTION -#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal -#endif - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) - -*/ -extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, - const char* fileName2, - int iCaseSensitivity) - -{ - if (iCaseSensitivity==0) - iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; - - if (iCaseSensitivity==1) - return strcmp(fileName1,fileName2); - - return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); -local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T uSizeFile; - ZPOS64_T uBackRead; - ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; - - if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); - if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - - -/* - Locate the Central directory 64 of a zipfile (at the end, just before - the global comment) -*/ -local ZPOS64_T unz64local_SearchCentralDir64 OF(( - const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream)); - -local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, - voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T uSizeFile; - ZPOS64_T uBackRead; - ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; - uLong uL; - ZPOS64_T relativeOffset; - - if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); - if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - if (uPosFound == 0) - return 0; - - /* Zip64 end of central directory locator */ - if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) - return 0; - - /* the signature, already checked */ - if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) - return 0; - - /* number of the disk with the start of the zip64 end of central directory */ - if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) - return 0; - if (uL != 0) - return 0; - - /* relative offset of the zip64 end of central directory record */ - if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) - return 0; - - /* total number of disks */ - if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) - return 0; - if (uL != 1) - return 0; - - /* Goto end of central directory record */ - if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) - return 0; - - /* the signature */ - if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) - return 0; - - if (uL != 0x06064b50) - return 0; - - return relativeOffset; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer - "zlib/zlib114.zip". - If the zipfile cannot be opened (file doesn't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -local unzFile unzOpenInternal (const void *path, - zlib_filefunc64_32_def* pzlib_filefunc64_32_def, - int is64bitOpenFunction) -{ - unz64_s us; - unz64_s *s; - ZPOS64_T central_pos; - uLong uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - ZPOS64_T number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - if (unz_copyright[0]!=' ') - return NULL; - - us.z_filefunc.zseek32_file = NULL; - us.z_filefunc.ztell32_file = NULL; - if (pzlib_filefunc64_32_def==NULL) - fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); - else - us.z_filefunc = *pzlib_filefunc64_32_def; - us.is64bitOpenFunction = is64bitOpenFunction; - - - - us.filestream = ZOPEN64(us.z_filefunc, - path, - ZLIB_FILEFUNC_MODE_READ | - ZLIB_FILEFUNC_MODE_EXISTING); - if (us.filestream==NULL) - return NULL; - - central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); - if (central_pos) - { - uLong uS; - ZPOS64_T uL64; - - us.isZip64 = 1; - - if (ZSEEK64(us.z_filefunc, us.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* size of zip64 end of central directory record */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) - err=UNZ_ERRNO; - - /* version made by */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) - err=UNZ_ERRNO; - - /* version needed to extract */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central directory on this disk */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central directory */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - us.gi.size_comment = 0; - } - else - { - central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); - if (central_pos==0) - err=UNZ_ERRNO; - - us.isZip64 = 0; - - if (ZSEEK64(us.z_filefunc, us.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - us.gi.number_entry = uL; - - /* total number of entries in the central dir */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - number_entry_CD = uL; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - us.size_central_dir = uL; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - us.offset_central_dir = uL; - - /* zipfile comment length */ - if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) - err=UNZ_ERRNO; - } - - if ((central_pospfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - ZCLOSE64(s->z_filefunc, s->filestream); - TRYFREE(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) -{ - unz64_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - -extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) -{ - unz64_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - /* to do : check if number_entry is not truncated */ - pglobal_info32->number_entry = (uLong)s->gi.number_entry; - pglobal_info32->size_comment = s->gi.size_comment; - return UNZ_OK; -} -/* - Translate date/time from Dos format to tm_unz (readable more easilty) -*/ -local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) -{ - ZPOS64_T uDate; - uDate = (ZPOS64_T)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, - unz_file_info64 *pfile_info, - unz_file_info64_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -local int unz64local_GetCurrentFileInfoInternal (unzFile file, - unz_file_info64 *pfile_info, - unz_file_info64_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize) -{ - unz64_s* s; - unz_file_info64 file_info; - unz_file_info64_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - long lSeek=0; - uLong uL; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - if (ZSEEK64(s->z_filefunc, s->filestream, - s->pos_in_central_dir+s->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) - { - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - } - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) - err=UNZ_ERRNO; - file_info.compressed_size = uL; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) - err=UNZ_ERRNO; - file_info.uncompressed_size = uL; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - // relative offset of local header - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) - err=UNZ_ERRNO; - file_info_internal.offset_curfile = uL; - - lSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - lSeek -= uSizeRead; - } - - // Read extrafield - if ((err==UNZ_OK) && (extraField!=NULL)) - { - ZPOS64_T uSizeRead ; - if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - } - - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - - lSeek += file_info.size_file_extra - (uLong)uSizeRead; - } - else - lSeek += file_info.size_file_extra; - - - if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) - { - uLong acc = 0; - - // since lSeek now points to after the extra field we need to move back - lSeek -= file_info.size_file_extra; - - if (lSeek!=0) - { - if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - } - - while(acc < file_info.size_file_extra) - { - uLong headerId; - uLong dataSize; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) - err=UNZ_ERRNO; - - /* ZIP64 extra fields */ - if (headerId == 0x0001) - { - uLong uL; - - if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - } - - if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) - { - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - } - - if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) - { - /* Relative Header offset */ - if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - } - - if(file_info.disk_num_start == (unsigned long)-1) - { - /* Disk Start Number */ - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) - err=UNZ_ERRNO; - } - - } - else - { - if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) - err=UNZ_ERRNO; - } - - acc += 2 + 2 + dataSize; - } - } - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - lSeek=0; - else - err=UNZ_ERRNO; - } - - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - lSeek+=file_info.size_file_comment - uSizeRead; - } - else - lSeek+=file_info.size_file_comment; - - - if ((err==UNZ_OK) && (pfile_info!=NULL)) - *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) - *pfile_info_internal=file_info_internal; - - return err; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, - unz_file_info64 * pfile_info, - char * szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char* szComment, uLong commentBufferSize) -{ - return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); -} - -extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, - unz_file_info * pfile_info, - char * szFileName, uLong fileNameBufferSize, - void *extraField, uLong extraFieldBufferSize, - char* szComment, uLong commentBufferSize) -{ - int err; - unz_file_info64 file_info64; - err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); - if (err==UNZ_OK) - { - pfile_info->version = file_info64.version; - pfile_info->version_needed = file_info64.version_needed; - pfile_info->flag = file_info64.flag; - pfile_info->compression_method = file_info64.compression_method; - pfile_info->dosDate = file_info64.dosDate; - pfile_info->crc = file_info64.crc; - - pfile_info->size_filename = file_info64.size_filename; - pfile_info->size_file_extra = file_info64.size_file_extra; - pfile_info->size_file_comment = file_info64.size_file_comment; - - pfile_info->disk_num_start = file_info64.disk_num_start; - pfile_info->internal_fa = file_info64.internal_fa; - pfile_info->external_fa = file_info64.external_fa; - - pfile_info->tmu_date = file_info64.tmu_date, - - - pfile_info->compressed_size = (uLong)file_info64.compressed_size; - pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; - - } - return err; -} -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int ZEXPORT unzGoToFirstFile (unzFile file) -{ - int err=UNZ_OK; - unz64_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int ZEXPORT unzGoToNextFile (unzFile file) -{ - unz64_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ - if (s->num_file+1==s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ -extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) -{ - unz64_s* s; - int err; - - /* We remember the 'current' position in the file so that we can jump - * back there if we fail. - */ - unz_file_info64 cur_file_infoSaved; - unz_file_info64_internal cur_file_info_internalSaved; - ZPOS64_T num_fileSaved; - ZPOS64_T pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz64_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - /* Save the current state */ - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - cur_file_infoSaved = s->cur_file_info; - cur_file_info_internalSaved = s->cur_file_info_internal; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - err = unzGetCurrentFileInfo64(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (err == UNZ_OK) - { - if (unzStringFileNameCompare(szCurrentFileName, - szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - } - - /* We failed, so restore the state of the 'current file' to where we - * were. - */ - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - s->cur_file_info = cur_file_infoSaved; - s->cur_file_info_internal = cur_file_info_internalSaved; - return err; -} - - -/* -/////////////////////////////////////////// -// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) -// I need random access -// -// Further optimization could be realized by adding an ability -// to cache the directory in memory. The goal being a single -// comprehensive file read to put the file I need in a memory. -*/ - -/* -typedef struct unz_file_pos_s -{ - ZPOS64_T pos_in_zip_directory; // offset in file - ZPOS64_T num_of_file; // # of file -} unz_file_pos; -*/ - -extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) -{ - unz64_s* s; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - file_pos->pos_in_zip_directory = s->pos_in_central_dir; - file_pos->num_of_file = s->num_file; - - return UNZ_OK; -} - -extern int ZEXPORT unzGetFilePos( - unzFile file, - unz_file_pos* file_pos) -{ - unz64_file_pos file_pos64; - int err = unzGetFilePos64(file,&file_pos64); - if (err==UNZ_OK) - { - file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; - file_pos->num_of_file = (uLong)file_pos64.num_of_file; - } - return err; -} - -extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) -{ - unz64_s* s; - int err; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - - /* jump to the right spot */ - s->pos_in_central_dir = file_pos->pos_in_zip_directory; - s->num_file = file_pos->num_of_file; - - /* set the current file */ - err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - /* return results */ - s->current_file_ok = (err == UNZ_OK); - return err; -} - -extern int ZEXPORT unzGoToFilePos( - unzFile file, - unz_file_pos* file_pos) -{ - unz64_file_pos file_pos64; - if (file_pos == NULL) - return UNZ_PARAMERROR; - - file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; - file_pos64.num_of_file = file_pos->num_of_file; - return unzGoToFilePos64(file,&file_pos64); -} - -/* -// Unzip Helper Functions - should be here? -/////////////////////////////////////////// -*/ - -/* - Read the local header of the current zipfile - Check the coherency of the local header and info in the end of central - directory about this file - store in *piSizeVar the size of extra info in local header - (filename and size of extra field data) -*/ -local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, - ZPOS64_T * poffset_local_extrafield, - uInt * psize_local_extrafield) -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + - s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) - { - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - } - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; -/* - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) - err=UNZ_BADZIPFILE; -*/ - if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && -/* #ifdef HAVE_BZIP2 */ - (s->cur_file_info.compression_method!=Z_BZIP2ED) && -/* #endif */ - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ - err=UNZ_ERRNO; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ - err=UNZ_ERRNO; - else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ - err=UNZ_ERRNO; - else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) - err=UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) - err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + - SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, - int* level, int raw, const char* password) -{ - int err=UNZ_OK; - uInt iSizeVar; - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ - uInt size_local_extrafield; /* size of the local extra field */ -# ifndef NOUNCRYPT - char source[12]; -# else - if (password != NULL) - return UNZ_PARAMERROR; -# endif - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - pfile_in_zip_read_info->raw=raw; - - if (pfile_in_zip_read_info->read_buffer==NULL) - { - TRYFREE(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if (method!=NULL) - *method = (int)s->cur_file_info.compression_method; - - if (level!=NULL) - { - *level = 6; - switch (s->cur_file_info.flag & 0x06) - { - case 6 : *level = 1; break; - case 4 : *level = 2; break; - case 2 : *level = 9; break; - } - } - - if ((s->cur_file_info.compression_method!=0) && -/* #ifdef HAVE_BZIP2 */ - (s->cur_file_info.compression_method!=Z_BZIP2ED) && -/* #endif */ - (s->cur_file_info.compression_method!=Z_DEFLATED)) - - err=UNZ_BADZIPFILE; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->total_out_64=0; - pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; - pfile_in_zip_read_info->filestream=s->filestream; - pfile_in_zip_read_info->z_filefunc=s->z_filefunc; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) - { -#ifdef HAVE_BZIP2 - pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; - pfile_in_zip_read_info->bstream.bzfree = (free_func)0; - pfile_in_zip_read_info->bstream.opaque = (voidpf)0; - pfile_in_zip_read_info->bstream.state = (voidpf)0; - - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - pfile_in_zip_read_info->stream.next_in = (voidpf)0; - pfile_in_zip_read_info->stream.avail_in = 0; - - err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; - else - { - TRYFREE(pfile_in_zip_read_info); - return err; - } -#else - pfile_in_zip_read_info->raw=1; -#endif - } - else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - pfile_in_zip_read_info->stream.next_in = 0; - pfile_in_zip_read_info->stream.avail_in = 0; - - err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; - else - { - TRYFREE(pfile_in_zip_read_info); - return err; - } - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - pfile_in_zip_read_info->rest_read_compressed = - s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = - s->cur_file_info.uncompressed_size ; - - - pfile_in_zip_read_info->pos_in_zipfile = - s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + - iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - s->pfile_in_zip_read = pfile_in_zip_read_info; - s->encrypted = 0; - -# ifndef NOUNCRYPT - if (password != NULL) - { - int i; - s->pcrc_32_tab = get_crc_table(); - init_keys(password,s->keys,s->pcrc_32_tab); - if (ZSEEK64(s->z_filefunc, s->filestream, - s->pfile_in_zip_read->pos_in_zipfile + - s->pfile_in_zip_read->byte_before_the_zipfile, - SEEK_SET)!=0) - return UNZ_INTERNALERROR; - if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) - return UNZ_INTERNALERROR; - - for (i = 0; i<12; i++) - zdecode(s->keys,s->pcrc_32_tab,source[i]); - - s->pfile_in_zip_read->pos_in_zipfile+=12; - s->encrypted=1; - } -# endif - - - return UNZ_OK; -} - -extern int ZEXPORT unzOpenCurrentFile (unzFile file) -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); -} - -extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, password); -} - -extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) -{ - return unzOpenCurrentFile3(file, method, level, raw, NULL); -} - -/** Addition for GDAL : START */ - -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - s=(unz64_s*)file; - if (file==NULL) - return 0; //UNZ_PARAMERROR; - pfile_in_zip_read_info=s->pfile_in_zip_read; - if (pfile_in_zip_read_info==NULL) - return 0; //UNZ_PARAMERROR; - return pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile; -} - -/** Addition for GDAL : END */ - -/* - Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ -extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) -{ - int err=UNZ_OK; - uInt iRead = 0; - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->read_buffer == NULL)) - return UNZ_END_OF_LIST_OF_FILE; - if (len==0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; - - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && - (!(pfile_in_zip_read_info->raw))) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - - if ((len>pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in) && - (pfile_in_zip_read_info->raw)) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in; - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if ((pfile_in_zip_read_info->stream.avail_in==0) && - (pfile_in_zip_read_info->rest_read_compressed>0)) - { - uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) - return UNZ_EOF; - if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - if (ZREAD64(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->read_buffer, - uReadThis)!=uReadThis) - return UNZ_ERRNO; - - -# ifndef NOUNCRYPT - if(s->encrypted) - { - uInt i; - for(i=0;iread_buffer[i] = - zdecode(s->keys,s->pcrc_32_tab, - pfile_in_zip_read_info->read_buffer[i]); - } -# endif - - - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Bytef*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - } - - if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) - { - uInt uDoCopy,i ; - - if ((pfile_in_zip_read_info->stream.avail_in == 0) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - return (iRead==0) ? UNZ_EOF : iRead; - - if (pfile_in_zip_read_info->stream.avail_out < - pfile_in_zip_read_info->stream.avail_in) - uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else - uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, - uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } - else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) - { -#ifdef HAVE_BZIP2 - uLong uTotalOutBefore,uTotalOutAfter; - const Bytef *bufBefore; - uLong uOutThis; - - pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; - pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; - pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; - pfile_in_zip_read_info->bstream.total_in_hi32 = 0; - pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; - pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; - pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; - pfile_in_zip_read_info->bstream.total_out_hi32 = 0; - - uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; - bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; - - err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); - - uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); - pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; - pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; - pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; - pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; - pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; - pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; - - if (err==BZ_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=BZ_OK) - break; -#endif - } // end Z_BZIP2ED - else - { - ZPOS64_T uTotalOutBefore,uTotalOutAfter; - const Bytef *bufBefore; - ZPOS64_T uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - - /* - if ((pfile_in_zip_read_info->rest_read_uncompressed == - pfile_in_zip_read_info->stream.avail_out) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - flush = Z_FINISH; - */ - err=inflate(&pfile_in_zip_read_info->stream,flush); - - if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) - err = Z_DATA_ERROR; - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; - - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,bufBefore, - (uInt)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= - uOutThis; - - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) - break; - } - } - - if (err==Z_OK) - return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern z_off_t ZEXPORT unztell (unzFile file) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - -extern ZPOS64_T ZEXPORT unztell64 (unzFile file) -{ - - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return (ZPOS64_T)-1; - s=(unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return (ZPOS64_T)-1; - - return pfile_in_zip_read_info->total_out_64; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int ZEXPORT unzeof (unzFile file) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -/* -Read extra field from the current file (opened by unzOpenCurrentFile) -This is the local-header version of the extra field (sometimes, there is -more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) -{ - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - uInt read_now; - ZPOS64_T size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (ZREAD64(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - buf,read_now)!=read_now) - return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int ZEXPORT unzCloseCurrentFile (unzFile file) -{ - int err=UNZ_OK; - - unz64_s* s; - file_in_zip64_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && - (!pfile_in_zip_read_info->raw)) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err=UNZ_CRCERROR; - } - - - TRYFREE(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) - inflateEnd(&pfile_in_zip_read_info->stream); -#ifdef HAVE_BZIP2 - else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) - BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); -#endif - - - pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) -{ - unz64_s* s; - uLong uReadThis ; - if (file==NULL) - return (int)UNZ_PARAMERROR; - s=(unz64_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) - uReadThis = s->gi.size_comment; - - if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (uReadThis>0) - { - *szComment='\0'; - if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) - return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) - *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} - -/* Additions by RX '2004 */ -extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) -{ - unz64_s* s; - - if (file==NULL) - return 0; //UNZ_PARAMERROR; - s=(unz64_s*)file; - if (!s->current_file_ok) - return 0; - if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) - if (s->num_file==s->gi.number_entry) - return 0; - return s->pos_in_central_dir; -} - -extern uLong ZEXPORT unzGetOffset (unzFile file) -{ - ZPOS64_T offset64; - - if (file==NULL) - return 0; //UNZ_PARAMERROR; - offset64 = unzGetOffset64(file); - return (uLong)offset64; -} - -extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) -{ - unz64_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz64_s*)file; - - s->pos_in_central_dir = pos; - s->num_file = s->gi.number_entry; /* hack */ - err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - -extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) -{ - return unzSetOffset64(file,pos); -} diff --git a/libminizip/unzip.h b/libminizip/unzip.h deleted file mode 100644 index 3183968b7..000000000 --- a/libminizip/unzip.h +++ /dev/null @@ -1,437 +0,0 @@ -/* unzip.h -- IO for uncompress .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications of Unzip for Zip64 - Copyright (C) 2007-2008 Even Rouault - - Modifications for Zip64 support on both zip and unzip - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - --------------------------------------------------------------------------------- - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - --------------------------------------------------------------------------------- - - Changes - - See header of unzip64.c - -*/ - -#ifndef _unz64_H -#define _unz64_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#ifdef HAVE_BZIP2 -#include "bzlib.h" -#endif - -#define Z_BZIP2ED 12 - -#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagunzFile__ { int unused; } unzFile__; -typedef unzFile__ *unzFile; -#else -typedef voidp unzFile; -#endif - - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) - -/* tm_unz contain date/time info */ -typedef struct tm_unz_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_unz; - -/* unz_global_info structure contain global data about the ZIPfile - These data comes from the end of central dir */ -typedef struct unz_global_info64_s -{ - ZPOS64_T number_entry; /* total number of entries in - the central dir on this disk */ - uLong size_comment; /* size of the global comment of the zipfile */ -} unz_global_info64; - -typedef struct unz_global_info_s -{ - uLong number_entry; /* total number of entries in - the central dir on this disk */ - uLong size_comment; /* size of the global comment of the zipfile */ -} unz_global_info; - -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_info64_s -{ - uLong version; /* version made by 2 bytes */ - uLong version_needed; /* version needed to extract 2 bytes */ - uLong flag; /* general purpose bit flag 2 bytes */ - uLong compression_method; /* compression method 2 bytes */ - uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ - uLong crc; /* crc-32 4 bytes */ - ZPOS64_T compressed_size; /* compressed size 8 bytes */ - ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ - uLong size_filename; /* filename length 2 bytes */ - uLong size_file_extra; /* extra field length 2 bytes */ - uLong size_file_comment; /* file comment length 2 bytes */ - - uLong disk_num_start; /* disk number start 2 bytes */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ - - tm_unz tmu_date; -} unz_file_info64; - -typedef struct unz_file_info_s -{ - uLong version; /* version made by 2 bytes */ - uLong version_needed; /* version needed to extract 2 bytes */ - uLong flag; /* general purpose bit flag 2 bytes */ - uLong compression_method; /* compression method 2 bytes */ - uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ - uLong crc; /* crc-32 4 bytes */ - uLong compressed_size; /* compressed size 4 bytes */ - uLong uncompressed_size; /* uncompressed size 4 bytes */ - uLong size_filename; /* filename length 2 bytes */ - uLong size_file_extra; /* extra field length 2 bytes */ - uLong size_file_comment; /* file comment length 2 bytes */ - - uLong disk_num_start; /* disk number start 2 bytes */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ - - tm_unz tmu_date; -} unz_file_info; - -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) -*/ - - -extern unzFile ZEXPORT unzOpen OF((const char *path)); -extern unzFile ZEXPORT unzOpen64 OF((const void *path)); -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer - "zlib/zlib113.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. - the "64" function take a const void* pointer, because the path is just the - value passed to the open64_file_func callback. - Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path - is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* - does not describe the reality -*/ - - -extern unzFile ZEXPORT unzOpen2 OF((const char *path, - zlib_filefunc_def* pzlib_filefunc_def)); -/* - Open a Zip file, like unzOpen, but provide a set of file low level API - for read/write the zip file (see ioapi.h) -*/ - -extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, - zlib_filefunc64_def* pzlib_filefunc_def)); -/* - Open a Zip file, like unz64Open, but provide a set of file low level API - for read/write the zip file (see ioapi.h) -*/ - -extern int ZEXPORT unzClose OF((unzFile file)); -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ - -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, - unz_global_info *pglobal_info)); - -extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, - unz_global_info64 *pglobal_info)); -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ - - -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, - char *szComment, - uLong uSizeBuf)); -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ - - -/***************************************************************************/ -/* Unzip package allow you browse the directory of the zipfile */ - -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ - -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ - -extern int ZEXPORT unzLocateFile OF((unzFile file, - const char *szFileName, - int iCaseSensitivity)); -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ - - -/* ****************************************** */ -/* Ryan supplied functions */ -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_pos_s -{ - uLong pos_in_zip_directory; /* offset in zip file directory */ - uLong num_of_file; /* # of file */ -} unz_file_pos; - -extern int ZEXPORT unzGetFilePos( - unzFile file, - unz_file_pos* file_pos); - -extern int ZEXPORT unzGoToFilePos( - unzFile file, - unz_file_pos* file_pos); - -typedef struct unz64_file_pos_s -{ - ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ - ZPOS64_T num_of_file; /* # of file */ -} unz64_file_pos; - -extern int ZEXPORT unzGetFilePos64( - unzFile file, - unz64_file_pos* file_pos); - -extern int ZEXPORT unzGoToFilePos64( - unzFile file, - const unz64_file_pos* file_pos); - -/* ****************************************** */ - -extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, - unz_file_info64 *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); -/* - Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about - the current file - if szFileName!=NULL, the filemane string will be copied in szFileName - (fileNameBufferSize is the size of the buffer) - if extraField!=NULL, the extra field information will be copied in extraField - (extraFieldBufferSize is the size of the buffer). - This is the Central-header version of the extra field - if szComment!=NULL, the comment string of the file will be copied in szComment - (commentBufferSize is the size of the buffer) -*/ - - -/** Addition for GDAL : START */ - -extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); - -/** Addition for GDAL : END */ - - -/***************************************************************************/ -/* for reading the content of the current zipfile, you can open it, read data - from it, and close it (you can close it before reading all the file) - */ - -extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); -/* - Open for reading data the current file in the zipfile. - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, - const char* password)); -/* - Open for reading data the current file in the zipfile. - password is a crypting password - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, - int* method, - int* level, - int raw)); -/* - Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) - if raw==1 - *method will receive method of compression, *level will receive level of - compression - note : you can set level parameter as NULL (if you did not want known level, - but you CANNOT set method parameter as NULL -*/ - -extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, - int* method, - int* level, - int raw, - const char* password)); -/* - Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) - if raw==1 - *method will receive method of compression, *level will receive level of - compression - note : you can set level parameter as NULL (if you did not want known level, - but you CANNOT set method parameter as NULL -*/ - - -extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); -/* - Close the file in zip opened with unzOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ - -extern int ZEXPORT unzReadCurrentFile OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read bytes from the current file (opened by unzOpenCurrentFile) - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ - -extern z_off_t ZEXPORT unztell OF((unzFile file)); - -extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); -/* - Give the current position in uncompressed data -*/ - -extern int ZEXPORT unzeof OF((unzFile file)); -/* - return 1 if the end of file was reached, 0 elsewhere -*/ - -extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ - -/***************************************************************************/ - -/* Get the current file offset */ -extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); -extern uLong ZEXPORT unzGetOffset (unzFile file); - -/* Set the current file offset */ -extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); -extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); - - - -#ifdef __cplusplus -} -#endif - -#endif /* _unz64_H */ diff --git a/libminizip/zip.c b/libminizip/zip.c deleted file mode 100644 index 3c34fc8bd..000000000 --- a/libminizip/zip.c +++ /dev/null @@ -1,2004 +0,0 @@ -/* zip.c -- IO on .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - Changes - Oct-2009 - Mathias Svensson - Remove old C style function prototypes - Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives - Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. - Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data - It is used when recreting zip archive with RAW when deleting items from a zip. - ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. - Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) - Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer - -*/ - - -#include -#include -#include -#include -#include "zlib.h" -#include "zip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#ifndef VERSIONMADEBY -# define VERSIONMADEBY (0x0) /* platform depedent */ -#endif - -#ifndef Z_BUFSIZE -#define Z_BUFSIZE (64*1024) //(16384) -#endif - -#ifndef Z_MAXFILENAMEINZIP -#define Z_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -/* -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) -*/ - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - - -// NOT sure that this work on ALL platform -#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#ifndef DEF_MEM_LEVEL -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -#endif -const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - - -#define SIZEDATA_INDATABLOCK (4096-(4*4)) - -#define LOCALHEADERMAGIC (0x04034b50) -#define CENTRALHEADERMAGIC (0x02014b50) -#define ENDHEADERMAGIC (0x06054b50) -#define ZIP64ENDHEADERMAGIC (0x6064b50) -#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) - -#define FLAG_LOCALHEADER_OFFSET (0x06) -#define CRC_LOCALHEADER_OFFSET (0x0e) - -#define SIZECENTRALHEADER (0x2e) /* 46 */ - -typedef struct linkedlist_datablock_internal_s -{ - struct linkedlist_datablock_internal_s* next_datablock; - uLong avail_in_this_block; - uLong filled_in_this_block; - uLong unused; /* for future use and alignement */ - unsigned char data[SIZEDATA_INDATABLOCK]; -} linkedlist_datablock_internal; - -typedef struct linkedlist_data_s -{ - linkedlist_datablock_internal* first_block; - linkedlist_datablock_internal* last_block; -} linkedlist_data; - - -typedef struct -{ - z_stream stream; /* zLib stream structure for inflate */ -#ifdef HAVE_BZIP2 - bz_stream bstream; /* bzLib stream structure for bziped */ -#endif - - int stream_initialised; /* 1 is stream is initialised */ - uInt pos_in_buffered_data; /* last written byte in buffered_data */ - - ZPOS64_T pos_local_header; /* offset of the local header of the file - currenty writing */ - char* central_header; /* central header data for the current file */ - uLong size_centralExtra; - uLong size_centralheader; /* size of the central header for cur file */ - uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ - uLong flag; /* flag of the file currently writing */ - - int method; /* compression method of file currenty wr.*/ - int raw; /* 1 for directly writing raw data */ - Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ - uLong dosDate; - uLong crc32; - int encrypt; - int zip64; /* Add ZIP64 extened information in the extra field */ - ZPOS64_T pos_zip64extrainfo; - ZPOS64_T totalCompressedData; - ZPOS64_T totalUncompressedData; -#ifndef NOCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; - int crypt_header_size; -#endif -} curfile64_info; - -typedef struct -{ - zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - linkedlist_data central_dir;/* datablock with central dir in construction*/ - int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ - curfile64_info ci; /* info on the file curretly writing */ - - ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ - ZPOS64_T add_position_when_writting_offset; - ZPOS64_T number_entry; - -#ifndef NO_ADDFILEINEXISTINGZIP - char *globalcomment; -#endif - -} zip64_internal; - - -#ifndef NOCRYPT -#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED -#include "crypt.h" -#endif - -local linkedlist_datablock_internal* allocate_new_datablock() -{ - linkedlist_datablock_internal* ldi; - ldi = (linkedlist_datablock_internal*) - ALLOC(sizeof(linkedlist_datablock_internal)); - if (ldi!=NULL) - { - ldi->next_datablock = NULL ; - ldi->filled_in_this_block = 0 ; - ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; - } - return ldi; -} - -local void free_datablock(linkedlist_datablock_internal* ldi) -{ - while (ldi!=NULL) - { - linkedlist_datablock_internal* ldinext = ldi->next_datablock; - TRYFREE(ldi); - ldi = ldinext; - } -} - -local void init_linkedlist(linkedlist_data* ll) -{ - ll->first_block = ll->last_block = NULL; -} - -local void free_linkedlist(linkedlist_data* ll) -{ - free_datablock(ll->first_block); - ll->first_block = ll->last_block = NULL; -} - - -local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) -{ - linkedlist_datablock_internal* ldi; - const unsigned char* from_copy; - - if (ll==NULL) - return ZIP_INTERNALERROR; - - if (ll->last_block == NULL) - { - ll->first_block = ll->last_block = allocate_new_datablock(); - if (ll->first_block == NULL) - return ZIP_INTERNALERROR; - } - - ldi = ll->last_block; - from_copy = (unsigned char*)buf; - - while (len>0) - { - uInt copy_this; - uInt i; - unsigned char* to_copy; - - if (ldi->avail_in_this_block==0) - { - ldi->next_datablock = allocate_new_datablock(); - if (ldi->next_datablock == NULL) - return ZIP_INTERNALERROR; - ldi = ldi->next_datablock ; - ll->last_block = ldi; - } - - if (ldi->avail_in_this_block < len) - copy_this = (uInt)ldi->avail_in_this_block; - else - copy_this = (uInt)len; - - to_copy = &(ldi->data[ldi->filled_in_this_block]); - - for (i=0;ifilled_in_this_block += copy_this; - ldi->avail_in_this_block -= copy_this; - from_copy += copy_this ; - len -= copy_this; - } - return ZIP_OK; -} - - - -/****************************************************************************/ - -#ifndef NO_ADDFILEINEXISTINGZIP -/* =========================================================================== - Inputs a long in LSB order to the given file - nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) -*/ - -local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); -local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) -{ - unsigned char buf[8]; - int n; - for (n = 0; n < nbByte; n++) - { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - if (x != 0) - { /* data overflow - hack for ZIP64 (X Roche) */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } - - if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) - return ZIP_ERRNO; - else - return ZIP_OK; -} - -local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); -local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) -{ - unsigned char* buf=(unsigned char*)dest; - int n; - for (n = 0; n < nbByte; n++) { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - - if (x != 0) - { /* data overflow - hack for ZIP64 */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } -} - -/****************************************************************************/ - - -local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) -{ - uLong year = (uLong)ptm->tm_year; - if (year>=1980) - year-=1980; - else if (year>=80) - year-=80; - return - (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | - ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); -} - - -/****************************************************************************/ - -local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); - -local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) -{ - unsigned char c; - int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return ZIP_OK; - } - else - { - if (ZERROR64(*pzlib_filefunc_def,filestream)) - return ZIP_ERRNO; - else - return ZIP_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); - -local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ - uLong x ; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); - -local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ - uLong x ; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); - - -local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) -{ - ZPOS64_T x; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (ZPOS64_T)i; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<8; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<16; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<24; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<32; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<40; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<48; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<56; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - - return err; -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); - -local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T uSizeFile; - ZPOS64_T uBackRead; - ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; - - if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); - if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - -/* -Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before -the global comment) -*/ -local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); - -local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T uSizeFile; - ZPOS64_T uBackRead; - ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; - uLong uL; - ZPOS64_T relativeOffset; - - if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); - if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - { - // Signature "0x07064b50" Zip64 end of central directory locater - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) - { - uPosFound = uReadPos+i; - break; - } - } - - if (uPosFound!=0) - break; - } - - TRYFREE(buf); - if (uPosFound == 0) - return 0; - - /* Zip64 end of central directory locator */ - if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) - return 0; - - /* the signature, already checked */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - - /* number of the disk with the start of the zip64 end of central directory */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - if (uL != 0) - return 0; - - /* relative offset of the zip64 end of central directory record */ - if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) - return 0; - - /* total number of disks */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - if (uL != 1) - return 0; - - /* Goto Zip64 end of central directory record */ - if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) - return 0; - - /* the signature */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - - if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' - return 0; - - return relativeOffset; -} - -int LoadCentralDirectoryRecord(zip64_internal* pziinit) -{ - int err=ZIP_OK; - ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - - ZPOS64_T size_central_dir; /* size of the central directory */ - ZPOS64_T offset_central_dir; /* offset of start of central directory */ - ZPOS64_T central_pos; - uLong uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - ZPOS64_T number_entry; - ZPOS64_T number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - uLong VersionMadeBy; - uLong VersionNeeded; - uLong size_comment; - - int hasZIP64Record = 0; - - // check first if we find a ZIP64 record - central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); - if(central_pos > 0) - { - hasZIP64Record = 1; - } - else if(central_pos == 0) - { - central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); - } - -/* disable to allow appending to empty ZIP archive - if (central_pos==0) - err=ZIP_ERRNO; -*/ - - if(hasZIP64Record) - { - ZPOS64_T sizeEndOfCentralDirectory; - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - /* the signature, already checked */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) - err=ZIP_ERRNO; - - /* size of zip64 end of central directory record */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) - err=ZIP_ERRNO; - - /* version made by */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) - err=ZIP_ERRNO; - - /* version needed to extract */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of this disk */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of the disk with the start of the central directory */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central directory on this disk */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central directory */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) - err=ZIP_BADZIPFILE; - - /* size of the central directory */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - // TODO.. - // read the comment from the standard central header. - size_comment = 0; - } - else - { - // Read End of central Directory info - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=ZIP_ERRNO; - - /* the signature, already checked */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of this disk */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of the disk with the start of the central directory */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir on this disk */ - number_entry = 0; - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - number_entry = uL; - - /* total number of entries in the central dir */ - number_entry_CD = 0; - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - number_entry_CD = uL; - - if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) - err=ZIP_BADZIPFILE; - - /* size of the central directory */ - size_central_dir = 0; - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - size_central_dir = uL; - - /* offset of start of central directory with respect to the starting disk number */ - offset_central_dir = 0; - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - offset_central_dir = uL; - - - /* zipfile global comment length */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) - err=ZIP_ERRNO; - } - - if ((central_posz_filefunc, pziinit->filestream); - return ZIP_ERRNO; - } - - if (size_comment>0) - { - pziinit->globalcomment = (char*)ALLOC(size_comment+1); - if (pziinit->globalcomment) - { - size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); - pziinit->globalcomment[size_comment]=0; - } - } - - byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); - pziinit->add_position_when_writting_offset = byte_before_the_zipfile; - - { - ZPOS64_T size_central_dir_to_read = size_central_dir; - size_t buf_size = SIZEDATA_INDATABLOCK; - void* buf_read = (void*)ALLOC(buf_size); - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - while ((size_central_dir_to_read>0) && (err==ZIP_OK)) - { - ZPOS64_T read_this = SIZEDATA_INDATABLOCK; - if (read_this > size_central_dir_to_read) - read_this = size_central_dir_to_read; - - if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) - err=ZIP_ERRNO; - - if (err==ZIP_OK) - err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); - - size_central_dir_to_read-=read_this; - } - TRYFREE(buf_read); - } - pziinit->begin_pos = byte_before_the_zipfile; - pziinit->number_entry = number_entry_CD; - - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - return err; -} - - -#endif /* !NO_ADDFILEINEXISTINGZIP*/ - - -/************************************************************/ -extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) -{ - zip64_internal ziinit; - zip64_internal* zi; - int err=ZIP_OK; - - ziinit.z_filefunc.zseek32_file = NULL; - ziinit.z_filefunc.ztell32_file = NULL; - if (pzlib_filefunc64_32_def==NULL) - fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); - else - ziinit.z_filefunc = *pzlib_filefunc64_32_def; - - ziinit.filestream = ZOPEN64(ziinit.z_filefunc, - pathname, - (append == APPEND_STATUS_CREATE) ? - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); - - if (ziinit.filestream == NULL) - return NULL; - - if (append == APPEND_STATUS_CREATEAFTER) - ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); - - ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); - ziinit.in_opened_file_inzip = 0; - ziinit.ci.stream_initialised = 0; - ziinit.number_entry = 0; - ziinit.add_position_when_writting_offset = 0; - init_linkedlist(&(ziinit.central_dir)); - - - - zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); - if (zi==NULL) - { - ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); - return NULL; - } - - /* now we add file in a zipfile */ -# ifndef NO_ADDFILEINEXISTINGZIP - ziinit.globalcomment = NULL; - if (append == APPEND_STATUS_ADDINZIP) - { - // Read and Cache Central Directory Records - err = LoadCentralDirectoryRecord(&ziinit); - } - - if (globalcomment) - { - *globalcomment = ziinit.globalcomment; - } -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - - if (err != ZIP_OK) - { -# ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(ziinit.globalcomment); -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - TRYFREE(zi); - return NULL; - } - else - { - *zi = ziinit; - return (zipFile)zi; - } -} - -extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) -{ - if (pzlib_filefunc32_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); - return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); - } - else - return zipOpen3(pathname, append, globalcomment, NULL); -} - -extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) -{ - if (pzlib_filefunc_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; - zlib_filefunc64_32_def_fill.ztell32_file = NULL; - zlib_filefunc64_32_def_fill.zseek32_file = NULL; - return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); - } - else - return zipOpen3(pathname, append, globalcomment, NULL); -} - - - -extern zipFile ZEXPORT zipOpen (const char* pathname, int append) -{ - return zipOpen3((const void*)pathname,append,NULL,NULL); -} - -extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) -{ - return zipOpen3(pathname,append,NULL,NULL); -} - -int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) -{ - /* write the local header */ - int err; - uInt size_filename = (uInt)strlen(filename); - uInt size_extrafield = size_extrafield_local; - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); - - if (err==ZIP_OK) - { - if(zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ - } - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); - - // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ - if (err==ZIP_OK) - { - if(zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ - } - if (err==ZIP_OK) - { - if(zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ - } - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); - - if(zi->ci.zip64) - { - size_extrafield += 20; - } - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); - - if ((err==ZIP_OK) && (size_filename > 0)) - { - if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) - err = ZIP_ERRNO; - } - - if ((err==ZIP_OK) && (size_extrafield_local > 0)) - { - if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) - err = ZIP_ERRNO; - } - - - if ((err==ZIP_OK) && (zi->ci.zip64)) - { - // write the Zip64 extended info - short HeaderID = 1; - short DataSize = 16; - ZPOS64_T CompressedSize = 0; - ZPOS64_T UncompressedSize = 0; - - // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) - zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); - } - - return err; -} - -/* - NOTE. - When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped - before calling this function it can be done with zipRemoveExtraInfoBlock - - It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize - unnecessary allocations. - */ -extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, - uLong versionMadeBy, uLong flagBase, int zip64) -{ - zip64_internal* zi; - uInt size_filename; - uInt size_comment; - uInt i; - int err = ZIP_OK; - -# ifdef NOCRYPT - if (password != NULL) - return ZIP_PARAMERROR; -# endif - - if (file == NULL) - return ZIP_PARAMERROR; - -#ifdef HAVE_BZIP2 - if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) - return ZIP_PARAMERROR; -#else - if ((method!=0) && (method!=Z_DEFLATED)) - return ZIP_PARAMERROR; -#endif - - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - if (err != ZIP_OK) - return err; - } - - if (filename==NULL) - filename="-"; - - if (comment==NULL) - size_comment = 0; - else - size_comment = (uInt)strlen(comment); - - size_filename = (uInt)strlen(filename); - - if (zipfi == NULL) - zi->ci.dosDate = 0; - else - { - if (zipfi->dosDate != 0) - zi->ci.dosDate = zipfi->dosDate; - else - zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); - } - - zi->ci.flag = flagBase; - if ((level==8) || (level==9)) - zi->ci.flag |= 2; - if ((level==2)) - zi->ci.flag |= 4; - if ((level==1)) - zi->ci.flag |= 6; - if (password != NULL) - zi->ci.flag |= 1; - - zi->ci.crc32 = 0; - zi->ci.method = method; - zi->ci.encrypt = 0; - zi->ci.stream_initialised = 0; - zi->ci.pos_in_buffered_data = 0; - zi->ci.raw = raw; - zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); - - zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; - zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data - - zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); - - zi->ci.size_centralExtra = size_extrafield_global; - zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); - /* version info */ - zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); - zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); - zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); - zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); - zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); - zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ - zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ - zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ - zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); - zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); - zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); - zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ - - if (zipfi==NULL) - zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); - else - zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); - - if (zipfi==NULL) - zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); - else - zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); - - if(zi->ci.pos_local_header >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); - else - zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); - - for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = - *(((const char*)extrafield_global)+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ - size_extrafield_global+i) = *(comment+i); - if (zi->ci.central_header == NULL) - return ZIP_INTERNALERROR; - - zi->ci.zip64 = zip64; - zi->ci.totalCompressedData = 0; - zi->ci.totalUncompressedData = 0; - zi->ci.pos_zip64extrainfo = 0; - - err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); - -#ifdef HAVE_BZIP2 - zi->ci.bstream.avail_in = (uInt)0; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - zi->ci.bstream.total_in_hi32 = 0; - zi->ci.bstream.total_in_lo32 = 0; - zi->ci.bstream.total_out_hi32 = 0; - zi->ci.bstream.total_out_lo32 = 0; -#endif - - zi->ci.stream.avail_in = (uInt)0; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - zi->ci.stream.total_in = 0; - zi->ci.stream.total_out = 0; - zi->ci.stream.data_type = Z_BINARY; - -#ifdef HAVE_BZIP2 - if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) -#else - if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) -#endif - { - if(zi->ci.method == Z_DEFLATED) - { - zi->ci.stream.zalloc = (alloc_func)0; - zi->ci.stream.zfree = (free_func)0; - zi->ci.stream.opaque = (voidpf)0; - - if (windowBits>0) - windowBits = -windowBits; - - err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); - - if (err==Z_OK) - zi->ci.stream_initialised = Z_DEFLATED; - } - else if(zi->ci.method == Z_BZIP2ED) - { -#ifdef HAVE_BZIP2 - // Init BZip stuff here - zi->ci.bstream.bzalloc = 0; - zi->ci.bstream.bzfree = 0; - zi->ci.bstream.opaque = (voidpf)0; - - err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); - if(err == BZ_OK) - zi->ci.stream_initialised = Z_BZIP2ED; -#endif - } - - } - -# ifndef NOCRYPT - zi->ci.crypt_header_size = 0; - if ((err==Z_OK) && (password != NULL)) - { - unsigned char bufHead[RAND_HEAD_LEN]; - unsigned int sizeHead; - zi->ci.encrypt = 1; - zi->ci.pcrc_32_tab = get_crc_table(); - /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ - - sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); - zi->ci.crypt_header_size = sizeHead; - - if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) - err = ZIP_ERRNO; - } -# endif - - if (err==Z_OK) - zi->in_opened_file_inzip = 1; - return err; -} - -extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, - uLong versionMadeBy, uLong flagBase) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, versionMadeBy, flagBase, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, VERSIONMADEBY, 0, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void*extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void*extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, 0); -} - -local int zip64FlushWriteBuffer(zip64_internal* zi) -{ - int err=ZIP_OK; - - if (zi->ci.encrypt != 0) - { -#ifndef NOCRYPT - uInt i; - int t; - for (i=0;ici.pos_in_buffered_data;i++) - zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); -#endif - } - - if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) - err = ZIP_ERRNO; - - zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; - -#ifdef HAVE_BZIP2 - if(zi->ci.method == Z_BZIP2ED) - { - zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; - zi->ci.bstream.total_in_lo32 = 0; - zi->ci.bstream.total_in_hi32 = 0; - } - else -#endif - { - zi->ci.totalUncompressedData += zi->ci.stream.total_in; - zi->ci.stream.total_in = 0; - } - - - zi->ci.pos_in_buffered_data = 0; - - return err; -} - -extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) -{ - zip64_internal* zi; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - - zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); - -#ifdef HAVE_BZIP2 - if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) - { - zi->ci.bstream.next_in = (void*)buf; - zi->ci.bstream.avail_in = len; - err = BZ_RUN_OK; - - while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) - { - if (zi->ci.bstream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - } - - - if(err != BZ_RUN_OK) - break; - - if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) - { - uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; -// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; - err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); - - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; - } - } - - if(err == BZ_RUN_OK) - err = ZIP_OK; - } - else -#endif - { - zi->ci.stream.next_in = (Bytef*)buf; - zi->ci.stream.avail_in = len; - - while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) - { - if (zi->ci.stream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - - - if(err != ZIP_OK) - break; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - uLong uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_NO_FLUSH); - if(uTotalOutBefore > zi->ci.stream.total_out) - { - int bBreak = 0; - bBreak++; - } - - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - } - else - { - uInt copy_this,i; - if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) - copy_this = zi->ci.stream.avail_in; - else - copy_this = zi->ci.stream.avail_out; - - for (i = 0; i < copy_this; i++) - *(((char*)zi->ci.stream.next_out)+i) = - *(((const char*)zi->ci.stream.next_in)+i); - { - zi->ci.stream.avail_in -= copy_this; - zi->ci.stream.avail_out-= copy_this; - zi->ci.stream.next_in+= copy_this; - zi->ci.stream.next_out+= copy_this; - zi->ci.stream.total_in+= copy_this; - zi->ci.stream.total_out+= copy_this; - zi->ci.pos_in_buffered_data += copy_this; - } - } - }// while(...) - } - - return err; -} - -extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) -{ - return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); -} - -extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) -{ - zip64_internal* zi; - ZPOS64_T compressed_size; - uLong invalidValue = 0xffffffff; - short datasize = 0; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - zi->ci.stream.avail_in = 0; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - while (err==ZIP_OK) - { - uLong uTotalOutBefore; - if (zi->ci.stream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_FINISH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - } - } - else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) - { -#ifdef HAVE_BZIP2 - err = BZ_FINISH_OK; - while (err==BZ_FINISH_OK) - { - uLong uTotalOutBefore; - if (zi->ci.bstream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - } - uTotalOutBefore = zi->ci.bstream.total_out_lo32; - err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); - if(err == BZ_STREAM_END) - err = Z_STREAM_END; - - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); - } - - if(err == BZ_FINISH_OK) - err = ZIP_OK; -#endif - } - - if (err==Z_STREAM_END) - err=ZIP_OK; /* this is normal */ - - if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) - { - if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) - err = ZIP_ERRNO; - } - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - int tmp_err = deflateEnd(&zi->ci.stream); - if (err == ZIP_OK) - err = tmp_err; - zi->ci.stream_initialised = 0; - } -#ifdef HAVE_BZIP2 - else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) - { - int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); - if (err==ZIP_OK) - err = tmperr; - zi->ci.stream_initialised = 0; - } -#endif - - if (!zi->ci.raw) - { - crc32 = (uLong)zi->ci.crc32; - uncompressed_size = zi->ci.totalUncompressedData; - } - compressed_size = zi->ci.totalCompressedData; - -# ifndef NOCRYPT - compressed_size += zi->ci.crypt_header_size; -# endif - - // update Current Item crc and sizes, - if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) - { - /*version Made by*/ - zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); - /*version needed*/ - zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); - - } - - zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ - - - if(compressed_size >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ - else - zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ - - /// set internal file attributes field - if (zi->ci.stream.data_type == Z_ASCII) - zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); - - if(uncompressed_size >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ - else - zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ - - // Add ZIP64 extra info field for uncompressed size - if(uncompressed_size >= 0xffffffff) - datasize += 8; - - // Add ZIP64 extra info field for compressed size - if(compressed_size >= 0xffffffff) - datasize += 8; - - // Add ZIP64 extra info field for relative offset to local file header of current file - if(zi->ci.pos_local_header >= 0xffffffff) - datasize += 8; - - if(datasize > 0) - { - char* p = NULL; - - if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) - { - // we can not write more data to the buffer that we have room for. - return ZIP_BADZIPFILE; - } - - p = zi->ci.central_header + zi->ci.size_centralheader; - - // Add Extra Information Header for 'ZIP64 information' - zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID - p += 2; - zip64local_putValue_inmemory(p, datasize, 2); // DataSize - p += 2; - - if(uncompressed_size >= 0xffffffff) - { - zip64local_putValue_inmemory(p, uncompressed_size, 8); - p += 8; - } - - if(compressed_size >= 0xffffffff) - { - zip64local_putValue_inmemory(p, compressed_size, 8); - p += 8; - } - - if(zi->ci.pos_local_header >= 0xffffffff) - { - zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); - p += 8; - } - - // Update how much extra free space we got in the memory buffer - // and increase the centralheader size so the new ZIP64 fields are included - // ( 4 below is the size of HeaderID and DataSize field ) - zi->ci.size_centralExtraFree -= datasize + 4; - zi->ci.size_centralheader += datasize + 4; - - // Update the extra info size field - zi->ci.size_centralExtra += datasize + 4; - zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); - } - - if (err==ZIP_OK) - err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); - - free(zi->ci.central_header); - - if (err==ZIP_OK) - { - // Update the LocalFileHeader with the new values. - - ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); - - if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - - if(uncompressed_size >= 0xffffffff) - { - if(zi->ci.pos_zip64extrainfo > 0) - { - // Update the size in the ZIP64 extended field. - if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if (err==ZIP_OK) /* compressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); - } - } - else - { - if (err==ZIP_OK) /* compressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); - } - - if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - } - - zi->number_entry ++; - zi->in_opened_file_inzip = 0; - - return err; -} - -extern int ZEXPORT zipCloseFileInZip (zipFile file) -{ - return zipCloseFileInZipRaw (file,0,0); -} - -int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) -{ - int err = ZIP_OK; - ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); - - /*num disks*/ - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); - - /*relative offset*/ - if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); - - /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); - - return err; -} - -int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) -{ - int err = ZIP_OK; - - uLong Zip64DataSize = 44; - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); - - if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? - - if (err==ZIP_OK) /* version made by */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); - - if (err==ZIP_OK) /* version needed */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); - - if (err==ZIP_OK) /* number of this disk */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); - - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); - - if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); - - if (err==ZIP_OK) /* total number of entries in the central dir */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); - - if (err==ZIP_OK) /* size of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); - - if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ - { - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); - } - return err; -} -int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) -{ - int err = ZIP_OK; - - /*signature*/ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); - - if (err==ZIP_OK) /* number of this disk */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ - { - { - if(zi->number_entry >= 0xFFFF) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - } - } - - if (err==ZIP_OK) /* total number of entries in the central dir */ - { - if(zi->number_entry >= 0xFFFF) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - } - - if (err==ZIP_OK) /* size of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); - - if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ - { - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; - if(pos >= 0xffffffff) - { - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); - } - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); - } - - return err; -} - -int Write_GlobalComment(zip64_internal* zi, const char* global_comment) -{ - int err = ZIP_OK; - uInt size_global_comment = 0; - - if(global_comment != NULL) - size_global_comment = (uInt)strlen(global_comment); - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); - - if (err == ZIP_OK && size_global_comment > 0) - { - if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) - err = ZIP_ERRNO; - } - return err; -} - -extern int ZEXPORT zipClose (zipFile file, const char* global_comment) -{ - zip64_internal* zi; - int err = 0; - uLong size_centraldir = 0; - ZPOS64_T centraldir_pos_inzip; - ZPOS64_T pos; - - if (file == NULL) - return ZIP_PARAMERROR; - - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - } - -#ifndef NO_ADDFILEINEXISTINGZIP - if (global_comment==NULL) - global_comment = zi->globalcomment; -#endif - - centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); - - if (err==ZIP_OK) - { - linkedlist_datablock_internal* ldi = zi->central_dir.first_block; - while (ldi!=NULL) - { - if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) - { - if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) - err = ZIP_ERRNO; - } - - size_centraldir += ldi->filled_in_this_block; - ldi = ldi->next_datablock; - } - } - free_linkedlist(&(zi->central_dir)); - - pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; - if(pos >= 0xffffffff) - { - ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); - Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); - - Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); - } - - if (err==ZIP_OK) - err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); - - if(err == ZIP_OK) - err = Write_GlobalComment(zi, global_comment); - - if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) - if (err == ZIP_OK) - err = ZIP_ERRNO; - -#ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(zi->globalcomment); -#endif - TRYFREE(zi); - - return err; -} - -extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) -{ - char* p = pData; - int size = 0; - char* pNewHeader; - char* pTmp; - short header; - short dataSize; - - int retVal = ZIP_OK; - - if(pData == NULL || *dataLen < 4) - return ZIP_PARAMERROR; - - pNewHeader = (char*)ALLOC(*dataLen); - pTmp = pNewHeader; - - while(p < (pData + *dataLen)) - { - header = *(short*)p; - dataSize = *(((short*)p)+1); - - if( header == sHeader ) // Header found. - { - p += dataSize + 4; // skip it. do not copy to temp buffer - } - else - { - // Extra Info block should not be removed, So copy it to the temp buffer. - memcpy(pTmp, p, dataSize + 4); - p += dataSize + 4; - size += dataSize + 4; - } - - } - - if(size < *dataLen) - { - // clean old extra info block. - memset(pData,0, *dataLen); - - // copy the new extra info block over the old - if(size > 0) - memcpy(pData, pNewHeader, size); - - // set the new extra info size - *dataLen = size; - - retVal = ZIP_OK; - } - else - retVal = ZIP_ERRNO; - - TRYFREE(pNewHeader); - - return retVal; -} diff --git a/libminizip/zip.h b/libminizip/zip.h deleted file mode 100644 index 88feecc84..000000000 --- a/libminizip/zip.h +++ /dev/null @@ -1,362 +0,0 @@ -/* zip.h -- IO on .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - --------------------------------------------------------------------------- - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - --------------------------------------------------------------------------- - - Changes - - See header of zip.h - -*/ - -#ifndef _zip12_H -#define _zip12_H - -#ifdef __cplusplus -extern "C" { -#endif - -//#define HAVE_BZIP2 - -#ifndef _ZLIB_H -#include "zlib/zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#ifdef HAVE_BZIP2 -#include "bzlib.h" -#endif - -#define Z_BZIP2ED 12 - -#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagzipFile__ { int unused; } zipFile__; -typedef zipFile__ *zipFile; -#else -typedef voidp zipFile; -#endif - -#define ZIP_OK (0) -#define ZIP_EOF (0) -#define ZIP_ERRNO (Z_ERRNO) -#define ZIP_PARAMERROR (-102) -#define ZIP_BADZIPFILE (-103) -#define ZIP_INTERNALERROR (-104) - -#ifndef DEF_MEM_LEVEL -# if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -# else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -# endif -#endif -/* default memLevel */ - -/* tm_zip contain date/time info */ -typedef struct tm_zip_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_zip; - -typedef struct -{ - tm_zip tmz_date; /* date in understandable format */ - uLong dosDate; /* if dos_date == 0, tmu_date is used */ -/* uLong flag; */ /* general purpose bit flag 2 bytes */ - - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ -} zip_fileinfo; - -typedef const char* zipcharpc; - - -#define APPEND_STATUS_CREATE (0) -#define APPEND_STATUS_CREATEAFTER (1) -#define APPEND_STATUS_ADDINZIP (2) - -extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); -extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); -/* - Create a zipfile. - pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on - an Unix computer "zlib/zlib113.zip". - if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip - will be created at the end of the file. - (useful if the file contain a self extractor code) - if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will - add files in existing zip (be sure you don't add file that doesn't exist) - If the zipfile cannot be opened, the return value is NULL. - Else, the return value is a zipFile Handle, usable with other function - of this zip package. -*/ - -/* Note : there is no delete function into a zipfile. - If you want delete file into a zipfile, you must open a zipfile, and create another - Of couse, you can use RAW reading and writing to copy the file you did not want delte -*/ - -extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, - int append, - zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc_def)); - -extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, - int append, - zipcharpc* globalcomment, - zlib_filefunc64_def* pzlib_filefunc_def)); - -extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level)); - -extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int zip64)); - -/* - Open a file in the ZIP for writing. - filename : the filename in zip (if NULL, '-' without quote will be used - *zipfi contain supplemental information - if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local - contains the extrafield data the the local header - if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global - contains the extrafield data the the local header - if comment != NULL, comment contain the comment string - method contain the compression method (0 for store, Z_DEFLATED for deflate) - level contain the level of compression (can be Z_DEFAULT_COMPRESSION) - zip64 is set to 1 if a zip64 extended information block should be added to the local file header. - this MUST be '1' if the uncompressed size is >= 0xffffffff. - -*/ - - -extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw)); - - -extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int zip64)); -/* - Same than zipOpenNewFileInZip, except if raw=1, we write raw file - */ - -extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting)); - -extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - int zip64 - )); - -/* - Same than zipOpenNewFileInZip2, except - windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 - password : crypting password (NULL for no crypting) - crcForCrypting : crc of file to compress (needed for crypting) - */ - -extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - uLong versionMadeBy, - uLong flagBase - )); - - -extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - uLong versionMadeBy, - uLong flagBase, - int zip64 - )); -/* - Same than zipOpenNewFileInZip4, except - versionMadeBy : value for Version made by field - flag : value for flag field (compression level info will be added) - */ - - -extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, - const void* buf, - unsigned len)); -/* - Write data in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); -/* - Close the current file in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, - uLong uncompressed_size, - uLong crc32)); - -extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, - ZPOS64_T uncompressed_size, - uLong crc32)); - -/* - Close the current file in the zipfile, for file opened with - parameter raw=1 in zipOpenNewFileInZip2 - uncompressed_size and crc32 are value for the uncompressed size -*/ - -extern int ZEXPORT zipClose OF((zipFile file, - const char* global_comment)); -/* - Close the zipfile -*/ - - -extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); -/* - zipRemoveExtraInfoBlock - Added by Mathias Svensson - - Remove extra information block from a extra information data for the local file header or central directory header - - It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. - - 0x0001 is the signature header for the ZIP64 extra information blocks - - usage. - Remove ZIP64 Extra information from a central director extra field data - zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); - - Remove ZIP64 Extra information from a Local File Header extra field data - zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); -*/ - -#ifdef __cplusplus -} -#endif - -#endif /* _zip64_H */ diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 5298cde62..8f57c24a6 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -20,13 +20,15 @@ * Ethereum IDE client. */ +#include +#include #include #include #include #include #include +#include #include -#include "libminizip/zip.h" #include "FileIo.h" using namespace dev::mix; @@ -104,47 +106,54 @@ bool FileIo::fileExists(QString const& _url) return file.exists(); } -QString compress(QString const& _manifest, QString const& _folder) +QString FileIo::compress(QString const& _manifest, QString const& _deploymentFolder) { - zipFile compressed = zipOpen(_folder + "\dapp.zip", APPEND_STATUS_CREATE); - zip_fileinfo zfiManifest = { 0 }; - bool res = zipOpenNewFileInZip(compressed, "manifest.json", - &zfiManifest, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION); - if (res) - { - zipWriteInFileInZip(compressed, _manifest , _manifest.size()); - zipCloseFileInZip(compressed); - } + QUrl folder(_deploymentFolder); + QString path(folder.path()); + QDir deployDir = QDir(path); + + dev::RLPStream str; + + QByteArray manifestBytes = "swarm.json"; + str.append(bytes(manifestBytes.begin(), manifestBytes.end())); + + QByteArray manifestcontentBytes = "application/json"; + str.append(bytes(manifestcontentBytes.begin(), manifestcontentBytes.end())); + + QByteArray b = _manifest.toUtf8(); + str.append(bytes(b.begin(), b.end())); - QDirIterator dirIt(_folder, QDirIterator::Subdirectories); - while (dirIt.hasNext()) + for (auto item: deployDir.entryInfoList(QDir::Files)) { - dirIt.next(); - QFile file(dirIt.filePath()); - QByteArray _a; - while (!file.atEnd()) + QFile qFile(item.filePath()); + if (qFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - QByteArray line = file.readLine(); - _a.insert(_a, line.begin(), line.end()); - } - zip_fileinfo zfi = { 0 }; - res = zipOpenNewFileInZip(compressed, QFileInfo(dirIt.filePath()).fileName().toStdString(), - &zfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION); - if (res) - { - zipWriteInFileInZip(compressed, _a, _a.size()); - zipCloseFileInZip(compressed); + QFileInfo i = QFileInfo(qFile.fileName()); + QByteArray fileBytes = i.fileName().toUtf8(); + str.append(bytes(fileBytes.begin(), fileBytes.end())); + + QByteArray contentBytes = QString().toUtf8(); + str.append(bytes(contentBytes.begin(), contentBytes.end())); + + QByteArray _a = qFile.readAll(); + str.append(bytes(_a.begin(), _a.end())); } - file.close(); + qFile.close(); } - QFile zip(_folder + "\dapp.zip"); - QByteArray aZip; - while (!zip.atEnd()) + bytes dapp = str.out(); + dev::h256 h = dev::sha3(dapp); + QString ret = QString::fromStdString(toHex(h.ref())); + QUrl url(_deploymentFolder + "package.dapp"); + QFile compressed(url.path()); + if (compressed.open(QIODevice::WriteOnly | QIODevice::Text)) { - QByteArray line = zip.readLine(); - aZip.insert(aZip, line.begin(), line.end()); + compressed.write((char*)dapp.data(), dapp.size()); + compressed.flush(); } - dev::h256 h = dev::sha3(aZip); - return toHex(h.ref()); + else + error(tr("Error creating package.dapp")); + compressed.close(); + return ret; } + diff --git a/mix/FileIo.h b/mix/FileIo.h index f534b4be0..5bfd17aa9 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -22,6 +22,7 @@ #pragma once +#include #include namespace dev @@ -53,7 +54,7 @@ public: /// Check if file exists Q_INVOKABLE bool fileExists(QString const& _url); /// Compress a folder, @returns sha3 of the compressed file. - Q_INVOKABLE QString compress(QString const& _manifest, QString const& _folder); + Q_INVOKABLE QString compress(QString const& _manifest, QString const& _deploymentFolder); private: QString getHomePath() const; diff --git a/mix/QVariableDefinition.h b/mix/QVariableDefinition.h index 1825c2567..8d890539b 100644 --- a/mix/QVariableDefinition.h +++ b/mix/QVariableDefinition.h @@ -53,6 +53,8 @@ public: virtual bytes encodeValue() = 0; /// Decode the return value @a _rawValue. virtual void decodeValue(dev::bytes const& _rawValue) = 0; + /// returns String representation of the encoded value. + Q_INVOKABLE QString encodeValueAsString() { return QString::fromStdString(dev::toHex(encodeValue())); } protected: QString m_value; diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 56d9069cf..c4f94630d 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -5,18 +5,18 @@ import QtQuick.Window 2.0 import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper +import "js/ProjectModel.js" as ProjectModelCode import "." Window { - id: modalTransactionDialog + id: modalDeploymentDialog modality: Qt.ApplicationModal width: 520 - height: 300 + height: 200 visible: false property alias applicationUrlEth: applicationUrlEth.text property alias applicationUrlHttp: applicationUrlHttp.text - - signal accepted + color: Style.generic.layout.backgroundColor function close() { @@ -25,64 +25,66 @@ Window { function open() { + modalDeploymentDialog.setX((Screen.width - width) / 2); + modalDeploymentDialog.setY((Screen.height - height) / 2); visible = true; } - ColumnLayout + GridLayout { - anchors.fill: parent - RowLayout + columns: 2 + anchors.top: parent.top + anchors.left: parent.left + anchors.topMargin: 10 + anchors.leftMargin: 10 + anchors.rightMargin: 10 + DefaultLabel { - height: 40 - DefaultLabel - { - text: qsTr("Fill in eth application URL") - } - - Rectangle - { - TextField - { - id: applicationUrlEth - } - } + text: qsTr("Eth URL: ") } - RowLayout + DefaultTextField { - height: 40 - DefaultLabel - { - text: qsTr("Fill in http application URL") - } + id: applicationUrlEth + } - Rectangle - { - TextField - { - id: applicationUrlHttp - } - } + DefaultLabel + { + text: qsTr("Http URL: ") } - RowLayout + DefaultTextField { - anchors.bottom: parent.bottom - anchors.right: parent.right; + id: applicationUrlHttp + } + } - Button { - text: qsTr("OK"); - onClicked: { - close(); - accepted(); - } - } - Button { - text: qsTr("Cancel"); - onClicked: close(); + RowLayout + { + anchors.bottom: parent.bottom + anchors.right: parent.right; + anchors.bottomMargin: 10 + Button { + text: qsTr("Deploy"); + enabled: Object.keys(projectModel.deploymentAddresses).length === 0 + onClicked: { + ProjectModelCode.startDeployProject(); } } - } + Button { + text: qsTr("Rebuild Package"); + enabled: Object.keys(projectModel.deploymentAddresses).length > 0 && applicationUrlHttp.text !== "" + onClicked: { + var date = new Date(); + var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); + ProjectModelCode.finalizeDeployment(deploymentId, projectModel.deploymentAddresses); + } + } + Button { + text: qsTr("Close"); + onClicked: close(); + } + } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index e1c69af65..435d0342c 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -31,7 +31,7 @@ Item { property string projectPath: "" property string projectTitle: "" property string currentDocumentId: "" - property string deploymentAddress: "" + property var deploymentAddresses: [] property var listModel: projectListModel property var stateListModel: projectStateListModel.model property CodeEditorView codeEditor: null @@ -103,9 +103,6 @@ Item { DeploymentDialog { id: deploymentDialog - onAccepted: { - ProjectModelCode.startDeployProject() - } } ListModel { diff --git a/mix/qml/Style.qml b/mix/qml/Style.qml index 9e4b6f268..c317177a3 100644 --- a/mix/qml/Style.qml +++ b/mix/qml/Style.qml @@ -11,6 +11,7 @@ QtObject { property QtObject generic: QtObject { property QtObject layout: QtObject { property string separatorColor: "#808080" + property string backgroundColor: "#ededed" } property QtObject size: QtObject { property string titlePointSize: absoluteSize(0) diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 2a63cd1e6..aa0ed723c 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -19,9 +19,12 @@ * @date 2015 * Ethereum IDE client. */ +Qt.include("QEtherHelper.js") var htmlTemplate = "\n\n\n\n\n\n\n"; var contractTemplate = "contract Contract {\n}\n"; +var registrarContract = "6fcdee8688e44aebdcddf28a8d87318d38f695ff" /*"0000000000000000000000000000000000000a28"*/ +var hintContract = "c4040ef9635e7503bbbc74b73a9385ac78733d09" function saveAll() { saveProject(); @@ -45,7 +48,9 @@ function saveProject() { var projectData = { files: [], title: projectTitle, - deploymentAddress: deploymentAddress + deploymentAddresses: deploymentAddresses, + applicationUrlEth: deploymentDialog.applicationUrlEth, + applicationUrlHttp: deploymentDialog.applicationUrlHttp }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push(projectListModel.get(i).fileName) @@ -63,11 +68,15 @@ function loadProject(path) { var projectFile = path + projectFileName; var json = fileIo.readFile(projectFile); var projectData = JSON.parse(json); + if (projectData.applicationUrlEth) + deploymentDialog.applicationUrlEth = projectData.applicationUrlEth + if (projectData.applicationUrlHttp) + deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp if (!projectData.title) { var parts = path.split("/"); projectData.title = parts[parts.length - 2]; } - deploymentAddress = projectData.deploymentAddress ? projectData.deploymentAddress : ""; + deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : []; projectTitle = projectData.title; projectPath = path; if (!projectData.files) @@ -275,10 +284,10 @@ function deployProject(force) { saveAll(); //TODO: ask user - if (!force && deploymentAddress !== "") { + /*if (!force && deploymentAddresses !== []) { deployWarningDialog.visible = true; return; - } + }*/ deploymentDialog.open(); } @@ -293,6 +302,7 @@ function startDeployProject() var requests = []; var requestNames = []; + for (var c in codeModel.contracts) { //TODO: order based on dependencies var code = codeModel.contracts[c].codeHex; requests.push({ @@ -304,8 +314,8 @@ function startDeployProject() requestNames.push(c); } - var rpcRequest = JSON.stringify(requests);; - var httpRequest = new XMLHttpRequest() + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); httpRequest.open("POST", jsonRpcUrl, true); httpRequest.setRequestHeader("Content-type", "application/json"); httpRequest.setRequestHeader("Content-length", rpcRequest.length); @@ -317,7 +327,7 @@ function startDeployProject() if (rpcResponse.length === requestNames.length) { var contractAddresses = {}; for (var r = 0; r < rpcResponse.length; r++) - contractAddresses[requestNames[r]] = rpcResponse.result; + contractAddresses[requestNames[r]] = rpcResponse[r].result; finalizeDeployment(deploymentId, contractAddresses); } } else { @@ -335,8 +345,6 @@ function finalizeDeployment(deploymentId, addresses) { var deploymentDir = projectPath + deploymentId + "/"; fileIo.makeDir(deploymentDir); var manifest = { - previous: 'jgjgj67576576576567ytjy', - first: 'ds564rh5656hhfghfg', entries: [] }; for (var i = 0; i < projectListModel.count; i++) { @@ -361,6 +369,7 @@ function finalizeDeployment(deploymentId, addresses) { } else fileIo.copyFile(doc.path, deploymentDir + doc.fileName); + var jsonFile = { path: '/' + doc.fileName, file: '/' + doc.fileName @@ -384,30 +393,116 @@ function finalizeDeployment(deploymentId, addresses) { //copy scripts fileIo.copyFile("qrc:///js/bignumber.min.js", deploymentDir + "bignumber.min.js"); fileIo.copyFile("qrc:///js/webthree.js", deploymentDir + "ethereum.js"); - deploymentAddress = address; + deploymentAddresses = addresses; saveProject(); var hash = fileIo.compress(JSON.stringify(manifest), deploymentDir); - //Call Registry var applicationUrlEth = deploymentDialog.applicationUrlEth; var applicationUrlHttp = deploymentDialog.applicationUrlHttp; - applicationUrlEth = formatAppUrl(applicationEth); - deploymentComplete(); + applicationUrlEth = formatAppUrl(applicationUrlEth); + checkRegistration(applicationUrlEth, registrarContract, hash, function () { + deploymentComplete(); + }); +} + +function checkRegistration(dappUrl, addr, hash, callBack) +{ + var requests = []; + var data = ""; + if (dappUrl.length > 0) + { + //checking path (addr). + var str = createString(dappUrl[0]); + data = "6be16bed" + str.encodeValueAsString(); + console.log("checking if path exists (register) => " + data); + requests.push({ + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": addr, "data": data } ], + id: jsonRpcRequestId++ + }); + } + else + { + //finalize (setContentHash). + finalize = true; + var paramTitle = createString(projectModel.projectTitle); + var paramHash = createHash(hash); + data = "5d574e32" + paramTitle.encodeValueAsString() + paramHash.encodeValueAsString(); + console.log("finalize (setRegister) => " + data); + requests.push({ + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": addr, "data": data } ], + id: jsonRpcRequestId++ + }); + + var paramWebUrl = createString(deploymentDialog.applicationUrlHttp); + var dataHint = "4983e19c" + paramHash.encodeValueAsString() + paramWebUrl.encodeValueAsString(); + requests.push({ + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": hintContract, "data": dataHint } ], + id: jsonRpcRequestId++ + }); + } + + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status === 200) { + console.log(httpRequest.responseText); + if (dappUrl.length > 0) + { + var address = JSON.parse(httpRequest.responseText)[0].result.replace('0x', ''); + if (address === "") + deploymentError(qsTr("This Eth Dapp path has not been registered")); + else + { + dappUrl.splice(0, 1); + checkRegistration(dappUrl, address, hash, callBack); + } + } + else + callBack(); + } else { + var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status; + console.log(errorText); + deploymentError(errorText); + } + } + } + httpRequest.send(rpcRequest); } function formatAppUrl(url) { - var slash = url.indexof("/"); - var dot = url.indexof("."); - if ((slash === -1 && dot === -1) || dot > slash) + var slash = url.indexOf("/"); + var dot = url.indexOf("."); + if (slash === -1 && dot === -1) return url; + if (slash !== -1 && slash < dot) + return url.split("/"); else { - var split = url.split("/"); - var dotted = split[0].split("."); - var main = ""; + var dotted; + var ret = []; + if (slash !== -1) + { + ret.push(url.split("/")); + dotted = ret[0].split("."); + } + else + dotted = url.split("."); + for (var k in dotted) - main += dotted[k] + '/' + main; - return main; + ret.unshift(dotted[k]); + return ret; } } diff --git a/mix/qml/js/QEtherHelper.js b/mix/qml/js/QEtherHelper.js index 7563941d2..71ee258c3 100644 --- a/mix/qml/js/QEtherHelper.js +++ b/mix/qml/js/QEtherHelper.js @@ -15,3 +15,19 @@ function createBigInt(_value) return bigint; } +function createString(_value) +{ + var stringComponent = Qt.createComponent("qrc:/qml/QStringType.qml"); + var stringC = stringComponent.createObject(); + stringC.setValue(_value); + return stringC; +} + +function createHash(_value) +{ + var hComponent = Qt.createComponent("qrc:/qml/QHashType.qml"); + var hC = hComponent.createObject(); + hC.setValue(_value); + return hC; +} + From 945c2866e36a5b66c9041b7503290523f412cde7 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 19 Feb 2015 01:51:28 +0100 Subject: [PATCH 135/201] ui/ux changes --- mix/qml/DeploymentDialog.qml | 7 +++++-- mix/qml/ProjectModel.qml | 2 +- mix/qml/js/ProjectModel.js | 7 ------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index c4f94630d..88dfb90b2 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -66,9 +66,12 @@ Window { anchors.bottomMargin: 10 Button { text: qsTr("Deploy"); - enabled: Object.keys(projectModel.deploymentAddresses).length === 0 + enabled: applicationUrlHttp.text !== "" onClicked: { - ProjectModelCode.startDeployProject(); + if (Object.keys(projectModel.deploymentAddresses).length > 0) + deployWarningDialog.open(); + else + ProjectModelCode.startDeployProject(); } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 435d0342c..d1767ea5b 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -96,7 +96,7 @@ Item { standardButtons: StandardButton.Ok | StandardButton.Cancel icon: StandardIcon.Question onAccepted: { - ProjectModelCode.deployProject(true); + ProjectModelCode.startDeployProject(); } } diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index aa0ed723c..0af32c083 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -281,14 +281,7 @@ function generateFileName(name, extension) { var jsonRpcRequestId = 1; function deployProject(force) { - saveAll(); //TODO: ask user - - /*if (!force && deploymentAddresses !== []) { - deployWarningDialog.visible = true; - return; - }*/ - deploymentDialog.open(); } From 88955a7049bc2179ef875856578831f3325614ee Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 19 Feb 2015 08:21:12 +0100 Subject: [PATCH 136/201] 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 137/201] 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 138/201] 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 139/201] 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 140/201] 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 141/201] 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 142/201] 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 143/201] 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 144/201] 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 145/201] 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 146/201] 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 147/201] 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 148/201] 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 149/201] 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 86d446d2ba778d89c533fb99ce3b50184138a3bc Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 20 Feb 2015 18:10:21 +0100 Subject: [PATCH 150/201] Contract Deployment: - add files hash - add test action (to be removed --- mix/FileIo.cpp | 39 +++++-- mix/FileIo.h | 2 +- mix/qml/DeploymentDialog.qml | 128 +++++++++++++++++++++++ mix/qml/TransactionDialog.qml | 2 +- mix/qml/js/ProjectModel.js | 189 +++++++++++++++++++++++----------- 5 files changed, 287 insertions(+), 73 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 8f57c24a6..02d8b9bef 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -20,6 +20,8 @@ * Ethereum IDE client. */ +#include +#include #include #include #include @@ -106,23 +108,18 @@ bool FileIo::fileExists(QString const& _url) return file.exists(); } -QString FileIo::compress(QString const& _manifest, QString const& _deploymentFolder) +QString FileIo::compress(QString const& _deploymentFolder) { + + Json::Value manifest; + Json::Value entries(Json::arrayValue); + QUrl folder(_deploymentFolder); QString path(folder.path()); QDir deployDir = QDir(path); dev::RLPStream str; - QByteArray manifestBytes = "swarm.json"; - str.append(bytes(manifestBytes.begin(), manifestBytes.end())); - - QByteArray manifestcontentBytes = "application/json"; - str.append(bytes(manifestcontentBytes.begin(), manifestcontentBytes.end())); - - QByteArray b = _manifest.toUtf8(); - str.append(bytes(b.begin(), b.end())); - for (auto item: deployDir.entryInfoList(QDir::Files)) { QFile qFile(item.filePath()); @@ -133,14 +130,34 @@ QString FileIo::compress(QString const& _manifest, QString const& _deploymentFol str.append(bytes(fileBytes.begin(), fileBytes.end())); QByteArray contentBytes = QString().toUtf8(); - str.append(bytes(contentBytes.begin(), contentBytes.end())); + bytes b = bytes(contentBytes.begin(), contentBytes.end()); + str.append(b); QByteArray _a = qFile.readAll(); str.append(bytes(_a.begin(), _a.end())); + + Json::Value f; + f["path"] = "/"; //TODO: Manage relative sub folder + f["file"] = "/" + i.fileName().toStdString(); + f["hash"] = toHex(dev::sha3(b).ref()); + entries.append(f); } qFile.close(); } + manifest["entries"] = entries; + + QByteArray manifestBytes = "swarm.json"; + str.append(bytes(manifestBytes.begin(), manifestBytes.end())); + + QByteArray manifestcontentBytes = "application/json"; + str.append(bytes(manifestcontentBytes.begin(), manifestcontentBytes.end())); + + std::stringstream jsonStr; + jsonStr << manifest; + QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8(); + str.append(bytes(b.begin(), b.end())); + bytes dapp = str.out(); dev::h256 h = dev::sha3(dapp); QString ret = QString::fromStdString(toHex(h.ref())); diff --git a/mix/FileIo.h b/mix/FileIo.h index 5bfd17aa9..d8899015b 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -54,7 +54,7 @@ public: /// Check if file exists Q_INVOKABLE bool fileExists(QString const& _url); /// Compress a folder, @returns sha3 of the compressed file. - Q_INVOKABLE QString compress(QString const& _manifest, QString const& _deploymentFolder); + Q_INVOKABLE QString compress(QString const& _deploymentFolder); private: QString getHomePath() const; diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 88dfb90b2..a2b8b3623 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -6,8 +6,10 @@ import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper import "js/ProjectModel.js" as ProjectModelCode +import "js/QEtherHelper.js" as QEtherHelper import "." + Window { id: modalDeploymentDialog modality: Qt.ApplicationModal @@ -16,6 +18,12 @@ Window { visible: false property alias applicationUrlEth: applicationUrlEth.text property alias applicationUrlHttp: applicationUrlHttp.text + property string root: "42f6279a5b6d350e1ce2a9ebef05657c79275c6a"; + property string eth: "31f6aee7f26e9d3320753c112ed34bcfc3c989b8"; + property string wallet: "c4040ef9635e7503bbbc74b73a9385ac78733d09"; + property string urlHintContract: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a" + + color: Style.generic.layout.backgroundColor function close() @@ -30,6 +38,16 @@ Window { visible = true; } + function pad(h) + { + // TODO move this to QHashType class + while (h.length < 64) + { + h = '0' + h; + } + return h; + } + GridLayout { columns: 2 @@ -89,5 +107,115 @@ Window { text: qsTr("Close"); onClicked: close(); } + + Button { + text: qsTr("Check Ownership"); + onClicked: { + var requests = []; + var ethStr = QEtherHelper.createString("eth"); + + var ethHash = QEtherHelper.createHash(eth); + + requests.push({ //owner + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], + id: 3 + }); + + requests.push({ //register + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], + id: 4 + }); + + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status === 200) { + console.log(httpRequest.responseText); + } else { + var errorText = qsTr("path registration failed ") + httpRequest.status; + console.log(errorText); + } + } + } + httpRequest.send(rpcRequest); + } + } + + + Button { + text: qsTr("Generate registrar init"); + onClicked: { + console.log("registering eth/wallet") + var jsonRpcRequestId = 0; + + var requests = []; + var ethStr = QEtherHelper.createString("eth"); + var ethHash = QEtherHelper.createHash(eth); + requests.push({ //reserve + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x1c83171b" + ethStr.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + + console.log("0x7d2e3ce9" + ethStr.encodeValueAsString() + pad(eth)); + console.log(ethStr.encodeValueAsString()); + console.log(pad(eth)); + + requests.push({ //setRegister + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x96077307" + ethStr.encodeValueAsString() + pad(eth) /*ethHash.encodeValueAsString()*/ } ], + id: jsonRpcRequestId++ + }); + + var walletStr = QEtherHelper.createString("wallet"); + var walletHash = QEtherHelper.createHash(wallet); + + requests.push({ //reserve + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + walletStr.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + + + requests.push({ //setRegister + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + walletStr.encodeValueAsString() + pad(wallet) } ], + id: jsonRpcRequestId++ + }); + + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status === 200) { + console.log(httpRequest.responseText); + } else { + var errorText = qsTr("path registration failed ") + httpRequest.status; + console.log(errorText); + } + } + } + httpRequest.send(rpcRequest); + } + } } } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index e5a8bc746..434f8a850 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -405,7 +405,7 @@ Window { return boolViewComp; else if (type.indexOf("string") !== -1) return stringViewComp; - else if (type.indexOf("hash") !== -1) + else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1) return hashViewComp; else return null; diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 0af32c083..6426e39ef 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -23,8 +23,6 @@ Qt.include("QEtherHelper.js") var htmlTemplate = "\n\n\n\n\n\n\n"; var contractTemplate = "contract Contract {\n}\n"; -var registrarContract = "6fcdee8688e44aebdcddf28a8d87318d38f695ff" /*"0000000000000000000000000000000000000a28"*/ -var hintContract = "c4040ef9635e7503bbbc74b73a9385ac78733d09" function saveAll() { saveProject(); @@ -337,9 +335,6 @@ function finalizeDeployment(deploymentId, addresses) { //create a dir for frontend files and copy them var deploymentDir = projectPath + deploymentId + "/"; fileIo.makeDir(deploymentDir); - var manifest = { - entries: [] - }; for (var i = 0; i < projectListModel.count; i++) { var doc = projectListModel.get(i); if (doc.isContract) @@ -362,12 +357,6 @@ function finalizeDeployment(deploymentId, addresses) { } else fileIo.copyFile(doc.path, deploymentDir + doc.fileName); - - var jsonFile = { - path: '/' + doc.fileName, - file: '/' + doc.fileName - } - manifest.entries.push(jsonFile); } //write deployment js var deploymentJs = @@ -389,89 +378,168 @@ function finalizeDeployment(deploymentId, addresses) { deploymentAddresses = addresses; saveProject(); - var hash = fileIo.compress(JSON.stringify(manifest), deploymentDir); + var hash = fileIo.compress(deploymentDir); var applicationUrlEth = deploymentDialog.applicationUrlEth; - var applicationUrlHttp = deploymentDialog.applicationUrlHttp; applicationUrlEth = formatAppUrl(applicationUrlEth); - checkRegistration(applicationUrlEth, registrarContract, hash, function () { + checkRegistration(applicationUrlEth, deploymentDialog.root, hash, function () { deploymentComplete(); }); } +function rpcCall(requests, callBack) +{ + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status !== 200) + { + var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status; + console.log(errorText); + deploymentError(errorText); + return; + } + console.log(httpRequest.responseText); + callBack(httpRequest.status, httpRequest.responseText) + } + } + httpRequest.send(rpcRequest); +} + + function checkRegistration(dappUrl, addr, hash, callBack) { + console.log("CALL TO " + addr); var requests = []; var data = ""; + console.log(JSON.stringify(dappUrl)); if (dappUrl.length > 0) { - //checking path (addr). + //checking path (register). var str = createString(dappUrl[0]); - data = "6be16bed" + str.encodeValueAsString(); + data = "0x6be16bed" + str.encodeValueAsString(); console.log("checking if path exists (register) => " + data); + console.log("adrr : " + '0x' + addr + " param " + data); requests.push({ jsonrpc: "2.0", method: "eth_call", - params: [ { "to": addr, "data": data } ], + params: [ { "to": '0x' + addr, "data": data } ], id: jsonRpcRequestId++ }); + + rpcCall(requests, function (httpRequest, response) { + var address = JSON.parse(response)[0].result.replace('0x', ''); + if (address === "") + { + var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + " cannot continue"); + deploymentError(errorTxt); + console.log(errorTxt); + return; + } + + dappUrl.splice(0, 1); + checkRegistration(dappUrl, address, hash, callBack); + }); } else { - //finalize (setContentHash). - finalize = true; var paramTitle = createString(projectModel.projectTitle); - var paramHash = createHash(hash); - data = "5d574e32" + paramTitle.encodeValueAsString() + paramHash.encodeValueAsString(); - console.log("finalize (setRegister) => " + data); requests.push({ - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": addr, "data": data } ], - id: jsonRpcRequestId++ - }); + //owner() + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + addr, "data": "0xec7b9200" + paramTitle.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); - var paramWebUrl = createString(deploymentDialog.applicationUrlHttp); - var dataHint = "4983e19c" + paramHash.encodeValueAsString() + paramWebUrl.encodeValueAsString(); requests.push({ + //accounts jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": hintContract, "data": dataHint } ], + method: "eth_accounts", + params: null, id: jsonRpcRequestId++ }); - } - var jsonRpcUrl = "http://localhost:8080"; - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - if (httpRequest.status === 200) { - console.log(httpRequest.responseText); - if (dappUrl.length > 0) + rpcCall(requests, function (httpRequest, response) { + requests = []; + var res = JSON.parse(response); + var currentOwner = res[0].result; + var noOwner = currentOwner.replace('0x', '').replace(/0/g, '') === ''; + var bOwner = false; + + if (noOwner) + { + requests.push({ + //reserve() + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + addr, "data": "0x1c83171b" + paramTitle.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + } + else + { + currentOwner = normalizeAddress(currentOwner); + for (var u in res[1].result) { - var address = JSON.parse(httpRequest.responseText)[0].result.replace('0x', ''); - if (address === "") - deploymentError(qsTr("This Eth Dapp path has not been registered")); - else - { - dappUrl.splice(0, 1); - checkRegistration(dappUrl, address, hash, callBack); - } + if (normalizeAddress(res[1].result[u]) === currentOwner) + bOwner = true; + } + + if (!bOwner) + { + var errorTxt = qsTr("Current user is not the owner of this path. Cannot continue") + deploymentError(errorTxt); + console.log(errorTxt); + return; } - else - callBack(); - } else { - var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status; - console.log(errorText); - deploymentError(errorText); } - } + + + requests.push({ + //setContent() + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + addr, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + hash } ], + id: jsonRpcRequestId++ + }); + console.log("reserve and register"); + rpcCall(requests, function (httpRequest, response) { + requests = []; + var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); + requests.push({ + //urlHint => suggestUrl + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + hash + paramUrlHttp.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function (httpRequest, response) { + callBack(); + }); + }); + }); } - httpRequest.send(rpcRequest); +} + +function normalizeAddress(addr) +{ + addr = addr.replace('0x', ''); + var i = 0; + for (var k in addr) + { + if (addr[k] !== "0") + break; + else + i++; + } + return addr.substring(i); } function formatAppUrl(url) @@ -499,3 +567,4 @@ function formatAppUrl(url) return ret; } } + From 73d5ff677e8c768c282e87ffc57a60420388d7f5 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 19 Feb 2015 10:51:22 +0100 Subject: [PATCH 151/201] 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 152/201] 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 153/201] 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 154/201] 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 155/201] 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 156/201] 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 21cdd082752185561a264a242360781099531a90 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 20 Feb 2015 20:00:51 +0100 Subject: [PATCH 157/201] Changes on deployment process: - Deploy Contract + Package + Register to Registry. - Register to UrlHint. Display Base64 Value Encrypt --- mix/FileIo.cpp | 44 ++++++++++++++++---------- mix/FileIo.h | 2 +- mix/qml/DeploymentDialog.qml | 41 ++++++++++++++++++------ mix/qml/ProjectModel.qml | 2 ++ mix/qml/StatusPane.qml | 1 + mix/qml/js/ProjectModel.js | 60 +++++++++++++++++++----------------- 6 files changed, 94 insertions(+), 56 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 02d8b9bef..b368e6a1f 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -20,7 +20,6 @@ * Ethereum IDE client. */ -#include #include #include #include @@ -29,10 +28,15 @@ #include #include #include +#include +#include +#include #include #include #include "FileIo.h" +using namespace dev; +using namespace dev::crypto; using namespace dev::mix; void FileIo::makeDir(QString const& _url) @@ -108,7 +112,7 @@ bool FileIo::fileExists(QString const& _url) return file.exists(); } -QString FileIo::compress(QString const& _deploymentFolder) +QStringList FileIo::compress(QString const& _deploymentFolder) { Json::Value manifest; @@ -119,6 +123,14 @@ QString FileIo::compress(QString const& _deploymentFolder) QDir deployDir = QDir(path); dev::RLPStream str; + int k = 1; + for (auto item: deployDir.entryInfoList(QDir::Files)) + { + QFile qFile(item.filePath()); + if (qFile.open(QIODevice::ReadOnly | QIODevice::Text)) + k++; + } + str.appendList(k); for (auto item: deployDir.entryInfoList(QDir::Files)) { @@ -126,19 +138,15 @@ QString FileIo::compress(QString const& _deploymentFolder) if (qFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QFileInfo i = QFileInfo(qFile.fileName()); - QByteArray fileBytes = i.fileName().toUtf8(); - str.append(bytes(fileBytes.begin(), fileBytes.end())); - - QByteArray contentBytes = QString().toUtf8(); - bytes b = bytes(contentBytes.begin(), contentBytes.end()); - str.append(b); QByteArray _a = qFile.readAll(); - str.append(bytes(_a.begin(), _a.end())); + bytes b = bytes(_a.begin(), _a.end()); + str.append(b); Json::Value f; f["path"] = "/"; //TODO: Manage relative sub folder f["file"] = "/" + i.fileName().toStdString(); + f["contentType"] = "application/html"; //TODO: manage multiple content type f["hash"] = toHex(dev::sha3(b).ref()); entries.append(f); } @@ -147,12 +155,6 @@ QString FileIo::compress(QString const& _deploymentFolder) manifest["entries"] = entries; - QByteArray manifestBytes = "swarm.json"; - str.append(bytes(manifestBytes.begin(), manifestBytes.end())); - - QByteArray manifestcontentBytes = "application/json"; - str.append(bytes(manifestcontentBytes.begin(), manifestcontentBytes.end())); - std::stringstream jsonStr; jsonStr << manifest; QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8(); @@ -160,17 +162,25 @@ QString FileIo::compress(QString const& _deploymentFolder) bytes dapp = str.out(); dev::h256 h = dev::sha3(dapp); - QString ret = QString::fromStdString(toHex(h.ref())); + //encrypt + KeyPair key(h); + Secp256k1 enc; + enc.encrypt(key.pub(), dapp); + QUrl url(_deploymentFolder + "package.dapp"); QFile compressed(url.path()); + QByteArray qFileBytes((char*)dapp.data(), dapp.size()); if (compressed.open(QIODevice::WriteOnly | QIODevice::Text)) { - compressed.write((char*)dapp.data(), dapp.size()); + compressed.write(qFileBytes); compressed.flush(); } else error(tr("Error creating package.dapp")); compressed.close(); + QStringList ret; + ret.append(QString::fromStdString(toHex(h.ref()))); + ret.append(qFileBytes.toBase64()); return ret; } diff --git a/mix/FileIo.h b/mix/FileIo.h index d8899015b..2048a37c6 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -54,7 +54,7 @@ public: /// Check if file exists Q_INVOKABLE bool fileExists(QString const& _url); /// Compress a folder, @returns sha3 of the compressed file. - Q_INVOKABLE QString compress(QString const& _deploymentFolder); + Q_INVOKABLE QStringList compress(QString const& _deploymentFolder); private: QString getHomePath() const; diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index a2b8b3623..5ee0a3422 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -14,15 +14,16 @@ Window { id: modalDeploymentDialog modality: Qt.ApplicationModal width: 520 - height: 200 + height: 350 visible: false property alias applicationUrlEth: applicationUrlEth.text property alias applicationUrlHttp: applicationUrlHttp.text + property string urlHintContract: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a" + property string packageHash + property alias packageBase64: base64Value.text property string root: "42f6279a5b6d350e1ce2a9ebef05657c79275c6a"; property string eth: "31f6aee7f26e9d3320753c112ed34bcfc3c989b8"; property string wallet: "c4040ef9635e7503bbbc74b73a9385ac78733d09"; - property string urlHintContract: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a" - color: Style.generic.layout.backgroundColor @@ -75,6 +76,17 @@ Window { { id: applicationUrlHttp } + + DefaultLabel + { + text: qsTr("Package: ") + } + + TextArea + { + id: base64Value + height: 60 + } } RowLayout @@ -83,7 +95,8 @@ Window { anchors.right: parent.right; anchors.bottomMargin: 10 Button { - text: qsTr("Deploy"); + text: qsTr("Deploy on Ethereum"); + tooltip: qsTr("Deploy the contract and Package ressources files.") enabled: applicationUrlHttp.text !== "" onClicked: { if (Object.keys(projectModel.deploymentAddresses).length > 0) @@ -94,12 +107,11 @@ Window { } Button { - text: qsTr("Rebuild Package"); + text: qsTr("Register Web Application"); + tooltip: qsTr("Register hosted Web Application.") enabled: Object.keys(projectModel.deploymentAddresses).length > 0 && applicationUrlHttp.text !== "" onClicked: { - var date = new Date(); - var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); - ProjectModelCode.finalizeDeployment(deploymentId, projectModel.deploymentAddresses); + ProjectModelCode.registerToUrlHint(); } } @@ -110,13 +122,14 @@ Window { Button { text: qsTr("Check Ownership"); + visible : false onClicked: { var requests = []; - var ethStr = QEtherHelper.createString("eth"); + var ethStr = QEtherHelper.createString("mul"); var ethHash = QEtherHelper.createHash(eth); - requests.push({ //owner + /*requests.push({ //owner jsonrpc: "2.0", method: "eth_call", params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], @@ -128,6 +141,13 @@ Window { method: "eth_call", params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], id: 4 + });*/ + + requests.push({ //register + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.wallet, "data": "0x618242da" + ethStr.encodeValueAsString() } ], + id: 4 }); var jsonRpcUrl = "http://localhost:8080"; @@ -154,6 +174,7 @@ Window { Button { text: qsTr("Generate registrar init"); + visible: false onClicked: { console.log("registering eth/wallet") var jsonRpcRequestId = 0; diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index d1767ea5b..d14f9379f 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -21,6 +21,7 @@ Item { signal newProject(var projectData) signal documentSaved(var documentId) signal deploymentStarted() + signal deploymentStepChanged(string message) signal deploymentComplete() signal deploymentError(string error) @@ -55,6 +56,7 @@ Item { function getDocumentIndex(documentId) { return ProjectModelCode.getDocumentIndex(documentId); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } function deployProject() { ProjectModelCode.deployProject(false); } + function registerToUrlHint() { ProjectModelCode.registerToUrlHint(); } Connections { target: appContext diff --git a/mix/qml/StatusPane.qml b/mix/qml/StatusPane.qml index 6a8a0093d..1f226279d 100644 --- a/mix/qml/StatusPane.qml +++ b/mix/qml/StatusPane.qml @@ -47,6 +47,7 @@ Rectangle { onDeploymentStarted: infoMessage(qsTr("Running deployment...")); onDeploymentError: infoMessage(error); onDeploymentComplete: infoMessage(qsTr("Deployment complete")); + onDeploymentStepChanged: infoMessage(message); } Connections { target: codeModel diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 6426e39ef..81d774857 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -332,7 +332,7 @@ function startDeployProject() } function finalizeDeployment(deploymentId, addresses) { - //create a dir for frontend files and copy them + deploymentStepChanged(qsTr("Packaging application ...")); var deploymentDir = projectPath + deploymentId + "/"; fileIo.makeDir(deploymentDir); for (var i = 0; i < projectListModel.count; i++) { @@ -378,10 +378,14 @@ function finalizeDeployment(deploymentId, addresses) { deploymentAddresses = addresses; saveProject(); - var hash = fileIo.compress(deploymentDir); + var packageRet = fileIo.compress(deploymentDir); + deploymentDialog.packageHash = packageRet[0]; + deploymentDialog.packageBase64 = packageRet[1]; + var applicationUrlEth = deploymentDialog.applicationUrlEth; applicationUrlEth = formatAppUrl(applicationUrlEth); - checkRegistration(applicationUrlEth, deploymentDialog.root, hash, function () { + deploymentStepChanged(qsTr("Registering application on Ethereum ...")); + checkRegistration(applicationUrlEth, deploymentDialog.root, function () { deploymentComplete(); }); } @@ -404,7 +408,6 @@ function rpcCall(requests, callBack) deploymentError(errorText); return; } - console.log(httpRequest.responseText); callBack(httpRequest.status, httpRequest.responseText) } } @@ -412,19 +415,16 @@ function rpcCall(requests, callBack) } -function checkRegistration(dappUrl, addr, hash, callBack) +function checkRegistration(dappUrl, addr, callBack) { - console.log("CALL TO " + addr); var requests = []; var data = ""; - console.log(JSON.stringify(dappUrl)); if (dappUrl.length > 0) { //checking path (register). var str = createString(dappUrl[0]); data = "0x6be16bed" + str.encodeValueAsString(); - console.log("checking if path exists (register) => " + data); - console.log("adrr : " + '0x' + addr + " param " + data); + console.log("checking if path exists (register) => " + JSON.stringify(dappUrl)); requests.push({ jsonrpc: "2.0", method: "eth_call", @@ -443,7 +443,7 @@ function checkRegistration(dappUrl, addr, hash, callBack) } dappUrl.splice(0, 1); - checkRegistration(dappUrl, address, hash, callBack); + checkRegistration(dappUrl, address, callBack); }); } else @@ -470,7 +470,6 @@ function checkRegistration(dappUrl, addr, hash, callBack) var res = JSON.parse(response); var currentOwner = res[0].result; var noOwner = currentOwner.replace('0x', '').replace(/0/g, '') === ''; - var bOwner = false; if (noOwner) { @@ -484,6 +483,7 @@ function checkRegistration(dappUrl, addr, hash, callBack) } else { + var bOwner = false; currentOwner = normalizeAddress(currentOwner); for (var u in res[1].result) { @@ -499,35 +499,39 @@ function checkRegistration(dappUrl, addr, hash, callBack) return; } } - - + console.log("setContentHash"); requests.push({ //setContent() jsonrpc: "2.0", method: "eth_transact", - params: [ { "to": '0x' + addr, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + hash } ], + params: [ { "to": '0x' + addr, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ], id: jsonRpcRequestId++ }); - console.log("reserve and register"); rpcCall(requests, function (httpRequest, response) { - requests = []; - var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); - requests.push({ - //urlHint => suggestUrl - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + hash + paramUrlHttp.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - - rpcCall(requests, function (httpRequest, response) { - callBack(); - }); + callBack(); }); }); } } +function registerToUrlHint() +{ + deploymentStepChanged(qsTr("Registering application Ressources (" + deploymentDialog.applicationUrlHttp) + ") ..."); + var requests = []; + var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); + requests.push({ + //urlHint => suggestUrl + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); + + rpcCall(requests, function (httpRequest, response) { + deploymentComplete(); + }); +} + function normalizeAddress(addr) { addr = addr.replace('0x', ''); From 4323c987b77af21a5099ca9e2df1710c024d033f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 20 Feb 2015 21:00:13 +0100 Subject: [PATCH 158/201] 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 159/201] 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 160/201] 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 161/201] 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 162/201] 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 163/201] 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 164/201] 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 165/201] 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 166/201] 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 167/201] 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 168/201] 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 e101cc6b32111247041244313b1708b5fb225f5d Mon Sep 17 00:00:00 2001 From: yann300 Date: Sat, 21 Feb 2015 02:13:23 +0100 Subject: [PATCH 169/201] small changes --- mix/qml/DeploymentDialog.qml | 313 +++++++++++++++++++---------------- mix/qml/ProjectModel.qml | 30 +++- mix/qml/js/ProjectModel.js | 23 ++- 3 files changed, 215 insertions(+), 151 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index 5ee0a3422..e72866512 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -2,6 +2,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.1 import QtQuick.Window 2.0 +import QtQuick.Dialogs 1.1 import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper @@ -13,7 +14,7 @@ import "." Window { id: modalDeploymentDialog modality: Qt.ApplicationModal - width: 520 + width: 600 height: 350 visible: false property alias applicationUrlEth: applicationUrlEth.text @@ -21,9 +22,9 @@ Window { property string urlHintContract: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a" property string packageHash property alias packageBase64: base64Value.text - property string root: "42f6279a5b6d350e1ce2a9ebef05657c79275c6a"; - property string eth: "31f6aee7f26e9d3320753c112ed34bcfc3c989b8"; - property string wallet: "c4040ef9635e7503bbbc74b73a9385ac78733d09"; + property string root: "165fd25527c23aa90f8009dad4465bafab5d7dd0"; + property string eth: "afb7cdbd076674fd2c67f8a66518e3145b184ae4"; + property string wallet: "c83d3e22645fb015d02043a744921cc2f828c64d"; color: Style.generic.layout.backgroundColor @@ -49,87 +50,110 @@ Window { return h; } - GridLayout + Rectangle { - columns: 2 - anchors.top: parent.top - anchors.left: parent.left - anchors.topMargin: 10 - anchors.leftMargin: 10 - anchors.rightMargin: 10 - DefaultLabel + anchors.fill : parent + anchors.margins: 10 + color: Style.generic.layout.backgroundColor + GridLayout { - text: qsTr("Eth URL: ") - } + columns: 2 + anchors.top: parent.top + anchors.left: parent.left + width: parent.width + DefaultLabel + { + text: qsTr("Ethereum Application URL: ") + } - DefaultTextField - { - id: applicationUrlEth - } + DefaultTextField + { + Layout.fillWidth: true + id: applicationUrlEth + } - DefaultLabel - { - text: qsTr("Http URL: ") - } + DefaultLabel + { + text: qsTr("Web Application Ressources URL: ") + } - DefaultTextField - { - id: applicationUrlHttp - } + DefaultTextField + { + Layout.fillWidth: true + id: applicationUrlHttp + } - DefaultLabel - { - text: qsTr("Package: ") + DefaultLabel + { + text: qsTr("Package (Base64): ") + } + + TextArea + { + Layout.fillWidth: true + readOnly: true + id: base64Value + height: 60 + enabled: base64Value.text != "" + } } - TextArea - { - id: base64Value - height: 60 + MessageDialog { + id: deployDialog + standardButtons: StandardButton.Ok + icon: StandardIcon.Warning } - } - RowLayout - { - anchors.bottom: parent.bottom - anchors.right: parent.right; - anchors.bottomMargin: 10 - Button { - text: qsTr("Deploy on Ethereum"); - tooltip: qsTr("Deploy the contract and Package ressources files.") - enabled: applicationUrlHttp.text !== "" - onClicked: { - if (Object.keys(projectModel.deploymentAddresses).length > 0) - deployWarningDialog.open(); - else - ProjectModelCode.startDeployProject(); + RowLayout + { + anchors.bottom: parent.bottom + anchors.right: parent.right; + anchors.bottomMargin: 10 + Button { + text: qsTr("Deploy on Ethereum"); + tooltip: qsTr("Deploy the contract and Package ressources files.") + onClicked: { + if (applicationUrlEth.text === "") + { + deployDialog.title = text; + deployDialog.text = qsTr("Please provide the Ethereum link you want to use for this application.") + deployDialog.open(); + } + else + deployWarningDialog.open(); + } } - } - Button { - text: qsTr("Register Web Application"); - tooltip: qsTr("Register hosted Web Application.") - enabled: Object.keys(projectModel.deploymentAddresses).length > 0 && applicationUrlHttp.text !== "" - onClicked: { - ProjectModelCode.registerToUrlHint(); + Button { + text: qsTr("Register Web Application"); + tooltip: qsTr("Register hosted Web Application.") + onClicked: { + if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") + { + deployDialog.title = text; + deployDialog.text = qsTr("Please provide the link where the ressources are stored and ensure the package is aleary built using the deployment step. ") + deployDialog.open(); + } + else + ProjectModelCode.registerToUrlHint(); + } } - } - Button { - text: qsTr("Close"); - onClicked: close(); - } + Button { + text: qsTr("Close"); + onClicked: close(); + } - Button { - text: qsTr("Check Ownership"); - visible : false - onClicked: { - var requests = []; - var ethStr = QEtherHelper.createString("mul"); + Button { + text: qsTr("Check Ownership"); + visible : false + onClicked: { + var requests = []; + var ethStr = QEtherHelper.createString("eth"); - var ethHash = QEtherHelper.createHash(eth); + var ethHash = QEtherHelper.createHash(eth); - /*requests.push({ //owner + requests.push({ //owner jsonrpc: "2.0", method: "eth_call", params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], @@ -141,101 +165,102 @@ Window { method: "eth_call", params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], id: 4 - });*/ - - requests.push({ //register - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.wallet, "data": "0x618242da" + ethStr.encodeValueAsString() } ], - id: 4 }); - var jsonRpcUrl = "http://localhost:8080"; - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - if (httpRequest.status === 200) { - console.log(httpRequest.responseText); - } else { - var errorText = qsTr("path registration failed ") + httpRequest.status; - console.log(errorText); + requests.push({ //register + jsonrpc: "2.0", + method: "eth_call", + params: [ { "to": '0x' + modalDeploymentDialog.wallet, "data": "0x618242da" + ethStr.encodeValueAsString() } ], + id: 4 + }); + + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status === 200) { + console.log(httpRequest.responseText); + } else { + var errorText = qsTr("path registration failed ") + httpRequest.status; + console.log(errorText); + } } } + httpRequest.send(rpcRequest); } - httpRequest.send(rpcRequest); } - } - Button { - text: qsTr("Generate registrar init"); - visible: false - onClicked: { - console.log("registering eth/wallet") - var jsonRpcRequestId = 0; + Button { + text: qsTr("Generate registrar init"); + visible: false + onClicked: { + console.log("registering eth/wallet") + var jsonRpcRequestId = 0; - var requests = []; - var ethStr = QEtherHelper.createString("eth"); - var ethHash = QEtherHelper.createHash(eth); - requests.push({ //reserve - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x1c83171b" + ethStr.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); + var requests = []; + var ethStr = QEtherHelper.createString("eth"); + var ethHash = QEtherHelper.createHash(eth); + requests.push({ //reserve + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x1c83171b" + ethStr.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); - console.log("0x7d2e3ce9" + ethStr.encodeValueAsString() + pad(eth)); - console.log(ethStr.encodeValueAsString()); - console.log(pad(eth)); + console.log("0x7d2e3ce9" + ethStr.encodeValueAsString() + pad(eth)); + console.log(ethStr.encodeValueAsString()); + console.log(pad(eth)); - requests.push({ //setRegister - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x96077307" + ethStr.encodeValueAsString() + pad(eth) /*ethHash.encodeValueAsString()*/ } ], - id: jsonRpcRequestId++ - }); + requests.push({ //setRegister + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x96077307" + ethStr.encodeValueAsString() + pad(eth) /*ethHash.encodeValueAsString()*/ } ], + id: jsonRpcRequestId++ + }); - var walletStr = QEtherHelper.createString("wallet"); - var walletHash = QEtherHelper.createHash(wallet); + var walletStr = QEtherHelper.createString("wallet"); + var walletHash = QEtherHelper.createHash(wallet); - requests.push({ //reserve - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + walletStr.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); + requests.push({ //reserve + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + walletStr.encodeValueAsString() } ], + id: jsonRpcRequestId++ + }); - requests.push({ //setRegister - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + walletStr.encodeValueAsString() + pad(wallet) } ], - id: jsonRpcRequestId++ - }); + requests.push({ //setRegister + jsonrpc: "2.0", + method: "eth_transact", + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + walletStr.encodeValueAsString() + pad(wallet) } ], + id: jsonRpcRequestId++ + }); - var jsonRpcUrl = "http://localhost:8080"; - var rpcRequest = JSON.stringify(requests); - var httpRequest = new XMLHttpRequest(); - httpRequest.open("POST", jsonRpcUrl, true); - httpRequest.setRequestHeader("Content-type", "application/json"); - httpRequest.setRequestHeader("Content-length", rpcRequest.length); - httpRequest.setRequestHeader("Connection", "close"); - httpRequest.onreadystatechange = function() { - if (httpRequest.readyState === XMLHttpRequest.DONE) { - if (httpRequest.status === 200) { - console.log(httpRequest.responseText); - } else { - var errorText = qsTr("path registration failed ") + httpRequest.status; - console.log(errorText); + var jsonRpcUrl = "http://localhost:8080"; + var rpcRequest = JSON.stringify(requests); + var httpRequest = new XMLHttpRequest(); + httpRequest.open("POST", jsonRpcUrl, true); + httpRequest.setRequestHeader("Content-type", "application/json"); + httpRequest.setRequestHeader("Content-length", rpcRequest.length); + httpRequest.setRequestHeader("Connection", "close"); + httpRequest.onreadystatechange = function() { + if (httpRequest.readyState === XMLHttpRequest.DONE) { + if (httpRequest.status === 200) { + console.log(httpRequest.responseText); + } else { + var errorText = qsTr("path registration failed ") + httpRequest.status; + console.log(errorText); + } } } + httpRequest.send(rpcRequest); } - httpRequest.send(rpcRequest); } } } diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index d14f9379f..02929d39e 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -93,13 +93,37 @@ Item { MessageDialog { id: deployWarningDialog + property bool redeploy title: qsTr("Project") - text: qsTr("This project has been already deployed to the network. Do you want to re-deploy it?") - standardButtons: StandardButton.Ok | StandardButton.Cancel + text: + { + if (Object.keys(projectModel.deploymentAddresses).length > 0) + { + redeploy = true + standardButtons = StandardButton.Ok | StandardButton.Reset | StandardButton.Abort; + return qsTr("This project has been already deployed to the network. Do you want to repackage the ressources only, or also reset the deployed contract to his initial state?") + } + else + { + redeploy = false; + standardButtons = StandardButton.Ok | StandardButton.Abort; + return qsTr("This action will deploy to the network. Do you want to deploy it?") + } + } icon: StandardIcon.Question onAccepted: { - ProjectModelCode.startDeployProject(); + ProjectModelCode.startDeployProject(!redeploy); } + onReset: { + ProjectModelCode.startDeployProject(true); + } + } + + MessageDialog { + id: deployRessourcesDialog + title: qsTr("Project") + standardButtons: StandardButton.Ok + icon: StandardIcon.Info } DeploymentDialog diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 81d774857..c2f1a1d4b 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -48,7 +48,9 @@ function saveProject() { title: projectTitle, deploymentAddresses: deploymentAddresses, applicationUrlEth: deploymentDialog.applicationUrlEth, - applicationUrlHttp: deploymentDialog.applicationUrlHttp + applicationUrlHttp: deploymentDialog.applicationUrlHttp, + packageHash: deploymentDialog.packageHash, + packageBase64: deploymentDialog.packageBase64 }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push(projectListModel.get(i).fileName) @@ -66,6 +68,10 @@ function loadProject(path) { var projectFile = path + projectFileName; var json = fileIo.readFile(projectFile); var projectData = JSON.parse(json); + if (projectData.packageHash) + deploymentDialog.packageHash = projectData.packageHash + if (projectData.packageBase64) + deploymentDialog.packageBase64 = projectData.packageBase64 if (projectData.applicationUrlEth) deploymentDialog.applicationUrlEth = projectData.applicationUrlEth if (projectData.applicationUrlHttp) @@ -283,10 +289,16 @@ function deployProject(force) { deploymentDialog.open(); } -function startDeployProject() +function startDeployProject(erasePrevious) { var date = new Date(); var deploymentId = date.toLocaleString(Qt.locale(), "ddMMyyHHmmsszzz"); + if (!erasePrevious) + { + finalizeDeployment(deploymentId, projectModel.deploymentAddresses); + return; + } + var jsonRpcUrl = "http://localhost:8080"; console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); deploymentStarted(); @@ -384,9 +396,12 @@ function finalizeDeployment(deploymentId, addresses) { var applicationUrlEth = deploymentDialog.applicationUrlEth; applicationUrlEth = formatAppUrl(applicationUrlEth); - deploymentStepChanged(qsTr("Registering application on Ethereum ...")); + + deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); checkRegistration(applicationUrlEth, deploymentDialog.root, function () { deploymentComplete(); + deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment."); + deployRessourcesDialog.open(); }); } @@ -552,7 +567,7 @@ function formatAppUrl(url) var dot = url.indexOf("."); if (slash === -1 && dot === -1) return url; - if (slash !== -1 && slash < dot) + if ((slash !== -1 && slash < dot) || dot === -1) return url.split("/"); else { From a0f0812fcbc56b69c4298bc4818070b8b9e63d81 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 21 Feb 2015 00:48:43 -0500 Subject: [PATCH 170/201] 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 171/201] 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 30bd6f271f71182c65153f38916d92eceb83fad0 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 20 Feb 2015 15:52:30 +0100 Subject: [PATCH 172/201] Parsing of array types and basic implementation. --- libsolidity/AST.h | 31 +++- libsolidity/ASTForward.h | 1 + libsolidity/ASTPrinter.cpp | 12 ++ libsolidity/ASTPrinter.h | 2 + libsolidity/ASTVisitor.h | 4 + libsolidity/AST_accept.h | 22 +++ libsolidity/CompilerUtils.cpp | 32 ++-- libsolidity/CompilerUtils.h | 4 +- libsolidity/ExpressionCompiler.cpp | 23 +-- libsolidity/ExpressionCompiler.h | 4 +- libsolidity/NameAndTypeResolver.cpp | 6 +- libsolidity/Parser.cpp | 195 +++++++++++++++++++------ libsolidity/Parser.h | 40 +++-- libsolidity/Types.cpp | 64 ++++++-- libsolidity/Types.h | 41 ++++-- test/SolidityNameAndTypeResolution.cpp | 9 ++ test/SolidityParser.cpp | 40 +++++ 17 files changed, 409 insertions(+), 121 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 064457d3b..594f8f4be 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -441,7 +441,7 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - TypeName const* getTypeName() const { return m_typeName.get(); } + TypeName* getTypeName() { 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 @@ -588,7 +588,7 @@ public: /// Retrieve the element of the type hierarchy this node refers to. Can return an empty shared /// pointer until the types have been resolved using the @ref NameAndTypeResolver. /// If it returns an empty shared pointer after that, this indicates that the type was not found. - virtual std::shared_ptr toType() const = 0; + virtual std::shared_ptr toType() = 0; }; /** @@ -605,7 +605,7 @@ public: } virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - virtual std::shared_ptr toType() const override { return Type::fromElementaryTypeName(m_type); } + virtual std::shared_ptr toType() override { return Type::fromElementaryTypeName(m_type); } Token::Value getTypeName() const { return m_type; } @@ -623,7 +623,7 @@ public: TypeName(_location), m_name(_name), m_referencedDeclaration(nullptr) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - virtual std::shared_ptr toType() const override { return Type::fromUserDefinedTypeName(*this); } + virtual std::shared_ptr toType() override { return Type::fromUserDefinedTypeName(*this); } ASTString const& getName() const { return *m_name; } void setReferencedDeclaration(Declaration const& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; } @@ -646,7 +646,7 @@ public: TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - virtual std::shared_ptr toType() const override { return Type::fromMapping(*this); } + virtual TypePointer toType() override { return Type::fromMapping(*m_keyType, *m_valueType); } ElementaryTypeName const& getKeyType() const { return *m_keyType; } TypeName const& getValueType() const { return *m_valueType; } @@ -656,6 +656,27 @@ private: ASTPointer m_valueType; }; +/** + * An array type, can be "typename[]" or "typename[]". + */ +class ArrayTypeName: public TypeName +{ +public: + ArrayTypeName(Location const& _location, ASTPointer const& _baseType, + ASTPointer const& _length): + TypeName(_location), m_baseType(_baseType), m_length(_length) {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + virtual std::shared_ptr toType() override { return Type::fromArrayTypeName(*m_baseType, m_length.get()); } + + TypeName const& getBaseType() const { return *m_baseType; } + Expression const* getLength() const { return m_length.get(); } + +private: + ASTPointer m_baseType; + ASTPointer m_length; ///< Length of the array, might be empty. +}; + /// @} /// Statements diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 3a151b63e..0ba485a2f 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -53,6 +53,7 @@ class TypeName; class ElementaryTypeName; class UserDefinedTypeName; class Mapping; +class ArrayTypeName; class Statement; class Block; class PlaceholderStatement; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 209bb73e6..5bcc46df7 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -155,6 +155,13 @@ bool ASTPrinter::visit(Mapping const& _node) return goDeeper(); } +bool ASTPrinter::visit(ArrayTypeName const& _node) +{ + writeLine("ArrayTypeName"); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(Statement const& _node) { writeLine("Statement"); @@ -419,6 +426,11 @@ void ASTPrinter::endVisit(Mapping const&) m_indentation--; } +void ASTPrinter::endVisit(ArrayTypeName const&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(Statement const&) { m_indentation--; diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index 7a0ef5a65..a1797383c 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -58,6 +58,7 @@ public: bool visit(ElementaryTypeName const& _node) override; bool visit(UserDefinedTypeName const& _node) override; bool visit(Mapping const& _node) override; + bool visit(ArrayTypeName const& _node) override; bool visit(Statement const& _node) override; bool visit(Block const& _node) override; bool visit(PlaceholderStatement const& _node) override; @@ -99,6 +100,7 @@ public: void endVisit(ElementaryTypeName const&) override; void endVisit(UserDefinedTypeName const&) override; void endVisit(Mapping const&) override; + void endVisit(ArrayTypeName const&) override; void endVisit(Statement const&) override; void endVisit(Block const&) override; void endVisit(PlaceholderStatement const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index 2ecfbe4b1..3eeb9c456 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -59,6 +59,7 @@ public: virtual bool visit(ElementaryTypeName&) { return true; } virtual bool visit(UserDefinedTypeName&) { return true; } virtual bool visit(Mapping&) { return true; } + virtual bool visit(ArrayTypeName&) { return true; } virtual bool visit(Statement&) { return true; } virtual bool visit(Block&) { return true; } virtual bool visit(PlaceholderStatement&) { return true; } @@ -102,6 +103,7 @@ public: virtual void endVisit(ElementaryTypeName&) { } virtual void endVisit(UserDefinedTypeName&) { } virtual void endVisit(Mapping&) { } + virtual void endVisit(ArrayTypeName&) { } virtual void endVisit(Statement&) { } virtual void endVisit(Block&) { } virtual void endVisit(PlaceholderStatement&) { } @@ -149,6 +151,7 @@ public: virtual bool visit(ElementaryTypeName const&) { return true; } virtual bool visit(UserDefinedTypeName const&) { return true; } virtual bool visit(Mapping const&) { return true; } + virtual bool visit(ArrayTypeName const&) { return true; } virtual bool visit(Statement const&) { return true; } virtual bool visit(Block const&) { return true; } virtual bool visit(PlaceholderStatement const&) { return true; } @@ -192,6 +195,7 @@ public: virtual void endVisit(ElementaryTypeName const&) { } virtual void endVisit(UserDefinedTypeName const&) { } virtual void endVisit(Mapping const&) { } + virtual void endVisit(ArrayTypeName const&) { } virtual void endVisit(Statement const&) { } virtual void endVisit(Block const&) { } virtual void endVisit(PlaceholderStatement const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 5bd6993db..61b8280d5 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -327,6 +327,28 @@ void Mapping::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void ArrayTypeName::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_baseType->accept(_visitor); + if (m_length) + m_length->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void ArrayTypeName::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_baseType->accept(_visitor); + if (m_length) + m_length->accept(_visitor); + } + _visitor.endVisit(*this); +} + void Block::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 047bc6d62..c7ce94456 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -36,14 +36,14 @@ const unsigned int CompilerUtils::dataStartOffset = 4; unsigned CompilerUtils::loadFromMemory(unsigned _offset, Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) { - solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically load dynamic type."); + solAssert(_type.getCategory() != Type::Category::Array, "Unable to statically load dynamic type."); m_context << u256(_offset); return loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries); } void CompilerUtils::loadFromMemoryDynamic(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) { - solAssert(_type.getCategory() != Type::Category::ByteArray, "Byte arrays not yet implemented."); + solAssert(_type.getCategory() != Type::Category::Array, "Arrays not yet implemented."); m_context << eth::Instruction::DUP1; unsigned numBytes = loadFromMemoryHelper(_type, _fromCalldata, _padToWordBoundaries); // update memory counter @@ -55,7 +55,7 @@ void CompilerUtils::loadFromMemoryDynamic(Type const& _type, bool _fromCalldata, unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries) { - solAssert(_type.getCategory() != Type::Category::ByteArray, "Unable to statically store dynamic type."); + solAssert(_type.getCategory() != Type::Category::Array, "Unable to statically store dynamic type."); unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); if (numBytes > 0) m_context << u256(_offset) << eth::Instruction::MSTORE; @@ -64,11 +64,12 @@ unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries) { - if (_type.getCategory() == Type::Category::ByteArray) + if (_type.getCategory() == Type::Category::Array) { - auto const& type = dynamic_cast(_type); + auto const& type = dynamic_cast(_type); + solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); - if (type.getLocation() == ByteArrayType::Location::CallData) + if (type.getLocation() == ArrayType::Location::CallData) { // stack: target source_offset source_len m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5 @@ -79,7 +80,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound } else { - solAssert(type.getLocation() == ByteArrayType::Location::Storage, "Memory byte arrays not yet implemented."); + solAssert(type.getLocation() == ArrayType::Location::Storage, "Memory byte arrays not yet implemented."); m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; // stack here: memory_offset storage_offset length_bytes // jump to end if length is zero @@ -163,16 +164,18 @@ void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundari m_context << u256(length) << u256(0) << eth::Instruction::SHA3; } -void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType, - ByteArrayType const& _sourceType) const +void CompilerUtils::copyByteArrayToStorage( + ArrayType const& _targetType, ArrayType const& _sourceType) const { // stack layout: [source_ref] target_ref (top) // need to leave target_ref on the stack at the end - solAssert(_targetType.getLocation() == ByteArrayType::Location::Storage, ""); + solAssert(_targetType.getLocation() == ArrayType::Location::Storage, ""); + solAssert(_targetType.isByteArray(), "Non byte arrays not yet implemented here."); + solAssert(_sourceType.isByteArray(), "Non byte arrays not yet implemented here."); switch (_sourceType.getLocation()) { - case ByteArrayType::Location::CallData: + case ArrayType::Location::CallData: { // This also assumes that after "length" we only have zeros, i.e. it cannot be used to // slice a byte array from calldata. @@ -224,7 +227,7 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType, << eth::Instruction::POP << eth::Instruction::POP; break; } - case ByteArrayType::Location::Storage: + case ArrayType::Location::Storage: { // this copies source to target and also clears target if it was larger @@ -313,9 +316,10 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda return numBytes; } -void CompilerUtils::clearByteArray(ByteArrayType const& _type) const +void CompilerUtils::clearByteArray(ArrayType const& _type) const { - solAssert(_type.getLocation() == ByteArrayType::Location::Storage, ""); + solAssert(_type.getLocation() == ArrayType::Location::Storage, ""); + solAssert(_type.isByteArray(), "Non byte arrays not yet implemented here."); // fetch length m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index 5369d3bf2..2fb97d808 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -82,11 +82,11 @@ public: /// Copies a byte array to a byte array in storage. /// Stack pre: [source_reference] target_reference /// Stack post: target_reference - void copyByteArrayToStorage(ByteArrayType const& _targetType, ByteArrayType const& _sourceType) const; + void copyByteArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const; /// Clears the length and data elements of the byte array referenced on the stack. /// Stack pre: reference /// Stack post: - void clearByteArray(ByteArrayType const& _type) const; + void clearByteArray(ArrayType const& _type) const; /// Bytes we need to the start of call data. /// - The size in bytes of the function (hash) identifier. diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 461dfef14..cdad48407 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -530,20 +530,21 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) m_context << enumType->getMemberValue(_memberAccess.getMemberName()); break; } - case Type::Category::ByteArray: + case Type::Category::Array: { - solAssert(member == "length", "Illegal bytearray member."); - auto const& type = dynamic_cast(*_memberAccess.getExpression().getType()); + solAssert(member == "length", "Illegal array member."); + auto const& type = dynamic_cast(*_memberAccess.getExpression().getType()); + solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); switch (type.getLocation()) { - case ByteArrayType::Location::CallData: + case ArrayType::Location::CallData: m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; break; - case ByteArrayType::Location::Storage: + case ArrayType::Location::Storage: m_context << eth::Instruction::SLOAD; break; default: - solAssert(false, "Unsupported byte array location."); + solAssert(false, "Unsupported array location."); break; } break; @@ -1135,11 +1136,11 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co else { solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "Wrong type conversation for assignment."); - if (m_dataType->getCategory() == Type::Category::ByteArray) + if (m_dataType->getCategory() == Type::Category::Array) { CompilerUtils(*m_context).copyByteArrayToStorage( - dynamic_cast(*m_dataType), - dynamic_cast(_sourceType)); + dynamic_cast(*m_dataType), + dynamic_cast(_sourceType)); if (_move) *m_context << eth::Instruction::POP; } @@ -1210,8 +1211,8 @@ void ExpressionCompiler::LValue::setToZero(Location const& _location) const break; } case LValueType::Storage: - if (m_dataType->getCategory() == Type::Category::ByteArray) - CompilerUtils(*m_context).clearByteArray(dynamic_cast(*m_dataType)); + if (m_dataType->getCategory() == Type::Category::Array) + CompilerUtils(*m_context).clearByteArray(dynamic_cast(*m_dataType)); else if (m_dataType->getCategory() == Type::Category::Struct) { // stack layout: ref diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 889c58b19..31bcc924a 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -39,7 +39,7 @@ namespace solidity { class CompilerContext; class Type; class IntegerType; -class ByteArrayType; +class ArrayType; class StaticStringType; /** @@ -165,7 +165,7 @@ private: /// Convenience function to retrieve Value from Storage. Specific version of @ref retrieveValue void retrieveValueFromStorage(bool _remove = false) const; /// Copies from a byte array to a byte array in storage, both references on the stack. - void copyByteArrayToStorage(ByteArrayType const& _targetType, ByteArrayType const& _sourceType) const; + void copyByteArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const; CompilerContext* m_context; LValueType m_type = LValueType::None; diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 15e1ac6f5..f6ee2f1d0 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -334,10 +334,10 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) if (_variable.getTypeName()) { TypePointer type = _variable.getTypeName()->toType(); - // All byte array parameter types should point to call data + // All 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); + if (auto const* arrayType = dynamic_cast(type.get())) + type = arrayType->copyForLocation(ArrayType::Location::CallData); _variable.setType(type); if (!_variable.getType()) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 9940fb8d9..975061798 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -41,8 +41,11 @@ class Parser::ASTNodeFactory public: ASTNodeFactory(Parser const& _parser): m_parser(_parser), m_location(_parser.getPosition(), -1, _parser.getSourceName()) {} + ASTNodeFactory(Parser const& _parser, ASTPointer const& _childNode): + m_parser(_parser), m_location(_childNode->getLocation()) {} void markEndPosition() { m_location.end = m_parser.getEndPosition(); } + void setLocation(Location const& _location) { m_location = _location; } void setLocationEmpty() { m_location.end = m_location.start; } /// Set the end position to the one of the given node. void setEndPositionFromNode(ASTPointer const& _node) { m_location.end = _node->getLocation().end; } @@ -299,12 +302,20 @@ ASTPointer Parser::parseEnumDefinition() return nodeFactory.createNode(name, members); } -ASTPointer Parser::parseVariableDeclaration(VarDeclParserOptions const& _options) +ASTPointer Parser::parseVariableDeclaration( + VarDeclParserOptions const& _options, ASTPointer const& _lookAheadArrayType) { - ASTNodeFactory nodeFactory(*this); - ASTPointer type = parseTypeName(_options.allowVar); - if (type != nullptr) - nodeFactory.setEndPositionFromNode(type); + ASTNodeFactory nodeFactory = _lookAheadArrayType ? + ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this); + ASTPointer type; + if (_lookAheadArrayType) + type = _lookAheadArrayType; + else + { + type = parseTypeName(_options.allowVar); + if (type != nullptr) + nodeFactory.setEndPositionFromNode(type); + } bool isIndexed = false; ASTPointer identifier; Token::Value token = m_scanner->getCurrentToken(); @@ -407,6 +418,7 @@ ASTPointer Parser::parseIdentifier() ASTPointer Parser::parseTypeName(bool _allowVar) { + ASTNodeFactory nodeFactory(*this); ASTPointer type; Token::Value token = m_scanner->getCurrentToken(); if (Token::isElementaryTypeName(token)) @@ -421,9 +433,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) m_scanner->next(); } else if (token == Token::Mapping) - { type = parseMapping(); - } else if (token == Token::Identifier) { ASTNodeFactory nodeFactory(*this); @@ -432,6 +442,18 @@ ASTPointer Parser::parseTypeName(bool _allowVar) } else BOOST_THROW_EXCEPTION(createParserError("Expected type name")); + + // Parse "[...]" postfixes for arrays. + while (m_scanner->getCurrentToken() == Token::LBrack) + { + m_scanner->next(); + ASTPointer length; + if (m_scanner->getCurrentToken() != Token::RBrack) + length = parseExpression(); + nodeFactory.markEndPosition(); + expectToken(Token::RBrack); + type = nodeFactory.createNode(type, length); + } return type; } @@ -530,7 +552,7 @@ ASTPointer Parser::parseStatement() } // fall-through default: - statement = parseVarDeclOrExprStmt(); + statement = parseSimpleStatement(); } expectToken(Token::Semicolon); return statement; @@ -579,7 +601,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 = parseVarDeclOrExprStmt(); + initExpression = parseSimpleStatement(); expectToken(Token::Semicolon); if (m_scanner->getCurrentToken() != Token::Semicolon) @@ -598,48 +620,88 @@ ASTPointer Parser::parseForStatement() body); } -ASTPointer Parser::parseVarDeclOrExprStmt() +ASTPointer Parser::parseSimpleStatement() { - if (peekVariableDeclarationStatement()) + // These two cases are very hard to distinguish: + // x[7 * 20 + 3] a; - x[7 * 20 + 3] = 9; + // In the first case, x is a type name, in the second it is the name of a variable. + int isVariableDeclaration = peekVariableDeclarationStatement(); + if (isVariableDeclaration == 1) return parseVariableDeclarationStatement(); - else + else if (isVariableDeclaration == -1) return parseExpressionStatement(); + + // At this point, we have '(Identifier|ElementaryTypeName) "["'. + // We parse '(Identifier|ElementaryTypeName) ( "[" Expression "]" )+' and then decide whether to hand this over + // to ExpressionStatement or create a VariableDeclarationStatement out of it. + ASTPointer primary; + if (m_scanner->getCurrentToken() == Token::Identifier) + primary = parseIdentifier(); + else + { + primary = ASTNodeFactory(*this).createNode(m_scanner->getCurrentToken()); + m_scanner->next(); + } + vector, Location>> indices; + solAssert(m_scanner->getCurrentToken() == Token::LBrack, ""); + Location indexLocation = primary->getLocation(); + bool encounteredEmptyBrackets = false; + do + { + expectToken(Token::LBrack); + ASTPointer index; + if (m_scanner->getCurrentToken() == Token::RBrack) + encounteredEmptyBrackets = true; + else + index = parseExpression(); + indexLocation.end = getEndPosition(); + indices.push_back(make_pair(index, indexLocation)); + expectToken(Token::RBrack); + } + while (m_scanner->getCurrentToken() == Token::LBrack); + + if (m_scanner->getCurrentToken() == Token::Identifier || encounteredEmptyBrackets) + return parseVariableDeclarationStatement(typeNameFromArrayIndexStructure(primary, indices)); + else + return parseExpressionStatement(expressionFromArrayIndexStructure(primary, indices)); } -ASTPointer Parser::parseVariableDeclarationStatement() +ASTPointer Parser::parseVariableDeclarationStatement( + ASTPointer const& _lookAheadArrayType) { - ASTNodeFactory nodeFactory(*this); VarDeclParserOptions options; options.allowVar = true; options.allowInitialValue = true; - ASTPointer variable = parseVariableDeclaration(options); + ASTPointer variable = parseVariableDeclaration(options, _lookAheadArrayType); + ASTNodeFactory nodeFactory(*this, variable); return nodeFactory.createNode(variable); } -ASTPointer Parser::parseExpressionStatement() +ASTPointer Parser::parseExpressionStatement( + ASTPointer const& _lookAheadArrayExpression) { - ASTNodeFactory nodeFactory(*this); - ASTPointer expression = parseExpression(); - nodeFactory.setEndPositionFromNode(expression); - return nodeFactory.createNode(expression); + ASTPointer expression = parseExpression(_lookAheadArrayExpression); + return ASTNodeFactory(*this, expression).createNode(expression); } -ASTPointer Parser::parseExpression() +ASTPointer Parser::parseExpression( + ASTPointer const& _lookAheadArrayExpression) { - ASTNodeFactory nodeFactory(*this); - ASTPointer expression = parseBinaryExpression(); + ASTPointer expression = parseBinaryExpression(4, _lookAheadArrayExpression); if (!Token::isAssignmentOp(m_scanner->getCurrentToken())) return expression; Token::Value assignmentOperator = expectAssignmentOperator(); ASTPointer rightHandSide = parseExpression(); + ASTNodeFactory nodeFactory(*this, expression); nodeFactory.setEndPositionFromNode(rightHandSide); return nodeFactory.createNode(expression, assignmentOperator, rightHandSide); } -ASTPointer Parser::parseBinaryExpression(int _minPrecedence) +ASTPointer Parser::parseBinaryExpression(int _minPrecedence, + ASTPointer const& _lookAheadArrayExpression) { - ASTNodeFactory nodeFactory(*this); - ASTPointer expression = parseUnaryExpression(); + ASTPointer expression = parseUnaryExpression(_lookAheadArrayExpression); + ASTNodeFactory nodeFactory(*this, expression); int precedence = Token::precedence(m_scanner->getCurrentToken()); for (; precedence >= _minPrecedence; --precedence) while (Token::precedence(m_scanner->getCurrentToken()) == precedence) @@ -653,11 +715,13 @@ ASTPointer Parser::parseBinaryExpression(int _minPrecedence) return expression; } -ASTPointer Parser::parseUnaryExpression() +ASTPointer Parser::parseUnaryExpression( + ASTPointer const& _lookAheadArrayExpression) { - ASTNodeFactory nodeFactory(*this); + ASTNodeFactory nodeFactory = _lookAheadArrayExpression ? + ASTNodeFactory(*this, _lookAheadArrayExpression) : ASTNodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); - if (Token::isUnaryOp(token) || Token::isCountOp(token)) + if (!_lookAheadArrayExpression && (Token::isUnaryOp(token) || Token::isCountOp(token))) { // prefix expression m_scanner->next(); @@ -668,7 +732,7 @@ ASTPointer Parser::parseUnaryExpression() else { // potential postfix expression - ASTPointer subExpression = parseLeftHandSideExpression(); + ASTPointer subExpression = parseLeftHandSideExpression(_lookAheadArrayExpression); token = m_scanner->getCurrentToken(); if (!Token::isCountOp(token)) return subExpression; @@ -678,11 +742,16 @@ ASTPointer Parser::parseUnaryExpression() } } -ASTPointer Parser::parseLeftHandSideExpression() +ASTPointer Parser::parseLeftHandSideExpression( + ASTPointer const& _lookAheadArrayExpression) { - ASTNodeFactory nodeFactory(*this); + ASTNodeFactory nodeFactory = _lookAheadArrayExpression ? + ASTNodeFactory(*this, _lookAheadArrayExpression) : ASTNodeFactory(*this); + ASTPointer expression; - if (m_scanner->getCurrentToken() == Token::New) + if (_lookAheadArrayExpression) + expression = _lookAheadArrayExpression; + else if (m_scanner->getCurrentToken() == Token::New) { expectToken(Token::New); ASTPointer contractName(parseIdentifier()); @@ -774,10 +843,7 @@ ASTPointer Parser::parsePrimaryExpression() m_scanner->next(); } else - { BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); - return ASTPointer(); // this is not reached - } break; } return expression; @@ -824,18 +890,55 @@ pair>, vector>> Parser::pars return ret; } +int Parser::peekVariableDeclarationStatement() const +{ + // Distinguish between variable declaration (and potentially assignment) and expression statement + // (which include assignments to other expressions and pre-declared variables). + // We have a variable declaration if we get a keyword that specifies a type name. + // If it is an identifier or an elementary type name followed by an identifier, we also have + // a variable declaration. + // If we get an identifier followed by a "[", it can be both ("type[9] a;" or "arr[9] = 7;"). + // In all other cases, we have an expression statement. + Token::Value token(m_scanner->getCurrentToken()); + bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); + if (token == Token::Mapping || token == Token::Var || + (mightBeTypeName && m_scanner->peekNextToken() == Token::Identifier)) + return 1; + if (mightBeTypeName && m_scanner->peekNextToken() == Token::LBrack) + return 0; + return -1; +} -bool Parser::peekVariableDeclarationStatement() +ASTPointer Parser::typeNameFromArrayIndexStructure( + ASTPointer const& _primary, vector, Location>> const& _indices) { - // distinguish between variable declaration (and potentially assignment) and expression statement - // (which include assignments to other expressions and pre-declared variables) - // 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 || - ((Token::isElementaryTypeName(m_scanner->getCurrentToken()) || - m_scanner->getCurrentToken() == Token::Identifier) && - m_scanner->peekNextToken() == Token::Identifier)); + ASTNodeFactory nodeFactory(*this, _primary); + ASTPointer type; + if (auto identifier = dynamic_cast(_primary.get())) + type = nodeFactory.createNode(make_shared(identifier->getName())); + else if (auto typeName = dynamic_cast(_primary.get())) + type = nodeFactory.createNode(typeName->getTypeToken()); + else + solAssert(false, "Invalid type name for array look-ahead."); + for (auto const& lengthExpression: _indices) + { + nodeFactory.setLocation(lengthExpression.second); + type = nodeFactory.createNode(type, lengthExpression.first); + } + return type; +} + +ASTPointer Parser::expressionFromArrayIndexStructure( + ASTPointer const& _primary, vector, Location>> const& _indices) +{ + ASTNodeFactory nodeFactory(*this, _primary); + ASTPointer expression(_primary); + for (auto const& index: _indices) + { + nodeFactory.setLocation(index.second); + expression = nodeFactory.createNode(expression, index.first); + } + return expression; } void Parser::expectToken(Token::Value _value) diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 4034aec85..8726decb8 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -64,7 +64,9 @@ private: ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); ASTPointer parseEnumValue(); - ASTPointer parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); + ASTPointer parseVariableDeclaration( + VarDeclParserOptions const& _options = VarDeclParserOptions(), + ASTPointer const& _lookAheadArrayType = ASTPointer()); ASTPointer parseModifierDefinition(); ASTPointer parseEventDefinition(); ASTPointer parseModifierInvocation(); @@ -77,13 +79,20 @@ private: ASTPointer parseIfStatement(); ASTPointer parseWhileStatement(); ASTPointer parseForStatement(); - ASTPointer parseVarDeclOrExprStmt(); - ASTPointer parseVariableDeclarationStatement(); - ASTPointer parseExpressionStatement(); - ASTPointer parseExpression(); - ASTPointer parseBinaryExpression(int _minPrecedence = 4); - ASTPointer parseUnaryExpression(); - ASTPointer parseLeftHandSideExpression(); + /// A "simple statement" can be a variable declaration statement or an expression statement. + ASTPointer parseSimpleStatement(); + ASTPointer parseVariableDeclarationStatement( + ASTPointer const& _lookAheadArrayType = ASTPointer()); + ASTPointer parseExpressionStatement( + ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer parseExpression( + ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer parseBinaryExpression(int _minPrecedence = 4, + ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer parseUnaryExpression( + ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer parseLeftHandSideExpression( + ASTPointer const& _lookAheadArrayExpression = ASTPointer()); ASTPointer parsePrimaryExpression(); std::vector> parseFunctionCallListArguments(); std::pair>, std::vector>> parseFunctionCallArguments(); @@ -92,9 +101,18 @@ private: ///@{ ///@name Helper functions - /// Peeks ahead in the scanner to determine if a variable declaration statement is going to follow - bool peekVariableDeclarationStatement(); - + /// Performs limited look-ahead to distinguish between variable declaration and expression statement. + /// @returns 1 if it is a variable declaration, -1 if it is an expression statement and 0 if + /// it might be an array-typed variable declaration or an index access to an existing variable. + int peekVariableDeclarationStatement() const; + /// Returns a typename parsed in look-ahead fashion from something like "a[8][2**70]". + ASTPointer typeNameFromArrayIndexStructure( + ASTPointer const& _primary, + std::vector, Location>> const& _indices); + /// Returns an expression parsed in look-ahead fashion from something like "a[8][2**70]". + ASTPointer expressionFromArrayIndexStructure( + ASTPointer const& _primary, + std::vector, Location>> const& _indices); /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); Token::Value expectAssignmentOperator(); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 55dedd921..d0448ef77 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -58,7 +58,7 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) else if (Token::String0 <= _typeToken && _typeToken <= Token::String32) return make_shared(int(_typeToken) - int(Token::String0)); else if (_typeToken == Token::Bytes) - return make_shared(ByteArrayType::Location::Storage); + return make_shared(ArrayType::Location::Storage); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -83,17 +83,35 @@ TypePointer Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) return TypePointer(); } -TypePointer Type::fromMapping(Mapping const& _typeName) +TypePointer Type::fromMapping(ElementaryTypeName& _keyType, TypeName& _valueType) { - TypePointer keyType = _typeName.getKeyType().toType(); + TypePointer keyType = _keyType.toType(); if (!keyType) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Error resolving type name.")); - TypePointer valueType = _typeName.getValueType().toType(); + TypePointer valueType = _valueType.toType(); if (!valueType) - BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name")); + BOOST_THROW_EXCEPTION(_valueType.createTypeError("Invalid type name.")); return make_shared(keyType, valueType); } +TypePointer Type::fromArrayTypeName(TypeName& _baseTypeName, Expression* _length) +{ + TypePointer baseType = _baseTypeName.toType(); + if (!baseType) + BOOST_THROW_EXCEPTION(_baseTypeName.createTypeError("Invalid type name.")); + if (_length) + { + if (!_length->getType()) + _length->checkTypeRequirements(); + auto const* length = dynamic_cast(_length->getType().get()); + if (!length) + BOOST_THROW_EXCEPTION(_length->createTypeError("Invalid array length.")); + return make_shared(ArrayType::Location::Storage, baseType, length->literalValue(nullptr)); + } + else + return make_shared(ArrayType::Location::Storage, baseType); +} + TypePointer Type::forLiteral(Literal const& _literal) { switch (_literal.getToken()) @@ -517,27 +535,27 @@ TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const return _operator == Token::Delete ? make_shared() : TypePointer(); } -bool ByteArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const +bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const { return _convertTo.getCategory() == getCategory(); } -TypePointer ByteArrayType::unaryOperatorResult(Token::Value _operator) const +TypePointer ArrayType::unaryOperatorResult(Token::Value _operator) const { if (_operator == Token::Delete) return make_shared(); return TypePointer(); } -bool ByteArrayType::operator==(Type const& _other) const +bool ArrayType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) return false; - ByteArrayType const& other = dynamic_cast(_other); + ArrayType const& other = dynamic_cast(_other); return other.m_location == m_location; } -unsigned ByteArrayType::getSizeOnStack() const +unsigned ArrayType::getSizeOnStack() const { if (m_location == Location::CallData) // offset, length (stack top) @@ -547,12 +565,30 @@ unsigned ByteArrayType::getSizeOnStack() const return 1; } -shared_ptr ByteArrayType::copyForLocation(ByteArrayType::Location _location) const +string ArrayType::toString() const { - return make_shared(_location); + if (isByteArray()) + return "bytes"; + string ret = getBaseType()->toString() + "["; + if (!isDynamicallySized()) + ret += getLength().str(); + return ret + "]"; +} + +shared_ptr ArrayType::copyForLocation(ArrayType::Location _location) const +{ + auto copy = make_shared(_location); + copy->m_isByteArray = m_isByteArray; + if (m_baseType->getCategory() == Type::Category::Array) + copy->m_baseType = dynamic_cast(*m_baseType).copyForLocation(_location); + else + copy->m_baseType = m_baseType; + copy->m_hasDynamicLength = m_hasDynamicLength; + copy->m_length = m_length; + return copy; } -const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared(256)}}); +const MemberList ArrayType::s_arrayTypeMemberList = MemberList({{"length", make_shared(256)}}); bool ContractType::operator==(Type const& _other) const { @@ -1033,7 +1069,7 @@ MagicType::MagicType(MagicType::Kind _kind): m_members = MemberList({{"sender", make_shared(0, IntegerType::Modifier::Address)}, {"gas", make_shared(256)}, {"value", make_shared(256)}, - {"data", make_shared(ByteArrayType::Location::CallData)}}); + {"data", make_shared(ArrayType::Location::CallData)}}); break; case Kind::Transaction: m_members = MemberList({{"origin", make_shared(0, IntegerType::Modifier::Address)}, diff --git a/libsolidity/Types.h b/libsolidity/Types.h index af64f1cb5..b13f3517e 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -36,8 +36,6 @@ namespace dev namespace solidity { -// @todo realMxN, dynamic strings, text, arrays - class Type; // forward class FunctionType; // forward using TypePointer = std::shared_ptr; @@ -78,7 +76,7 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this(8)) {} + /// Constructor for a dynamically sized array type ("type[]") + ArrayType(Location _location, const TypePointer &_baseType): + m_location(_location), m_baseType(_baseType) {} + /// Constructor for a fixed-size array type ("type[20]") + ArrayType(Location _location, const TypePointer &_baseType, u256 const& _length): + m_location(_location), m_baseType(_baseType), m_hasDynamicLength(false), m_length(_length) {} + virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(const Type& _other) const override; - virtual bool isDynamicallySized() const { return true; } + virtual bool isDynamicallySized() const { return m_hasDynamicLength; } virtual unsigned getSizeOnStack() const override; - virtual std::string toString() const override { return "bytes"; } - virtual MemberList const& getMembers() const override { return s_byteArrayMemberList; } + virtual std::string toString() const override; + virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; } Location getLocation() const { return m_location; } + bool isByteArray() const { return m_isByteArray; } + TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;} + u256 const& getLength() const { return m_length; } /// @returns a copy of this type with location changed to @a _location /// @todo this might move as far up as Type later - std::shared_ptr copyForLocation(Location _location) const; + std::shared_ptr copyForLocation(Location _location) const; private: Location m_location; - static const MemberList s_byteArrayMemberList; + bool m_isByteArray = false; ///< Byte arrays ("bytes") have different semantics from ordinary arrays. + TypePointer m_baseType; + bool m_hasDynamicLength = true; + u256 m_length; + static const MemberList s_arrayTypeMemberList; }; /** diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index da6c2a88a..d7267970a 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1176,6 +1176,15 @@ BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type) BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(sourceCode)); } +BOOST_AUTO_TEST_CASE(array_with_nonconstant_length) +{ + char const* text = R"( + contract c { + function f(uint a) { uint8[a] x; } + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index ddb582447..6c53887a5 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -480,6 +480,7 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion) char const* text = "contract test {\n" " function fun() {\n" " uint64(2);\n" + " uint64[7](3);\n" " }\n" "}\n"; BOOST_CHECK_NO_THROW(parseText(text)); @@ -753,6 +754,45 @@ BOOST_AUTO_TEST_CASE(external_variable) BOOST_CHECK_THROW(parseText(text), ParserError); } +BOOST_AUTO_TEST_CASE(arrays_in_storage) +{ + char const* text = R"( + contract c { + uint[10] a; + uint[] a2; + struct x { uint[2**20] b; y[0] c; } + struct y { uint d; mapping(uint=>x)[] e; } + })"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + +BOOST_AUTO_TEST_CASE(arrays_in_events) +{ + char const* text = R"( + contract c { + event e(uint[10] a, string7[8] indexed b, c[3] x); + })"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + +BOOST_AUTO_TEST_CASE(arrays_in_expressions) +{ + char const* text = R"( + contract c { + function f() { c[10] a = 7; uint8[10 * 2] x; } + })"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + +BOOST_AUTO_TEST_CASE(multi_arrays) +{ + char const* text = R"( + contract c { + mapping(uint => mapping(uint => int8)[8][][9])[] x; + })"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + BOOST_AUTO_TEST_SUITE_END() } From 84555b00c9d716ec4de06b6ff77fcbf6618f03a4 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 21 Feb 2015 00:46:35 +0100 Subject: [PATCH 173/201] Index access. --- libsolidity/AST.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index a18785ae1..4e4fe7d5b 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -609,13 +609,28 @@ void MemberAccess::checkTypeRequirements() void IndexAccess::checkTypeRequirements() { m_base->checkTypeRequirements(); - if (m_base->getType()->getCategory() != Type::Category::Mapping) - BOOST_THROW_EXCEPTION(m_base->createTypeError("Indexed expression has to be a mapping (is " + - m_base->getType()->toString() + ")")); - MappingType const& type = dynamic_cast(*m_base->getType()); - m_index->expectType(*type.getKeyType()); - m_type = type.getValueType(); - m_isLValue = true; + switch (m_base->getType()->getCategory()) + { + case Type::Category::Array: + { + ArrayType const& type = dynamic_cast(*m_base->getType()); + m_index->expectType(IntegerType(256)); + m_type = type.getBaseType(); + m_isLValue = true; + break; + } + case Type::Category::Mapping: + { + MappingType const& type = dynamic_cast(*m_base->getType()); + m_index->expectType(*type.getKeyType()); + m_type = type.getValueType(); + m_isLValue = true; + break; + } + default: + BOOST_THROW_EXCEPTION(m_base->createTypeError( + "Indexed expression has to be a mapping or array (is " + m_base->getType()->toString() + ")")); + } } void Identifier::checkTypeRequirements() From 900f7053246d32efdddd8595645ac4325e4de68d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 20 Feb 2015 18:15:34 +0100 Subject: [PATCH 174/201] 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 175/201] 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 92507f5bf02875776dc646daaee6d2ee56ee3148 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 21 Feb 2015 18:25:08 +0100 Subject: [PATCH 176/201] Allow conversion to dynamic arrays and update grammar. --- libsolidity/AST.cpp | 22 +++++++++++++++++++++- libsolidity/AST.h | 2 +- libsolidity/AST_accept.h | 6 ++++-- libsolidity/ExpressionCompiler.cpp | 3 ++- libsolidity/Parser.cpp | 11 +++++------ libsolidity/grammar.txt | 5 +++-- test/SolidityParser.cpp | 11 +++++++++++ 7 files changed, 47 insertions(+), 13 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 4e4fe7d5b..179461152 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -614,6 +614,8 @@ void IndexAccess::checkTypeRequirements() case Type::Category::Array: { ArrayType const& type = dynamic_cast(*m_base->getType()); + if (!m_index) + BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); m_index->expectType(IntegerType(256)); m_type = type.getBaseType(); m_isLValue = true; @@ -622,14 +624,32 @@ void IndexAccess::checkTypeRequirements() case Type::Category::Mapping: { MappingType const& type = dynamic_cast(*m_base->getType()); + if (!m_index) + BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); m_index->expectType(*type.getKeyType()); m_type = type.getValueType(); m_isLValue = true; break; } + case Type::Category::TypeType: + { + TypeType const& type = dynamic_cast(*m_base->getType()); + if (!m_index) + m_type = make_shared(make_shared(ArrayType::Location::Memory, type.getActualType())); + else + { + m_index->checkTypeRequirements(); + auto length = dynamic_cast(m_index->getType().get()); + if (!length) + BOOST_THROW_EXCEPTION(m_index->createTypeError("Integer constant expected.")); + m_type = make_shared(make_shared( + ArrayType::Location::Memory, type.getActualType(), length->literalValue(nullptr))); + } + break; + } default: BOOST_THROW_EXCEPTION(m_base->createTypeError( - "Indexed expression has to be a mapping or array (is " + m_base->getType()->toString() + ")")); + "Indexed expression has to be a type, mapping or array (is " + m_base->getType()->toString() + ")")); } } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 594f8f4be..07b405c4b 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -1102,7 +1102,7 @@ public: virtual void checkTypeRequirements() override; Expression const& getBaseExpression() const { return *m_base; } - Expression const& getIndexExpression() const { return *m_index; } + Expression const* getIndexExpression() const { return m_index.get(); } private: ASTPointer m_base; diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 61b8280d5..81ede8fc9 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -626,7 +626,8 @@ void IndexAccess::accept(ASTVisitor& _visitor) if (_visitor.visit(*this)) { m_base->accept(_visitor); - m_index->accept(_visitor); + if (m_index) + m_index->accept(_visitor); } _visitor.endVisit(*this); } @@ -636,7 +637,8 @@ void IndexAccess::accept(ASTConstVisitor& _visitor) const if (_visitor.visit(*this)) { m_base->accept(_visitor); - m_index->accept(_visitor); + if (m_index) + m_index->accept(_visitor); } _visitor.endVisit(*this); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index cdad48407..94f65b93f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -562,7 +562,8 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) solAssert(baseType.getCategory() == Type::Category::Mapping, ""); Type const& keyType = *dynamic_cast(baseType).getKeyType(); m_context << u256(0); - appendExpressionCopyToMemory(keyType, _indexAccess.getIndexExpression()); + solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); + appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); solAssert(baseType.getSizeOnStack() == 1, "Unexpected: Not exactly one stack slot taken by subscriptable expression."); m_context << eth::Instruction::SWAP1; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 975061798..def8b9ac4 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -645,14 +645,11 @@ ASTPointer Parser::parseSimpleStatement() vector, Location>> indices; solAssert(m_scanner->getCurrentToken() == Token::LBrack, ""); Location indexLocation = primary->getLocation(); - bool encounteredEmptyBrackets = false; do { expectToken(Token::LBrack); ASTPointer index; - if (m_scanner->getCurrentToken() == Token::RBrack) - encounteredEmptyBrackets = true; - else + if (m_scanner->getCurrentToken() != Token::RBrack) index = parseExpression(); indexLocation.end = getEndPosition(); indices.push_back(make_pair(index, indexLocation)); @@ -660,7 +657,7 @@ ASTPointer Parser::parseSimpleStatement() } while (m_scanner->getCurrentToken() == Token::LBrack); - if (m_scanner->getCurrentToken() == Token::Identifier || encounteredEmptyBrackets) + if (m_scanner->getCurrentToken() == Token::Identifier) return parseVariableDeclarationStatement(typeNameFromArrayIndexStructure(primary, indices)); else return parseExpressionStatement(expressionFromArrayIndexStructure(primary, indices)); @@ -768,7 +765,9 @@ ASTPointer Parser::parseLeftHandSideExpression( case Token::LBrack: { m_scanner->next(); - ASTPointer index = parseExpression(); + ASTPointer index; + if (m_scanner->getCurrentToken() != Token::RBrack) + index = parseExpression(); nodeFactory.markEndPosition(); expectToken(Token::RBrack); expression = nodeFactory.createNode(expression, index); diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index a3b246873..6503516c6 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -18,8 +18,9 @@ ParameterList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')' // semantic restriction: mappings and structs (recursively) containing mappings // are not allowed in argument lists VariableDeclaration = TypeName Identifier -TypeName = ElementaryTypeName | Identifier | Mapping +TypeName = ElementaryTypeName | Identifier | Mapping | ArrayTypeName Mapping = 'mapping' '(' ElementaryTypeName '=>' TypeName ')' +ArrayTypeName = TypeName '[' (Expression)? ']' Block = '{' Statement* '}' Statement = IfStatement | WhileStatement | Block | @@ -42,5 +43,5 @@ Assignment = Expression (AssignmentOp Expression) FunctionCall = Expression '(' Expression ( ',' Expression )* ')' NewExpression = 'new' Identifier MemberAccess = Expression '.' Identifier -IndexAccess = Expression '[' Expresison ']' +IndexAccess = Expression '[' (Expresison)? ']' PrimaryExpression = Identifier | NumberLiteral | StringLiteral | ElementaryTypeName | '(' Expression ')' diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 6c53887a5..b3fcd6484 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -481,6 +481,17 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion) " function fun() {\n" " uint64(2);\n" " uint64[7](3);\n" + " uint64[](3);\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + +BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array) +{ + char const* text = "contract test {\n" + " function fun() {\n" + " var x = uint64[](3);\n" " }\n" "}\n"; BOOST_CHECK_NO_THROW(parseText(text)); From 11566fd3a03e39c3593d48c9f191de4cd95a5b43 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sat, 21 Feb 2015 18:55:55 +0100 Subject: [PATCH 177/201] 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 178/201] 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 179/201] 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 180/201] 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 181/201] 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 182/201] 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 183/201] 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; From 92866a515039af1f986764457743531849435565 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 23 Feb 2015 09:54:10 +0100 Subject: [PATCH 184/201] small changes --- mix/FileIo.cpp | 39 +++++++++++++++--------------------- mix/FileIo.h | 2 +- mix/qml/DeploymentDialog.qml | 15 ++++---------- mix/qml/ProjectModel.qml | 2 +- mix/qml/js/ProjectModel.js | 4 ++-- 5 files changed, 24 insertions(+), 38 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index b368e6a1f..d43c92ceb 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -20,8 +20,6 @@ * Ethereum IDE client. */ -#include -#include #include #include #include @@ -112,7 +110,7 @@ bool FileIo::fileExists(QString const& _url) return file.exists(); } -QStringList FileIo::compress(QString const& _deploymentFolder) +QStringList FileIo::makePackage(QString const& _deploymentFolder) { Json::Value manifest; @@ -124,42 +122,37 @@ QStringList FileIo::compress(QString const& _deploymentFolder) dev::RLPStream str; int k = 1; + QMap files; for (auto item: deployDir.entryInfoList(QDir::Files)) { QFile qFile(item.filePath()); - if (qFile.open(QIODevice::ReadOnly | QIODevice::Text)) - k++; - } - str.appendList(k); - - for (auto item: deployDir.entryInfoList(QDir::Files)) - { - QFile qFile(item.filePath()); - if (qFile.open(QIODevice::ReadOnly | QIODevice::Text)) + if (qFile.open(QIODevice::ReadOnly)) { + k++; QFileInfo i = QFileInfo(qFile.fileName()); - - QByteArray _a = qFile.readAll(); - bytes b = bytes(_a.begin(), _a.end()); - str.append(b); - Json::Value f; - f["path"] = "/"; //TODO: Manage relative sub folder + std::string path = i.fileName() == "index.html" ? "/" : i.fileName().toStdString(); + f["path"] = path; //TODO: Manage relative sub folder f["file"] = "/" + i.fileName().toStdString(); - f["contentType"] = "application/html"; //TODO: manage multiple content type - f["hash"] = toHex(dev::sha3(b).ref()); + f["contentType"] = "text/html"; //TODO: manage multiple content type + QByteArray _a = qFile.readAll(); + files.insert(path, bytesConstRef((const unsigned char*)_a.data(), _a.size())); + f["hash"] = toHex(dev::sha3(files.value(path)).ref()); entries.append(f); } qFile.close(); } - - manifest["entries"] = entries; + str.appendList(k); std::stringstream jsonStr; jsonStr << manifest; QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8(); - str.append(bytes(b.begin(), b.end())); + str.append(bytesConstRef((const unsigned char*)b.data(), b.size())); + + for (auto item: files.keys()) + str.append(files.value(item)); + manifest["entries"] = entries; bytes dapp = str.out(); dev::h256 h = dev::sha3(dapp); //encrypt diff --git a/mix/FileIo.h b/mix/FileIo.h index 2048a37c6..3646627b8 100644 --- a/mix/FileIo.h +++ b/mix/FileIo.h @@ -54,7 +54,7 @@ public: /// Check if file exists Q_INVOKABLE bool fileExists(QString const& _url); /// Compress a folder, @returns sha3 of the compressed file. - Q_INVOKABLE QStringList compress(QString const& _deploymentFolder); + Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder); private: QString getHomePath() const; diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index e72866512..d84a4e8a7 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -110,17 +110,10 @@ Window { anchors.right: parent.right; anchors.bottomMargin: 10 Button { - text: qsTr("Deploy on Ethereum"); - tooltip: qsTr("Deploy the contract and Package ressources files.") + text: qsTr("Deploy to Ethereum"); + tooltip: qsTr("Deploy contract and package resources files.") onClicked: { - if (applicationUrlEth.text === "") - { - deployDialog.title = text; - deployDialog.text = qsTr("Please provide the Ethereum link you want to use for this application.") - deployDialog.open(); - } - else - deployWarningDialog.open(); + deployWarningDialog.open(); } } @@ -131,7 +124,7 @@ Window { if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") { deployDialog.title = text; - deployDialog.text = qsTr("Please provide the link where the ressources are stored and ensure the package is aleary built using the deployment step. ") + deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step. ") deployDialog.open(); } else diff --git a/mix/qml/ProjectModel.qml b/mix/qml/ProjectModel.qml index 02929d39e..19008be5e 100644 --- a/mix/qml/ProjectModel.qml +++ b/mix/qml/ProjectModel.qml @@ -101,7 +101,7 @@ Item { { redeploy = true standardButtons = StandardButton.Ok | StandardButton.Reset | StandardButton.Abort; - return qsTr("This project has been already deployed to the network. Do you want to repackage the ressources only, or also reset the deployed contract to his initial state?") + return qsTr("This project has been already deployed to the network. Do you want to repackage the resources only, or also reset the deployed contract to its initial state?") } else { diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index c2f1a1d4b..f4a3817a7 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -390,7 +390,7 @@ function finalizeDeployment(deploymentId, addresses) { deploymentAddresses = addresses; saveProject(); - var packageRet = fileIo.compress(deploymentDir); + var packageRet = fileIo.makePackage(deploymentDir); deploymentDialog.packageHash = packageRet[0]; deploymentDialog.packageBase64 = packageRet[1]; @@ -531,7 +531,7 @@ function checkRegistration(dappUrl, addr, callBack) function registerToUrlHint() { - deploymentStepChanged(qsTr("Registering application Ressources (" + deploymentDialog.applicationUrlHttp) + ") ..."); + deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ..."); var requests = []; var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); requests.push({ From dacf45a413feb73ab03089779a7620161169aa82 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 23 Feb 2015 11:38:57 +0100 Subject: [PATCH 185/201] small changes --- mix/qml/DeploymentDialog.qml | 36 ++++-------------------------------- mix/qml/js/ProjectModel.js | 2 +- 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/mix/qml/DeploymentDialog.qml b/mix/qml/DeploymentDialog.qml index d84a4e8a7..5033d02b8 100644 --- a/mix/qml/DeploymentDialog.qml +++ b/mix/qml/DeploymentDialog.qml @@ -19,10 +19,9 @@ Window { visible: false property alias applicationUrlEth: applicationUrlEth.text property alias applicationUrlHttp: applicationUrlHttp.text - property string urlHintContract: "29a2e6d3c56ef7713a4e7229c3d1a23406f0161a" + property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" property string packageHash property alias packageBase64: base64Value.text - property string root: "165fd25527c23aa90f8009dad4465bafab5d7dd0"; property string eth: "afb7cdbd076674fd2c67f8a66518e3145b184ae4"; property string wallet: "c83d3e22645fb015d02043a744921cc2f828c64d"; @@ -142,31 +141,24 @@ Window { visible : false onClicked: { var requests = []; - var ethStr = QEtherHelper.createString("eth"); + var ethStr = QEtherHelper.createString("wallet"); var ethHash = QEtherHelper.createHash(eth); requests.push({ //owner jsonrpc: "2.0", method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ], id: 3 }); requests.push({ //register jsonrpc: "2.0", method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], + params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ], id: 4 }); - requests.push({ //register - jsonrpc: "2.0", - method: "eth_call", - params: [ { "to": '0x' + modalDeploymentDialog.wallet, "data": "0x618242da" + ethStr.encodeValueAsString() } ], - id: 4 - }); - var jsonRpcUrl = "http://localhost:8080"; var rpcRequest = JSON.stringify(requests); var httpRequest = new XMLHttpRequest(); @@ -197,28 +189,8 @@ Window { var jsonRpcRequestId = 0; var requests = []; - var ethStr = QEtherHelper.createString("eth"); - var ethHash = QEtherHelper.createHash(eth); - requests.push({ //reserve - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x1c83171b" + ethStr.encodeValueAsString() } ], - id: jsonRpcRequestId++ - }); - - console.log("0x7d2e3ce9" + ethStr.encodeValueAsString() + pad(eth)); - console.log(ethStr.encodeValueAsString()); - console.log(pad(eth)); - - requests.push({ //setRegister - jsonrpc: "2.0", - method: "eth_transact", - params: [ { "to": '0x' + modalDeploymentDialog.root, "data": "0x96077307" + ethStr.encodeValueAsString() + pad(eth) /*ethHash.encodeValueAsString()*/ } ], - id: jsonRpcRequestId++ - }); var walletStr = QEtherHelper.createString("wallet"); - var walletHash = QEtherHelper.createHash(wallet); requests.push({ //reserve jsonrpc: "2.0", diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 27dddcda9..d60dc4124 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -398,7 +398,7 @@ function finalizeDeployment(deploymentId, addresses) { applicationUrlEth = formatAppUrl(applicationUrlEth); deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); - checkRegistration(applicationUrlEth, deploymentDialog.root, function () { + checkRegistration(applicationUrlEth, deploymentDialog.eth, function () { deploymentComplete(); deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment."); deployRessourcesDialog.open(); From 8341940c5993f27eaf5a33afa81f4a2ec47653c9 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 23 Feb 2015 11:41:46 +0100 Subject: [PATCH 186/201] small changes. --- mix/FileIo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index d43c92ceb..9b008b812 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -163,7 +163,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) QUrl url(_deploymentFolder + "package.dapp"); QFile compressed(url.path()); QByteArray qFileBytes((char*)dapp.data(), dapp.size()); - if (compressed.open(QIODevice::WriteOnly | QIODevice::Text)) + if (compressed.open(QIODevice::WriteOnly)) { compressed.write(qFileBytes); compressed.flush(); From e9d31289e2a24e4ced2c42394f380a745a57a414 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 23 Feb 2015 12:21:44 +0100 Subject: [PATCH 187/201] small changes --- mix/FileIo.cpp | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/mix/FileIo.cpp b/mix/FileIo.cpp index 9b008b812..506715767 100644 --- a/mix/FileIo.cpp +++ b/mix/FileIo.cpp @@ -120,43 +120,44 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) QString path(folder.path()); QDir deployDir = QDir(path); - dev::RLPStream str; + dev::RLPStream rlpStr; int k = 1; - QMap files; + std::vector files; for (auto item: deployDir.entryInfoList(QDir::Files)) { QFile qFile(item.filePath()); if (qFile.open(QIODevice::ReadOnly)) { k++; - QFileInfo i = QFileInfo(qFile.fileName()); - Json::Value f; - std::string path = i.fileName() == "index.html" ? "/" : i.fileName().toStdString(); - f["path"] = path; //TODO: Manage relative sub folder - f["file"] = "/" + i.fileName().toStdString(); - f["contentType"] = "text/html"; //TODO: manage multiple content type - QByteArray _a = qFile.readAll(); - files.insert(path, bytesConstRef((const unsigned char*)_a.data(), _a.size())); - f["hash"] = toHex(dev::sha3(files.value(path)).ref()); - entries.append(f); + QFileInfo fileInfo = QFileInfo(qFile.fileName()); + Json::Value jsonValue; + std::string path = fileInfo.fileName() == "index.html" ? "/" : fileInfo.fileName().toStdString(); + jsonValue["path"] = path; //TODO: Manage relative sub folder + jsonValue["file"] = "/" + fileInfo.fileName().toStdString(); + jsonValue["contentType"] = "text/html"; //TODO: manage multiple content type + QByteArray a = qFile.readAll(); + bytes data = bytes(a.begin(), a.end()); + files.push_back(data); + jsonValue["hash"] = toHex(dev::sha3(data).ref()); + entries.append(jsonValue); } qFile.close(); } - str.appendList(k); + rlpStr.appendList(k); std::stringstream jsonStr; jsonStr << manifest; QByteArray b = QString::fromStdString(jsonStr.str()).toUtf8(); - str.append(bytesConstRef((const unsigned char*)b.data(), b.size())); + rlpStr.append(bytesConstRef((const unsigned char*)b.data(), b.size())); - for (auto item: files.keys()) - str.append(files.value(item)); + for (unsigned int k = 0; k < files.size(); k++) + rlpStr.append(files.at(k)); manifest["entries"] = entries; - bytes dapp = str.out(); - dev::h256 h = dev::sha3(dapp); + bytes dapp = rlpStr.out(); + dev::h256 dappHash = dev::sha3(dapp); //encrypt - KeyPair key(h); + KeyPair key(dappHash); Secp256k1 enc; enc.encrypt(key.pub(), dapp); @@ -172,7 +173,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder) error(tr("Error creating package.dapp")); compressed.close(); QStringList ret; - ret.append(QString::fromStdString(toHex(h.ref()))); + ret.append(QString::fromStdString(toHex(dappHash.ref()))); ret.append(qFileBytes.toBase64()); return ret; } From a35dc1e594a2d5656ab0c1b0aac107831917bb2e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 23 Feb 2015 12:26:31 +0100 Subject: [PATCH 188/201] merge --- test/CMakeLists.txt | 15 +- test/ttTransactionTestFiller.json | 295 +++++++++++++++++------------- 2 files changed, 179 insertions(+), 131 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 764bf928e..7ddfdb40d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,11 +4,16 @@ aux_source_directory(. SRC_LIST) list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp") list(REMOVE_ITEM SRC_LIST "./checkRandomTest.cpp") +if (NOT JSONRPC) + list(REMOVE_ITEM SRC_LIST "./AccountHolder.cpp") +endif() + +include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) +include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) -include_directories(${JSONCPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -include_directories(..) + file(GLOB HEADERS "*.h") add_executable(testeth ${SRC_LIST} ${HEADERS}) @@ -21,8 +26,10 @@ target_link_libraries(testeth ethereum) target_link_libraries(testeth ethcore) target_link_libraries(testeth secp256k1) target_link_libraries(testeth solidity) -target_link_libraries(testeth webthree) - +if (NOT HEADLESS) + target_link_libraries(testeth webthree) + target_link_libraries(testeth natspec) +endif() if (JSONRPC) target_link_libraries(testeth web3jsonrpc) target_link_libraries(testeth ${JSON_RPC_CPP_CLIENT_LIBRARIES}) diff --git a/test/ttTransactionTestFiller.json b/test/ttTransactionTestFiller.json index 3c39b9da5..c54da4db6 100644 --- a/test/ttTransactionTestFiller.json +++ b/test/ttTransactionTestFiller.json @@ -1,290 +1,331 @@ { "RightVRSTest" : { "transaction" : - { + { "data" : "0x5544", "gasLimit" : "2000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", "value" : "10", - "v" : "28", - "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", - "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" - + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" } }, "WrongVRSTestVl27" : { "transaction" : - { + { "data" : "", "gasLimit" : "2000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", "value" : "10", - "v" : "26", - "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", - "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + "v" : "26", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" } }, "WrongVRSTestVge31" : { "transaction" : - { + { "data" : "", "gasLimit" : "2000", "gasPrice" : "1", "nonce" : "0", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", "value" : "10", - "v" : "31", - "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", - "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + "v" : "31", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" } }, - "SenderTest" : { - "//" : "sender a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "WrongVRSTestIncorrectSize" : { "transaction" : - { + { + "data" : "", + "gasLimit" : "2000", + "gasPrice" : "1", + "nonce" : "0", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10", + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a02c3", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a302c3" + } + }, + + "SenderTest" : { + "//" : "sender a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "transaction" : + { "data" : "", "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "10", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "secretkey 45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "secretkey 45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "TransactionWithTooManyRLPElements" : { + "TransactionWithTooManyRLPElements" : { "transaction" : - { + { "data" : "", "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "10", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", - "extrafield" : "128472387293" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804", + "extrafield" : "128472387293" } }, - "TransactionWithTooFewRLPElements" : { + "TransactionWithTooFewRLPElements" : { "transaction" : - { + { "data" : "", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "TransactionWithHihghValue" : { + "TransactionWithHihghValue" : { "transaction" : - { + { "data" : "", "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "TransactionWithHihghValueOverflow" : { + "TransactionWithHihghValueOverflow" : { "transaction" : - { + { "data" : "", "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "115792089237316195423570985008687907853269984665640564039457584007913129639936", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, "TransactionWithSvalueOverflow" : { "transaction" : - { + { "data" : "", "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "11", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f" } }, - "TransactionWithRvalueOverflow" : { + "TransactionWithRvalueOverflow" : { "transaction" : - { + { "data" : "", "gasLimit" : "850", "gasPrice" : "1", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "11", - "v" : "27", - "r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "TransactionWithNonceOverflow" : { + "TransactionWithNonceOverflow" : { "transaction" : - { + { "data" : "", "gasLimit" : "850", "gasPrice" : "1", "nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639936", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "11", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, -"TransactionWithGasPriceOverflow" : { + "TransactionWithGasPriceOverflow" : { "transaction" : - { + { "data" : "", "gasLimit" : "850", "gasPrice" : "115792089237316195423570985008687907853269984665640564039457584007913129639936", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "11", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "TransactionWithGasLimitOverflow" : { + "TransactionWithGasLimitOverflow" : { "transaction" : - { + { "data" : "", "gasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639936", "gasPrice" : "123", "nonce" : "0", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "11", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" - } - }, - - "RLPElementsWithZeros" : { - "transaction" : - { - "data" : "0x0000011222333", - "gasLimit" : "1000", - "gasPrice" : "00123", - "nonce" : "0054", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "00000011", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "RLPWrongHexElements" : { + "AddressMoreThan20PrefixedBy0" : { "transaction" : - { - "data" : "0x0000000012", + { + "data" : "0x12", "gasLimit" : "1000", "gasPrice" : "123", "nonce" : "54", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "to" : "0x0000000000000000095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "11", - "v" : "27", - "r" : "0x0048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0x00efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "EmptyTransaction" : { + "EmptyTransaction" : { "transaction" : - { - "data" : "", + { + "data" : "", "gasLimit" : "", "gasPrice" : "", "nonce" : "", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + "v" : "27", + "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", + "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" } }, - "AddressMore20" : { + "AddressMoreThan20" : { "transaction" : - { - "data" : "", - "gasLimit" : "", - "gasPrice" : "", - "nonce" : "", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d871f", - "value" : "", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + { + "data" : "", + "gasLimit" : "2000", + "gasPrice" : "1", + "nonce" : "0", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b1c", + "value" : "10", + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" } }, - "AddressLess20" : { + "AddressLessThan20" : { "transaction" : - { - "data" : "", - "gasLimit" : "", - "gasPrice" : "", - "nonce" : "", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d", - "value" : "", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + { + "data" : "", + "gasLimit" : "2000", + "gasPrice" : "1", + "nonce" : "0", + "to" : "b9331677e6ebf", + "value" : "10", + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" } }, - "AddressMore20WithFirstZeros" : { + "AddressLessThan20Prefixed0" : { "transaction" : - { - "data" : "", - "gasLimit" : "", - "gasPrice" : "", - "nonce" : "", - "to" : "0x00000000000000000000000095e7baea6a6c7c4c2dfeb977efac326af552d", - "value" : "", - "v" : "27", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" + { + "data" : "", + "gasLimit" : "2000", + "gasPrice" : "1", + "nonce" : "0", + "to" : "0x000000000000000000000000000b9331677e6ebf", + "value" : "10", + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" } - } + }, + "ValuesAsHex" : { + "transaction" : + { + "data" : "", + "gasLimit" : "0xadc053", + "gasPrice" : "1", + "nonce" : "0xffdc5", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "4294820140", + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + } + }, + + "ValuesAsDec" : { + "transaction" : + { + "data" : "", + "gasLimit" : "11386963", + "gasPrice" : "1", + "nonce" : "1048005", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "4501151495864620", + "v" : "28", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + } + }, + "unpadedRValue": { + "transaction": { + "nonce": "13", + "gasPrice": "0x09184e72a000", + "gasLimit": "0x2710", + "to": "7c47ef93268a311f4cad0c750724299e9b72c268", + "data": "0x379607f50000000000000000000000000000000000000000000000000000000000000005", + "r": "0x006ab6dda9f4df56ea45583af36660329147f1753f3724ea5eb9ed83e812ca77", + "s": "0x495701e230667832c8999e884e366a61028633ecf951e8cd66d119f381ae5718", + "v": "28", + "value": "" + } + } } From 1d518d66f2833e6e7dba9ae08a369f24c6d3cc35 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 23 Feb 2015 14:38:44 +0100 Subject: [PATCH 189/201] Renames and comments. --- libsolidity/Parser.cpp | 56 ++++++++++++++++++++++-------------------- libsolidity/Parser.h | 26 ++++++++++++-------- libsolidity/Types.h | 3 ++- 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index def8b9ac4..221d8a12a 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -625,11 +625,13 @@ ASTPointer Parser::parseSimpleStatement() // These two cases are very hard to distinguish: // x[7 * 20 + 3] a; - x[7 * 20 + 3] = 9; // In the first case, x is a type name, in the second it is the name of a variable. - int isVariableDeclaration = peekVariableDeclarationStatement(); - if (isVariableDeclaration == 1) + switch (peekStatementType()) + { + case LookAheadInfo::VariableDeclarationStatement: return parseVariableDeclarationStatement(); - else if (isVariableDeclaration == -1) + case LookAheadInfo::ExpressionStatement: return parseExpressionStatement(); + } // At this point, we have '(Identifier|ElementaryTypeName) "["'. // We parse '(Identifier|ElementaryTypeName) ( "[" Expression "]" )+' and then decide whether to hand this over @@ -658,9 +660,9 @@ ASTPointer Parser::parseSimpleStatement() while (m_scanner->getCurrentToken() == Token::LBrack); if (m_scanner->getCurrentToken() == Token::Identifier) - return parseVariableDeclarationStatement(typeNameFromArrayIndexStructure(primary, indices)); + return parseVariableDeclarationStatement(typeNameIndexAccessStructure(primary, indices)); else - return parseExpressionStatement(expressionFromArrayIndexStructure(primary, indices)); + return parseExpressionStatement(expressionFromIndexAccessStructure(primary, indices)); } ASTPointer Parser::parseVariableDeclarationStatement( @@ -675,16 +677,16 @@ ASTPointer Parser::parseVariableDeclarationStateme } ASTPointer Parser::parseExpressionStatement( - ASTPointer const& _lookAheadArrayExpression) + ASTPointer const& _lookAheadIndexAccessStructure) { - ASTPointer expression = parseExpression(_lookAheadArrayExpression); + ASTPointer expression = parseExpression(_lookAheadIndexAccessStructure); return ASTNodeFactory(*this, expression).createNode(expression); } ASTPointer Parser::parseExpression( - ASTPointer const& _lookAheadArrayExpression) + ASTPointer const& _lookAheadIndexAccessStructure) { - ASTPointer expression = parseBinaryExpression(4, _lookAheadArrayExpression); + ASTPointer expression = parseBinaryExpression(4, _lookAheadIndexAccessStructure); if (!Token::isAssignmentOp(m_scanner->getCurrentToken())) return expression; Token::Value assignmentOperator = expectAssignmentOperator(); @@ -695,9 +697,9 @@ ASTPointer Parser::parseExpression( } ASTPointer Parser::parseBinaryExpression(int _minPrecedence, - ASTPointer const& _lookAheadArrayExpression) + ASTPointer const& _lookAheadIndexAccessStructure) { - ASTPointer expression = parseUnaryExpression(_lookAheadArrayExpression); + ASTPointer expression = parseUnaryExpression(_lookAheadIndexAccessStructure); ASTNodeFactory nodeFactory(*this, expression); int precedence = Token::precedence(m_scanner->getCurrentToken()); for (; precedence >= _minPrecedence; --precedence) @@ -713,12 +715,12 @@ ASTPointer Parser::parseBinaryExpression(int _minPrecedence, } ASTPointer Parser::parseUnaryExpression( - ASTPointer const& _lookAheadArrayExpression) + ASTPointer const& _lookAheadIndexAccessStructure) { - ASTNodeFactory nodeFactory = _lookAheadArrayExpression ? - ASTNodeFactory(*this, _lookAheadArrayExpression) : ASTNodeFactory(*this); + ASTNodeFactory nodeFactory = _lookAheadIndexAccessStructure ? + ASTNodeFactory(*this, _lookAheadIndexAccessStructure) : ASTNodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); - if (!_lookAheadArrayExpression && (Token::isUnaryOp(token) || Token::isCountOp(token))) + if (!_lookAheadIndexAccessStructure && (Token::isUnaryOp(token) || Token::isCountOp(token))) { // prefix expression m_scanner->next(); @@ -729,7 +731,7 @@ ASTPointer Parser::parseUnaryExpression( else { // potential postfix expression - ASTPointer subExpression = parseLeftHandSideExpression(_lookAheadArrayExpression); + ASTPointer subExpression = parseLeftHandSideExpression(_lookAheadIndexAccessStructure); token = m_scanner->getCurrentToken(); if (!Token::isCountOp(token)) return subExpression; @@ -740,14 +742,14 @@ ASTPointer Parser::parseUnaryExpression( } ASTPointer Parser::parseLeftHandSideExpression( - ASTPointer const& _lookAheadArrayExpression) + ASTPointer const& _lookAheadIndexAccessStructure) { - ASTNodeFactory nodeFactory = _lookAheadArrayExpression ? - ASTNodeFactory(*this, _lookAheadArrayExpression) : ASTNodeFactory(*this); + ASTNodeFactory nodeFactory = _lookAheadIndexAccessStructure ? + ASTNodeFactory(*this, _lookAheadIndexAccessStructure) : ASTNodeFactory(*this); ASTPointer expression; - if (_lookAheadArrayExpression) - expression = _lookAheadArrayExpression; + if (_lookAheadIndexAccessStructure) + expression = _lookAheadIndexAccessStructure; else if (m_scanner->getCurrentToken() == Token::New) { expectToken(Token::New); @@ -889,7 +891,7 @@ pair>, vector>> Parser::pars return ret; } -int Parser::peekVariableDeclarationStatement() const +Parser::LookAheadInfo Parser::peekStatementType() const { // Distinguish between variable declaration (and potentially assignment) and expression statement // (which include assignments to other expressions and pre-declared variables). @@ -902,13 +904,13 @@ int Parser::peekVariableDeclarationStatement() const bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); if (token == Token::Mapping || token == Token::Var || (mightBeTypeName && m_scanner->peekNextToken() == Token::Identifier)) - return 1; + return LookAheadInfo::VariableDeclarationStatement; if (mightBeTypeName && m_scanner->peekNextToken() == Token::LBrack) - return 0; - return -1; + return LookAheadInfo::IndexAccessStructure; + return LookAheadInfo::ExpressionStatement; } -ASTPointer Parser::typeNameFromArrayIndexStructure( +ASTPointer Parser::typeNameIndexAccessStructure( ASTPointer const& _primary, vector, Location>> const& _indices) { ASTNodeFactory nodeFactory(*this, _primary); @@ -927,7 +929,7 @@ ASTPointer Parser::typeNameFromArrayIndexStructure( return type; } -ASTPointer Parser::expressionFromArrayIndexStructure( +ASTPointer Parser::expressionFromIndexAccessStructure( ASTPointer const& _primary, vector, Location>> const& _indices) { ASTNodeFactory nodeFactory(*this, _primary); diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 8726decb8..b6a7851ec 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -84,15 +84,15 @@ private: ASTPointer parseVariableDeclarationStatement( ASTPointer const& _lookAheadArrayType = ASTPointer()); ASTPointer parseExpressionStatement( - ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer const& _lookAheadIndexAccessStructure = ASTPointer()); ASTPointer parseExpression( - ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer const& _lookAheadIndexAccessStructure = ASTPointer()); ASTPointer parseBinaryExpression(int _minPrecedence = 4, - ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer const& _lookAheadIndexAccessStructure = ASTPointer()); ASTPointer parseUnaryExpression( - ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer const& _lookAheadIndexAccessStructure = ASTPointer()); ASTPointer parseLeftHandSideExpression( - ASTPointer const& _lookAheadArrayExpression = ASTPointer()); + ASTPointer const& _lookAheadIndexAccessStructure = ASTPointer()); ASTPointer parsePrimaryExpression(); std::vector> parseFunctionCallListArguments(); std::pair>, std::vector>> parseFunctionCallArguments(); @@ -101,16 +101,22 @@ private: ///@{ ///@name Helper functions + /// Used as return value of @see peekStatementType. + enum class LookAheadInfo + { + IndexAccessStructure, VariableDeclarationStatement, ExpressionStatement + }; + /// Performs limited look-ahead to distinguish between variable declaration and expression statement. - /// @returns 1 if it is a variable declaration, -1 if it is an expression statement and 0 if - /// it might be an array-typed variable declaration or an index access to an existing variable. - int peekVariableDeclarationStatement() const; + /// For source code of the form "a[][8]" ("IndexAccessStructure"), this it is not possible to + /// decide with constant look-ahead. + LookAheadInfo peekStatementType() const; /// Returns a typename parsed in look-ahead fashion from something like "a[8][2**70]". - ASTPointer typeNameFromArrayIndexStructure( + ASTPointer typeNameIndexAccessStructure( ASTPointer const& _primary, std::vector, Location>> const& _indices); /// Returns an expression parsed in look-ahead fashion from something like "a[8][2**70]". - ASTPointer expressionFromArrayIndexStructure( + ASTPointer expressionFromIndexAccessStructure( ASTPointer const& _primary, std::vector, Location>> const& _indices); /// If current token value is not _value, throw exception otherwise advance token. diff --git a/libsolidity/Types.h b/libsolidity/Types.h index b13f3517e..7e02f878d 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -279,7 +279,8 @@ public: }; /** - * The type of a byte array, prototype for a general array. + * The type of an array, the flavours are byte array (bytes), statically- ([]) + * and dynamically-sized array ([]). */ class ArrayType: public Type { From 14bcb21373d1d13a3f07b7c9a4bef139784f7834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 23 Feb 2015 14:43:03 +0100 Subject: [PATCH 190/201] Fixing EVMJIT build on Mac OS --- evmjit/libevmjit/ExecStats.h | 1 + evmjit/libevmjit/preprocessor/llvm_includes_end.h | 2 ++ evmjit/libevmjit/preprocessor/llvm_includes_start.h | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/evmjit/libevmjit/ExecStats.h b/evmjit/libevmjit/ExecStats.h index 498e21341..1ac9b6995 100644 --- a/evmjit/libevmjit/ExecStats.h +++ b/evmjit/libevmjit/ExecStats.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "ExecutionEngine.h" diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_end.h b/evmjit/libevmjit/preprocessor/llvm_includes_end.h index 023c8021e..2ead6dda3 100644 --- a/evmjit/libevmjit/preprocessor/llvm_includes_end.h +++ b/evmjit/libevmjit/preprocessor/llvm_includes_end.h @@ -1,5 +1,7 @@ #if defined(_MSC_VER) #pragma warning(pop) +#elif defined(__clang__) + #pragma clang diagnostic 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 index bf34ade99..699db91f2 100644 --- a/evmjit/libevmjit/preprocessor/llvm_includes_start.h +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -1,6 +1,10 @@ #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable: 4267 4244 4800) +#elif defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunused-parameter + #pragma clang diagnostic ignored "-Wconversion" #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" From ccc1d974d1b4827dccce3216dc8fc2ab05aef12e Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 23 Feb 2015 14:55:06 +0100 Subject: [PATCH 191/201] Comments and warnings. --- libsolidity/Parser.cpp | 2 ++ libsolidity/Parser.h | 2 +- libsolidity/Types.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 221d8a12a..9043d7fcf 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -631,6 +631,8 @@ ASTPointer Parser::parseSimpleStatement() return parseVariableDeclarationStatement(); case LookAheadInfo::ExpressionStatement: return parseExpressionStatement(); + default: + break; } // At this point, we have '(Identifier|ElementaryTypeName) "["'. diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index b6a7851ec..9e4c7bb24 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -108,7 +108,7 @@ private: }; /// Performs limited look-ahead to distinguish between variable declaration and expression statement. - /// For source code of the form "a[][8]" ("IndexAccessStructure"), this it is not possible to + /// For source code of the form "a[][8]" ("IndexAccessStructure"), this is not possible to /// decide with constant look-ahead. LookAheadInfo peekStatementType() const; /// Returns a typename parsed in look-ahead fashion from something like "a[8][2**70]". diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 7e02f878d..0d24b7221 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -279,7 +279,7 @@ public: }; /** - * The type of an array, the flavours are byte array (bytes), statically- ([]) + * The type of an array. The flavours are byte array (bytes), statically- ([]) * and dynamically-sized array ([]). */ class ArrayType: public Type From e41384dcf33d3b8bf3f2b86f39704efe4c9794c8 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 23 Feb 2015 15:12:23 +0100 Subject: [PATCH 192/201] remove tests with impossible pre conditions --- test/stSolidityTestFiller.json | 50 ++++++++++++++++----- test/stTransactionTestFiller.json | 72 ------------------------------- 2 files changed, 40 insertions(+), 82 deletions(-) diff --git a/test/stSolidityTestFiller.json b/test/stSolidityTestFiller.json index 973c52a8d..17c40ed26 100644 --- a/test/stSolidityTestFiller.json +++ b/test/stSolidityTestFiller.json @@ -264,7 +264,7 @@ }, "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100000", "//": "contract subcaller ", "//": "{ ", @@ -294,6 +294,12 @@ "nonce" : "0", "storage" : { } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "nonce" : "0", + "code" : "", + "storage": {} } }, "transaction" : @@ -304,7 +310,7 @@ "gasPrice" : "1", "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "1" } }, @@ -320,7 +326,7 @@ }, "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100000", "//" : "contract recursiveMethods ", "//" : "{ ", @@ -343,6 +349,12 @@ "nonce" : "0", "storage" : { } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "100000", + "nonce" : "0", + "code" : "", + "storage": {} } }, "transaction" : @@ -353,7 +365,7 @@ "gasPrice" : "1", "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "1" } }, @@ -369,7 +381,7 @@ }, "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100000", "//" : "contract recursiveMethods ", "//" : "{ ", @@ -392,6 +404,12 @@ "nonce" : "0", "storage" : { } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "500", + "nonce" : "0", + "code" : "", + "storage": {} } }, "transaction" : @@ -402,7 +420,7 @@ "gasPrice" : "1", "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "1" } }, @@ -418,7 +436,7 @@ }, "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "1000000", "//" : "contract recursiveCreate1 ", "//" : "{ ", @@ -461,6 +479,12 @@ "nonce" : "0", "storage" : { } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "500000", + "nonce" : "0", + "code" : "", + "storage": {} } }, "transaction" : @@ -471,7 +495,7 @@ "gasPrice" : "1", "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "1" } }, @@ -487,12 +511,18 @@ }, "pre" : { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "100000", "code" : "0x60003560e060020a90048063c040622614601557005b601b6021565b60006000f35b61014f60008190555056", "nonce" : "0", "storage" : { } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "500", + "nonce" : "0", + "code" : "", + "storage": {} } }, "transaction" : @@ -503,7 +533,7 @@ "gasPrice" : "1", "nonce" : "0", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "1" } } diff --git a/test/stTransactionTestFiller.json b/test/stTransactionTestFiller.json index 73026608d..37b752f86 100644 --- a/test/stTransactionTestFiller.json +++ b/test/stTransactionTestFiller.json @@ -842,78 +842,6 @@ } }, - "TransactionMakeAccountBalanceOverflow" : { - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "45678256", - "currentGasLimit" : "1000000", - "currentNumber" : "0", - "currentTimestamp" : 1, - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "pre" : - { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "100000", - "code" : "", - "nonce" : "0", - "storage" : { - } - }, - - "b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "code" : "", - "nonce" : "0", - "storage" : { - } - } - }, - "transaction" : - { - "data" : "", - "gasLimit" : "1000", - "gasPrice" : "1", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "value" : "100" - } - }, - - "TransactionMakeAccountNonceOverflow" : { - "env" : { - "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "currentDifficulty" : "1", - "currentGasLimit" : "1000000", - "currentNumber" : "0", - "currentTimestamp" : 1, - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "pre" : - { - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "100000", - "code" : "", - "nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "nonce" : "10000", - "storage" : { - } - } - }, - "transaction" : - { - "data" : "", - "gasLimit" : "1000", - "gasPrice" : "1", - "nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "nonce" : "10000", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "value" : "100" - } - }, - "UserTransactionZeroCost" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", From ba27591cd5268d5e34e565f1391c26f337123534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 23 Feb 2015 15:31:59 +0100 Subject: [PATCH 193/201] Typo fix --- evmjit/libevmjit/preprocessor/llvm_includes_start.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evmjit/libevmjit/preprocessor/llvm_includes_start.h b/evmjit/libevmjit/preprocessor/llvm_includes_start.h index 699db91f2..9077bf43f 100644 --- a/evmjit/libevmjit/preprocessor/llvm_includes_start.h +++ b/evmjit/libevmjit/preprocessor/llvm_includes_start.h @@ -3,7 +3,7 @@ #pragma warning(disable: 4267 4244 4800) #elif defined(__clang__) #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wunused-parameter + #pragma clang diagnostic ignored "-Wunused-parameter" #pragma clang diagnostic ignored "-Wconversion" #else #pragma GCC diagnostic push From d8784ed362a1d72b34abcbfa6db869eec592f694 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 23 Feb 2015 15:52:48 +0100 Subject: [PATCH 194/201] Avoid too many wornings about slots/signals. --- alethzero/MainWin.cpp | 13 ++++--------- alethzero/MainWin.h | 10 ++++++---- alethzero/Transact.cpp | 4 ++-- alethzero/Transact.h | 12 ++++++------ 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index c40e8f6a0..39bc0ad43 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1458,7 +1458,7 @@ void Main::on_debugCurrent_triggered() } } -void Main::on_debugDumpState_triggered(int _add) +void Main::debugDumpState(int _add) { if (auto item = ui->blocks->currentItem()) { @@ -1479,11 +1479,6 @@ void Main::on_debugDumpState_triggered(int _add) } } -void Main::on_debugDumpStatePre_triggered() -{ - on_debugDumpState_triggered(0); -} - void Main::on_contracts_currentItemChanged() { ui->contractInfo->clear(); @@ -1511,7 +1506,7 @@ void Main::on_contracts_currentItemChanged() } } -void Main::on_idealPeers_valueChanged() +void Main::on_idealPeers_valueChanged(int) { m_webThree->setIdealPeerCount(ui->idealPeers->value()); } @@ -1523,11 +1518,11 @@ void Main::on_ourAccounts_doubleClicked() qApp->clipboard()->setText(QString::fromStdString(toHex(h.asArray()))); } -void Main::on_log_doubleClicked() +/*void Main::on_log_doubleClicked() { ui->log->setPlainText(""); m_logHistory.clear(); -} +}*/ void Main::on_accounts_doubleClicked() { diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 52b98d293..638469fbe 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -109,7 +109,7 @@ private slots: void on_go_triggered(); void on_net_triggered(); void on_connect_triggered(); - void on_idealPeers_valueChanged(); + void on_idealPeers_valueChanged(int); // Mining void on_mine_triggered(); @@ -142,7 +142,7 @@ private slots: void on_blocks_currentItemChanged(); // Logging - void on_log_doubleClicked(); +// void on_log_doubleClicked(); void on_verbosity_valueChanged(); // Misc @@ -162,8 +162,8 @@ private slots: // Debugger void on_debugCurrent_triggered(); - void on_debugDumpState_triggered(int _add = 1); - void on_debugDumpStatePre_triggered(); + void on_debugDumpState_triggered() { debugDumpState(1); } + void on_debugDumpStatePre_triggered() { debugDumpState(0); } // Whisper void on_newIdentity_triggered(); @@ -177,6 +177,8 @@ signals: void poll(); private: + void debugDumpState(int _add); + dev::p2p::NetworkPreferences netPrefs() const; QString lookup(QString const& _n) const; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index 1b9a62a2d..c59c80c39 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -55,7 +55,7 @@ Transact::Transact(Context* _c, QWidget* _parent): ui->valueUnits->setCurrentIndex(6); ui->gasPriceUnits->setCurrentIndex(4); ui->gasPrice->setValue(10); - on_destination_currentTextChanged(); + on_destination_currentTextChanged(QString()); } Transact::~Transact() @@ -147,7 +147,7 @@ string Transact::getFunctionHashes(dev::solidity::CompilerStack const& _compiler return ret; } -void Transact::on_destination_currentTextChanged() +void Transact::on_destination_currentTextChanged(QString) { if (ui->destination->currentText().size() && ui->destination->currentText() != "(Create Contract)") if (Address a = m_context->fromString(ui->destination->currentText())) diff --git a/alethzero/Transact.h b/alethzero/Transact.h index afb45f62d..f14005eff 100644 --- a/alethzero/Transact.h +++ b/alethzero/Transact.h @@ -44,12 +44,12 @@ public: void setEnvironment(QList _myKeys, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); private slots: - void on_destination_currentTextChanged(); - void on_value_valueChanged() { updateFee(); } - void on_gas_valueChanged() { updateFee(); } - void on_valueUnits_currentIndexChanged() { updateFee(); } - void on_gasPriceUnits_currentIndexChanged() { updateFee(); } - void on_gasPrice_valueChanged() { updateFee(); } + void on_destination_currentTextChanged(QString); + void on_value_valueChanged(int) { updateFee(); } + void on_gas_valueChanged(int) { updateFee(); } + void on_valueUnits_currentIndexChanged(int) { updateFee(); } + void on_gasPriceUnits_currentIndexChanged(int) { updateFee(); } + void on_gasPrice_valueChanged(int) { updateFee(); } void on_data_textChanged() { rejigData(); } void on_optimize_clicked() { rejigData(); } void on_send_clicked(); From 20c581c4f864b1c09eddb6a1dfdc199d68cbab6a Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 23 Feb 2015 16:28:18 +0100 Subject: [PATCH 195/201] Activate standard sources by default. --- libsolidity/CompilerStack.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsolidity/CompilerStack.h b/libsolidity/CompilerStack.h index 8f77ef68a..812f41863 100644 --- a/libsolidity/CompilerStack.h +++ b/libsolidity/CompilerStack.h @@ -60,7 +60,7 @@ class CompilerStack: boost::noncopyable { public: /// Creates a new compiler stack. Adds standard sources if @a _addStandardSources. - explicit CompilerStack(bool _addStandardSources = false); + explicit CompilerStack(bool _addStandardSources = true); /// 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. From d1d9b2856ab79ba094e65c3a72741211b6d855c9 Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 22 Feb 2015 19:15:41 +0100 Subject: [PATCH 196/201] Implementation of index access. --- libsolidity/CompilerContext.cpp | 7 ++- libsolidity/ExpressionCompiler.cpp | 74 ++++++++++++++++++++---------- libsolidity/Types.cpp | 19 +++++++- libsolidity/Types.h | 1 + test/SolidityEndToEndTest.cpp | 27 +++++++++++ 5 files changed, 101 insertions(+), 27 deletions(-) diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 01a71d7c9..8d32a1a53 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -40,7 +40,12 @@ void CompilerContext::addMagicGlobal(MagicVariableDeclaration const& _declaratio void CompilerContext::addStateVariable(VariableDeclaration const& _declaration) { m_stateVariables[&_declaration] = m_stateVariablesSize; - m_stateVariablesSize += _declaration.getType()->getStorageSize(); + bigint newSize = bigint(m_stateVariablesSize) + _declaration.getType()->getStorageSize(); + if (newSize >= bigint(1) << 256) + BOOST_THROW_EXCEPTION(TypeError() + << errinfo_comment("State variable does not fit in storage.") + << errinfo_sourceLocation(_declaration.getLocation())); + m_stateVariablesSize = u256(newSize); } void CompilerContext::startFunction(Declaration const& _function) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 94f65b93f..dcd411c3e 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -534,19 +534,24 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) { solAssert(member == "length", "Illegal array member."); auto const& type = dynamic_cast(*_memberAccess.getExpression().getType()); - solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); - switch (type.getLocation()) + if (!type.isDynamicallySized()) { - case ArrayType::Location::CallData: - m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; - break; - case ArrayType::Location::Storage: - m_context << eth::Instruction::SLOAD; - break; - default: - solAssert(false, "Unsupported array location."); - break; + CompilerUtils(m_context).popStackElement(type); + m_context << type.getLength(); } + else + switch (type.getLocation()) + { + case ArrayType::Location::CallData: + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + break; + case ArrayType::Location::Storage: + m_context << eth::Instruction::SLOAD; + break; + default: + solAssert(false, "Unsupported array location."); + break; + } break; } default: @@ -559,19 +564,40 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) _indexAccess.getBaseExpression().accept(*this); Type const& baseType = *_indexAccess.getBaseExpression().getType(); - solAssert(baseType.getCategory() == Type::Category::Mapping, ""); - Type const& keyType = *dynamic_cast(baseType).getKeyType(); - m_context << u256(0); - solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); - appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); - solAssert(baseType.getSizeOnStack() == 1, - "Unexpected: Not exactly one stack slot taken by subscriptable expression."); - m_context << eth::Instruction::SWAP1; - appendTypeMoveToMemory(IntegerType(256)); - m_context << u256(0) << eth::Instruction::SHA3; - - m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType()); - m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); + if (baseType.getCategory() == Type::Category::Mapping) + { + Type const& keyType = *dynamic_cast(baseType).getKeyType(); + m_context << u256(0); + solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); + appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); + solAssert(baseType.getSizeOnStack() == 1, + "Unexpected: Not exactly one stack slot taken by subscriptable expression."); + m_context << eth::Instruction::SWAP1; + appendTypeMoveToMemory(IntegerType(256)); + m_context << u256(0) << eth::Instruction::SHA3; + m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType()); + m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); + } + else if (baseType.getCategory() == Type::Category::Array) + { + ArrayType const& arrayType = dynamic_cast(baseType); + solAssert(arrayType.getLocation() == ArrayType::Location::Storage, + "TODO: Index acces only implemented for storage arrays."); + solAssert(!arrayType.isDynamicallySized(), + "TODO: Index acces only implemented for fixed-size arrays."); + solAssert(!arrayType.isByteArray(), + "TODO: Index acces not implemented for byte arrays."); + solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); + // TODO: for dynamically-sized arrays, update the length for each write + // TODO: do we want to check the index? + _indexAccess.getIndexExpression()->accept(*this); + m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL + << eth::Instruction::ADD; + m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType()); + m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); + } + else + solAssert(false, "Index access only allowed for mappings or arrays."); return false; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index c0be0d93e..adcd2e542 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -555,6 +555,19 @@ bool ArrayType::operator==(Type const& _other) const return other.m_location == m_location; } +u256 ArrayType::getStorageSize() const +{ + if (isDynamicallySized()) + return 1; + else + { + bigint size = bigint(getLength()) * getBaseType()->getStorageSize(); + if (size >= bigint(1) << 256) + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Array too large for storage.")); + return max(1, u256(size)); + } +} + unsigned ArrayType::getSizeOnStack() const { if (m_location == Location::CallData) @@ -665,10 +678,12 @@ bool StructType::operator==(Type const& _other) const u256 StructType::getStorageSize() const { - u256 size = 0; + bigint size = 0; for (pair const& member: getMembers()) size += member.second->getStorageSize(); - return max(1, size); + if (size >= bigint(1) << 256) + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Struct too large for storage.")); + return max(1, u256(size)); } bool StructType::canLiveOutsideStorage() const diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 0d24b7221..9961f03a3 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -303,6 +303,7 @@ public: virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(const Type& _other) const override; virtual bool isDynamicallySized() const { return m_hasDynamicLength; } + virtual u256 getStorageSize() const override; virtual unsigned getSizeOnStack() const override; virtual std::string toString() const override; virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 20bc81599..0c4c79aca 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2667,6 +2667,33 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) == encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length()))); } +BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage) +{ + char const* sourceCode = R"( + contract c { + struct Data { uint x; uint y; } + Data[2**10] data; + uint[2**10 + 3] ids; + function setIDStatic(uint id) { ids[2] = id; } + function setID(uint index, uint id) { ids[index] = id; } + function setData(uint index, uint x, uint y) { data[index].x = x; data[index].y = y; } + function getID(uint index) returns (uint) { return ids[index]; } + function getData(uint index) returns (uint x, uint y) { x = data[index].x; y = data[index].y; } + function getLengths() returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("setIDStatic(uint256)", 11) == bytes()); + BOOST_CHECK(callContractFunction("getID(uint256)", 2) == encodeArgs(11)); + BOOST_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8) == bytes()); + BOOST_CHECK(callContractFunction("getID(uint256)", 7) == encodeArgs(8)); + BOOST_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9) == bytes()); + BOOST_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11) == bytes()); + BOOST_CHECK(callContractFunction("getData(uint256)", 7) == encodeArgs(8, 9)); + BOOST_CHECK(callContractFunction("getData(uint256)", 8) == encodeArgs(10, 11)); + BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(u256(1) << 10, (u256(1) << 10) + 3)); +} + BOOST_AUTO_TEST_SUITE_END() } From de537d5de3a3d48d31df20d11cfbfc975862701d Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 23 Feb 2015 01:31:05 +0100 Subject: [PATCH 197/201] Index and length access for dynamic arrays. --- libsolidity/AST.cpp | 12 +++++++++++- libsolidity/ExpressionCompiler.cpp | 18 ++++++++---------- test/SolidityEndToEndTest.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 179461152..c37e8c374 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -603,7 +603,17 @@ void MemberAccess::checkTypeRequirements() if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not " "visible in " + type.toString())); - m_isLValue = (type.getCategory() == Type::Category::Struct); + // This should probably move somewhere else. + if (type.getCategory() == Type::Category::Struct) + m_isLValue = true; + else if (type.getCategory() == Type::Category::Array) + { + auto const& arrayType(dynamic_cast(type)); + m_isLValue = (*m_memberName == "length" && + arrayType.getLocation() != ArrayType::Location::CallData && arrayType.isDynamicallySized()); + } + else + m_isLValue = false; } void IndexAccess::checkTypeRequirements() diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index dcd411c3e..a54915bc7 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -546,7 +546,8 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; break; case ArrayType::Location::Storage: - m_context << eth::Instruction::SLOAD; + m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _memberAccess.getType()); + m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); break; default: solAssert(false, "Unsupported array location."); @@ -583,13 +584,10 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) ArrayType const& arrayType = dynamic_cast(baseType); solAssert(arrayType.getLocation() == ArrayType::Location::Storage, "TODO: Index acces only implemented for storage arrays."); - solAssert(!arrayType.isDynamicallySized(), - "TODO: Index acces only implemented for fixed-size arrays."); - solAssert(!arrayType.isByteArray(), - "TODO: Index acces not implemented for byte arrays."); + solAssert(!arrayType.isByteArray(), "TODO: Index acces not implemented for byte arrays."); solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); - // TODO: for dynamically-sized arrays, update the length for each write - // TODO: do we want to check the index? + if (arrayType.isDynamicallySized()) + CompilerUtils(m_context).computeHashStatic(); _indexAccess.getIndexExpression()->accept(*this); m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL << eth::Instruction::ADD; @@ -1075,7 +1073,7 @@ void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _ { case LValueType::Stack: { - unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); + unsigned stackPos = m_context->baseToCurrentStackOffset(m_baseStackOffset); if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); @@ -1124,7 +1122,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co { case LValueType::Stack: { - unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1; + unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); @@ -1227,7 +1225,7 @@ void ExpressionCompiler::LValue::setToZero(Location const& _location) const { case LValueType::Stack: { - unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); + unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset); if (stackDiff > 16) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 0c4c79aca..6f85aec9e 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2694,6 +2694,35 @@ BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage) BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(u256(1) << 10, (u256(1) << 10) + 3)); } +BOOST_AUTO_TEST_CASE(dynamic_arrays_in_storage) +{ + char const* sourceCode = R"( + contract c { + struct Data { uint x; uint y; } + Data[] data; + uint[] ids; + function setIDStatic(uint id) { ids[2] = id; } + function setID(uint index, uint id) { ids[index] = id; } + function setData(uint index, uint x, uint y) { data[index].x = x; data[index].y = y; } + function getID(uint index) returns (uint) { return ids[index]; } + function getData(uint index) returns (uint x, uint y) { x = data[index].x; y = data[index].y; } + function getLengths() returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; } + function setLengths(uint l1, uint l2) { data.length = l1; ids.length = l2; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("setIDStatic(uint256)", 11) == bytes()); + BOOST_CHECK(callContractFunction("getID(uint256)", 2) == encodeArgs(11)); + BOOST_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8) == bytes()); + BOOST_CHECK(callContractFunction("getID(uint256)", 7) == encodeArgs(8)); + BOOST_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9) == bytes()); + BOOST_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11) == bytes()); + BOOST_CHECK(callContractFunction("getData(uint256)", 7) == encodeArgs(8, 9)); + BOOST_CHECK(callContractFunction("getData(uint256)", 8) == encodeArgs(10, 11)); + BOOST_CHECK(callContractFunction("setLengths(uint256,uint256)", 48, 49) == bytes()); + BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(48, 49)); +} + BOOST_AUTO_TEST_SUITE_END() } From 32f0c4f8e643706fa56b4ffb231e7ac16a26dc3b Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 23 Feb 2015 18:21:17 +0100 Subject: [PATCH 198/201] Out-of-bounds checking. --- libsolidity/ExpressionCompiler.cpp | 24 +++++++++++++-- test/SolidityEndToEndTest.cpp | 49 ++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a54915bc7..183864ec7 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -586,11 +586,29 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) "TODO: Index acces only implemented for storage arrays."); solAssert(!arrayType.isByteArray(), "TODO: Index acces not implemented for byte arrays."); solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); + + _indexAccess.getIndexExpression()->accept(*this); + // retrieve length if (arrayType.isDynamicallySized()) + m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; + else + m_context << arrayType.getLength(); + // stack: + // check out-of-bounds access + m_context << eth::Instruction::DUP2 << eth::Instruction::LT; + eth::AssemblyItem legalAccess = m_context.appendConditionalJump(); + // out-of-bounds access throws exception (just STOP for now) + m_context << eth::Instruction::STOP; + + m_context << legalAccess; + // stack: + m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL; + if (arrayType.isDynamicallySized()) + { + m_context << eth::Instruction::SWAP1; CompilerUtils(m_context).computeHashStatic(); - _indexAccess.getIndexExpression()->accept(*this); - m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL - << eth::Instruction::ADD; + } + m_context << eth::Instruction::ADD; m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType()); m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); } diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 6f85aec9e..f43692110 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2711,6 +2711,9 @@ BOOST_AUTO_TEST_CASE(dynamic_arrays_in_storage) } )"; compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(0, 0)); + BOOST_CHECK(callContractFunction("setLengths(uint256,uint256)", 48, 49) == bytes()); + BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(48, 49)); BOOST_CHECK(callContractFunction("setIDStatic(uint256)", 11) == bytes()); BOOST_CHECK(callContractFunction("getID(uint256)", 2) == encodeArgs(11)); BOOST_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8) == bytes()); @@ -2719,8 +2722,50 @@ BOOST_AUTO_TEST_CASE(dynamic_arrays_in_storage) BOOST_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11) == bytes()); BOOST_CHECK(callContractFunction("getData(uint256)", 7) == encodeArgs(8, 9)); BOOST_CHECK(callContractFunction("getData(uint256)", 8) == encodeArgs(10, 11)); - BOOST_CHECK(callContractFunction("setLengths(uint256,uint256)", 48, 49) == bytes()); - BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(48, 49)); +} + +BOOST_AUTO_TEST_CASE(fixed_out_of_bounds_array_access) +{ + char const* sourceCode = R"( + contract c { + uint[4] data; + function set(uint index, uint value) returns (bool) { data[index] = value; return true; } + function get(uint index) returns (uint) { return data[index]; } + function length() returns (uint) { return data.length; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); + BOOST_CHECK(callContractFunction("set(uint256,uint256)", 3, 4) == encodeArgs(true)); + BOOST_CHECK(callContractFunction("set(uint256,uint256)", 4, 5) == bytes()); + BOOST_CHECK(callContractFunction("set(uint256,uint256)", 400, 5) == bytes()); + BOOST_CHECK(callContractFunction("get(uint256)", 3) == encodeArgs(4)); + BOOST_CHECK(callContractFunction("get(uint256)", 4) == bytes()); + BOOST_CHECK(callContractFunction("get(uint256)", 400) == bytes()); + BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); +} + +BOOST_AUTO_TEST_CASE(dynamic_out_of_bounds_array_access) +{ + char const* sourceCode = R"( + contract c { + uint[] data; + function enlarge(uint amount) returns (uint) { return data.length += amount; } + function set(uint index, uint value) returns (bool) { data[index] = value; return true; } + function get(uint index) returns (uint) { return data[index]; } + function length() returns (uint) { return data.length; } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("length()") == encodeArgs(0)); + BOOST_CHECK(callContractFunction("get(uint256)", 3) == bytes()); + BOOST_CHECK(callContractFunction("enlarge(uint256)", 4) == encodeArgs(4)); + BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); + BOOST_CHECK(callContractFunction("set(uint256,uint256)", 3, 4) == encodeArgs(true)); + BOOST_CHECK(callContractFunction("get(uint256)", 3) == encodeArgs(4)); + BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); + BOOST_CHECK(callContractFunction("set(uint256,uint256)", 4, 8) == bytes()); + BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); } BOOST_AUTO_TEST_SUITE_END() From 73d7430c73da7f703ed5b05e34b3e1dde4cbc1dd Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 23 Feb 2015 22:10:35 +0100 Subject: [PATCH 199/201] fixed contract creation transaction --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 6ab701899..c304e3c03 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -701,10 +701,10 @@ 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.creation) + ret = right160(sha3(rlpList(t.from, client()->countAt(t.from))));; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) From 3767677b277e0eced9d782f01456926e228b7030 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 23 Feb 2015 23:45:04 +0100 Subject: [PATCH 200/201] explicit operator bool for hash type --- alethzero/MainWin.cpp | 2 +- libdevcore/FixedHash.h | 2 +- libdevcrypto/CryptoPP.cpp | 2 +- libethcore/ProofOfWork.h | 2 +- libethereum/EthereumHost.h | 2 +- libethereum/Transaction.h | 2 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- libwhisper/Common.cpp | 2 +- mix/ClientModel.cpp | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 39bc0ad43..9ee3f36e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1629,7 +1629,7 @@ void Main::on_net_triggered() { web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setNetworkPreferences(netPrefs()); - ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0); + ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); // TODO: p2p // if (m_networkConfig.size()/* && ui->usePast->isChecked()*/) // web3()->restoreNetwork(bytesConstRef((byte*)m_networkConfig.data(), m_networkConfig.size())); diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 561f2f405..2b4e6bc08 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -80,7 +80,7 @@ public: operator Arith() const { return fromBigEndian(m_data); } /// @returns true iff this is the empty hash. - operator bool() const { return ((Arith)*this) != 0; } + explicit operator bool() const { return ((Arith)*this) != 0; } // The obvious comparison operators. bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; } diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 2d0170fb9..43993e0c5 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -134,7 +134,7 @@ bool Secp256k1::verify(Signature const& _signature, bytesConstRef _message) bool Secp256k1::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) { // todo: verify w/o recovery (if faster) - return _p == _hashed ? recover(_sig, _message) : recover(_sig, sha3(_message).ref()); + return (bool)_p == _hashed ? (bool)recover(_sig, _message) : (bool)recover(_sig, sha3(_message).ref()); } Public Secp256k1::recover(Signature _signature, bytesConstRef _message) diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 64ce502af..c3c3f192b 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -82,7 +82,7 @@ template std::pair ProofOfWorkEngine::mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo) { std::pair ret; - static std::mt19937_64 s_eng((time(0) + (unsigned)m_last)); + static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()))); u256 s = (m_last = h256::random(s_eng)); bigint d = (bigint(1) << 256) / _difficulty; diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index c732f2dc1..dfa928675 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -94,7 +94,7 @@ private: h256Set neededBlocks(h256Set const& _exclude); /// Check to see if the network peer-state initialisation has happened. - bool isInitialised() const { return m_latestBlockSent; } + bool isInitialised() const { return (bool)m_latestBlockSent; } /// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first. bool ensureInitialised(); diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 0f88a4bc0..a9044970f 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -81,7 +81,7 @@ public: Address safeSender() const noexcept; /// @returns true if transaction is non-null. - operator bool() const { return m_type != NullTransaction; } + explicit operator bool() const { return m_type != NullTransaction; } /// @returns true if transaction is contract-creation. bool isCreation() const { return m_type == ContractCreation; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index c304e3c03..dbf3b2ec9 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -704,7 +704,7 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) if (!t.from) t.from = m_accounts->getDefaultTransactAccount(); if (t.creation) - ret = right160(sha3(rlpList(t.from, client()->countAt(t.from))));; + ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));; if (!t.gasPrice) t.gasPrice = 10 * dev::eth::szabo; if (!t.gas) diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index f17ad638b..c29ac6bf6 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -71,7 +71,7 @@ bool TopicFilter::matches(Envelope const& _e) const for (unsigned i = 0; i < t.size(); ++i) { for (auto et: _e.topic()) - if (((t[i].first ^ et) & t[i].second) == 0) + if (((t[i].first ^ et) & t[i].second) == CollapsedTopicPart()) goto NEXT_TOPICPART; // failed to match topicmask against any topics: move on to next mask goto NEXT_TOPICMASK; diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 45198c114..110bdc141 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -370,7 +370,7 @@ void ClientModel::onNewTransaction() QString function; QString returned; - bool creation = tr.contractAddress != 0; + bool creation = (bool)tr.contractAddress; //TODO: handle value transfer FixedHash<4> functionHash; @@ -403,7 +403,7 @@ void ClientModel::onNewTransaction() if (creation) returned = QString::fromStdString(toJS(tr.contractAddress)); - Address contractAddress = tr.address != 0 ? tr.address : tr.contractAddress; + Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress; auto contractAddressIter = m_contractNames.find(contractAddress); if (contractAddressIter != m_contractNames.end()) { From 1b284c5b8b705be4a19acacb84809589673174ff Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 24 Feb 2015 00:11:29 +0100 Subject: [PATCH 201/201] fixed test buid --- test/SolidityEndToEndTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 20bc81599..b63e9ad46 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2137,7 +2137,7 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data) callContractFunctionWithValue("deposit(hash256)", value, id); BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); - BOOST_CHECK(m_logs[0].data == encodeArgs(m_sender, id, value, true)); + BOOST_CHECK(m_logs[0].data == encodeArgs((u160)m_sender, id, value, true)); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,hash256,uint256,bool)"))); }