/* 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 main.cpp * @author Gav Wood * @date 2014 * Ethereum client. */ #include #include #include #include #include #include #include #include #include #include #include #if ETH_READLINE #include #include #endif #if ETH_JSONRPC #include "EthStubServer.h" #endif #include "BuildInfo.h" using namespace std; using namespace eth; using eth::Instruction; using eth::c_instructionInfo; bool isTrue(std::string const& _m) { return _m == "on" || _m == "yes" || _m == "true" || _m == "1"; } bool isFalse(std::string const& _m) { return _m == "off" || _m == "no" || _m == "false" || _m == "0"; } void interactiveHelp() { cout << "Commands:" << endl << " netstart Starts the network subsystem on a specific port." << endl << " netstop Stops the network subsystem." << endl << " jsonstart Starts the JSON-RPC server." << endl << " jsonstop Stops the JSON-RPC server." << endl << " connect Connects to a specific peer." << endl << " verbosity () Gets or sets verbosity level." << 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. TODO." << endl << " send Execute a given transaction with current secret. TODO." << endl << " create Create a new contract with current secret. TODO." << endl << " inspect Dumps a contract to /.evm." << endl << " exit Exits the application." << endl; } void help() { cout << "Usage eth [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 << " -i,--interactive Enter interactive mode (default: non-interactive)." << 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 #endif << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl << " -m,--mining Enable mining, optionally for a specified number of blocks (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 (Default: 8)." << endl << " -x,--peers Attempt to connect to given number of peers (Default: 5)." << endl << " -V,--version Show the version and exit." << endl; exit(0); } string credits(bool _interactive = false) { std::ostringstream cout; cout << "Ethereum (++) " << ETH_QUOTED(ETH_VERSION) << endl << " Code by Gav Wood, (c) 2013, 2014." << endl << " Based on a design by Vitalik Buterin." << endl << endl; if (_interactive) { string vs = toString(ETH_QUOTED(ETH_VERSION)); vs = vs.substr(vs.find_first_of('.') + 1)[0]; int pocnumber = stoi(vs); string m_servers; if (pocnumber == 3) m_servers = "54.201.28.117"; if (pocnumber == 4) m_servers = "54.72.31.55"; cout << "Type 'netstart 30303' to start networking" << endl; cout << "Type 'connect " << m_servers << " 30303' to connect" << endl; cout << "Type 'exit' to quit" << endl << endl; } return cout.str(); } void version() { cout << "eth version " << ETH_QUOTED(ETH_VERSION) << endl; cout << "Build: " << ETH_QUOTED(ETH_BUILD_PLATFORM) << "/" << ETH_QUOTED(ETH_BUILD_TYPE) << endl; exit(0); } Address c_config = Address("ccdeac59d35627b7de09332e819d5159e7bb7250"); string pretty(h160 _a, eth::State _st) { string ns; h256 n; if (h160 nameReg = (u160)_st.storage(c_config, 0)) n = _st.storage(nameReg, (u160)(_a)); if (n) { std::string s((char const*)n.data(), 32); if (s.find_first_of('\0') != string::npos) s.resize(s.find_first_of('\0')); ns = " " + s; } return ns; } int main(int argc, char** argv) { unsigned short listenPort = 30303; string remoteHost; unsigned short remotePort = 30303; string dbPath; eth::uint mining = ~(eth::uint)0; NodeMode mode = NodeMode::Full; unsigned peers = 5; bool interactive = false; #if ETH_JSONRPC int jsonrpc = 8080; #endif string publicIP; bool upnp = true; string clientName; // Init defaults Defaults::get(); // Our address. KeyPair us = KeyPair::create(); Address coinbase = us.address(); string configFile = getDataDir() + "/config.rlp"; bytes b = contents(configFile); if (b.size()) { RLP config(b); us = KeyPair(config[0].toHash()); coinbase = config[1].toHash
(); } else { RLPStream config(2); config << us.secret() << coinbase; writeFile(configFile, config.out()); } for (int i = 1; i < argc; ++i) { string arg = argv[i]; if ((arg == "-l" || arg == "--listen" || arg == "--listen-port") && i + 1 < argc) listenPort = (short)atoi(argv[++i]); else if ((arg == "-u" || arg == "--public-ip" || arg == "--public") && i + 1 < argc) publicIP = argv[++i]; else if ((arg == "-r" || arg == "--remote") && i + 1 < argc) remoteHost = argv[++i]; else if ((arg == "-p" || arg == "--port") && i + 1 < argc) remotePort = (short)atoi(argv[++i]); else if ((arg == "-n" || arg == "--upnp") && i + 1 < argc) { string m = argv[++i]; if (isTrue(m)) upnp = true; else if (isFalse(m)) upnp = false; else { cerr << "Invalid UPnP option: " << m << endl; return -1; } } else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc) clientName = argv[++i]; else if ((arg == "-a" || arg == "--address" || arg == "--coinbase-address") && i + 1 < argc) coinbase = h160(fromHex(argv[++i])); else if ((arg == "-s" || arg == "--secret") && i + 1 < argc) us = KeyPair(h256(fromHex(argv[++i]))); else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc) dbPath = argv[++i]; else if ((arg == "-m" || arg == "--mining") && i + 1 < argc) { string m = argv[++i]; if (isTrue(m)) mining = ~(eth::uint)0; else if (isFalse(m)) mining = 0; else if (int i = stoi(m)) mining = i; else { cerr << "Unknown mining option: " << m << endl; return -1; } } else if (arg == "-i" || arg == "--interactive") interactive = true; #if ETH_JSONRPC else if ((arg == "-j" || arg == "--json-rpc")) jsonrpc = jsonrpc ? jsonrpc : 8080; else if (arg == "--json-rpc-port" && i + 1 < argc) jsonrpc = atoi(argv[++i]); #endif else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc) g_logVerbosity = atoi(argv[++i]); else if ((arg == "-x" || arg == "--peers") && i + 1 < argc) peers = atoi(argv[++i]); else if ((arg == "-o" || arg == "--mode") && i + 1 < argc) { string m = argv[++i]; if (m == "full") mode = NodeMode::Full; else if (m == "peer") mode = NodeMode::PeerServer; else { cerr << "Unknown mode: " << m << endl; return -1; } } else if (arg == "-h" || arg == "--help") help(); else if (arg == "-V" || arg == "--version") version(); else remoteHost = argv[i]; } if (!clientName.empty()) clientName += "/"; Client c("Ethereum(++)/" + clientName + "v" ETH_QUOTED(ETH_VERSION) "/" ETH_QUOTED(ETH_BUILD_TYPE) "/" ETH_QUOTED(ETH_BUILD_PLATFORM), coinbase, dbPath); cout << credits(); cout << "Address: " << endl << toHex(us.address().asArray()) << endl; c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp); #if ETH_JSONRPC auto_ptr jsonrpcServer; if (jsonrpc > -1) { jsonrpcServer = auto_ptr(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c)); jsonrpcServer->setKeys({us}); jsonrpcServer->StartListening(); } #endif if (interactive) { string l; while (true) { #if ETH_READLINE if (l.size()) add_history(l.c_str()); if (auto c = readline("> ")) { l = c; free(c); } else break; #else string l; cout << "> " << flush; std::getline(cin, l); #endif istringstream iss(l); string cmd; iss >> cmd; if (cmd == "netstart") { eth::uint port; iss >> port; ClientGuard g(&c); c.startNetwork((short)port); } else if (cmd == "connect") { string addr; eth::uint port; iss >> addr >> port; ClientGuard g(&c); c.connect(addr, (short)port); } else if (cmd == "netstop") { ClientGuard g(&c); c.stopNetwork(); } else if (cmd == "minestart") { c.startMining(); } else if (cmd == "minestop") { c.stopMining(); } else if (cmd == "verbosity") { if (iss.peek() != -1) iss >> g_logVerbosity; cout << "Verbosity: " << g_logVerbosity << endl; } #if ETH_JSONRPC else if (cmd == "jsonport") { if (iss.peek() != -1) iss >> jsonrpc; cout << "JSONRPC Port: " << jsonrpc << endl; } else if (cmd == "jsonstart") { if (jsonrpc < 0) jsonrpc = 8080; jsonrpcServer = auto_ptr(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c)); jsonrpcServer->setKeys({us}); jsonrpcServer->StartListening(); } else if (cmd == "jsonstop") { if (jsonrpcServer.get()) jsonrpcServer->StopListening(); jsonrpcServer.reset(); } #endif else if (cmd == "address") { cout << "Current address:" << endl; const char* addchr = toHex(us.address().asArray()).c_str(); cout << addchr << endl; } else if (cmd == "secret") { cout << "Secret Key: " << toHex(us.secret().asArray()) << endl; } else if (cmd == "block") { ClientGuard g(&c); cout << "Current block: " << c.blockChain().details().number; } else if (cmd == "peers") { ClientGuard g(&c); for (auto it: c.peers()) cout << it.host << ":" << it.port << ", " << it.clientVersion << ", " << std::chrono::duration_cast(it.lastPing).count() << "ms" << endl; } else if (cmd == "balance") { ClientGuard g(&c); cout << "Current balance: " << c.postState().balance(us.address()) << endl; } else if (cmd == "transact") { //TODO. } else if (cmd == "send") { //TODO } else if (cmd == "create") { //TODO } else if (cmd == "inspect") { string rechex; iss >> rechex; if (rechex.length() != 40) cwarn << "Invalid address length"; else { ClientGuard g(&c); auto h = h160(fromHex(rechex)); stringstream s; auto mem = c.state().storage(h); for (auto const& i: mem) s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl; s << endl << disassemble(c.state().code(h)); string outFile = getDataDir() + "/" + rechex + ".evm"; ofstream ofs; ofs.open(outFile, ofstream::binary); ofs.write(s.str().c_str(), s.str().length()); ofs.close(); } } else if (cmd == "help") interactiveHelp(); else if (cmd == "exit") break; else cout << "Unrecognised command. Type 'help' for help in interactive mode." << endl; } #if ETH_JSONRPC if (jsonrpcServer.get()) jsonrpcServer->StopListening(); #endif } else { eth::uint n = c.blockChain().details().number; if (mining) c.startMining(); while (true) { if (c.blockChain().details().number - n == mining) c.stopMining(); this_thread::sleep_for(chrono::milliseconds(100)); } } return 0; }