bool AccountManager::execute(int argc, char** argv) { if (string(argv[1]) == "wallet") { if (3 < argc && string(argv[2]) == "import") { if (!openWallet()) return false; string file = argv[3]; string name = "presale wallet"; string pw; KeyPair k; try { k = m_keyManager->presaleSecret( contentsString(file), [&](bool){ return (pw = getPassword("Enter the passphrase for the presale key: "));} ); } catch (Exception const& _e) { if (auto err = boost::get_error_info<errinfo_comment>(_e)) cout << " Decryption failed: " << *err << endl; else cout << " Decryption failed: Unknown reason." << endl; return false; } m_keyManager->import(k.secret(), name, pw, "Same passphrase as used for presale key"); cout << " Address: {" << k.address().hex() << "}" << endl; } else streamWalletHelp(cout); return true; } else if (string(argv[1]) == "account") { if (argc < 3 || string(argv[2]) == "list") { openWallet(); if (m_keyManager->store().keys().empty()) cout << "No keys found." << endl; else { vector<u128> bare; AddressHash got; int k = 0; for (auto const& u: m_keyManager->store().keys()) { if (Address a = m_keyManager->address(u)) { got.insert(a); cout << "Account #" << k << ": {" << a.hex() << "}" << endl; k++; } else bare.push_back(u); } for (auto const& a: m_keyManager->accounts()) if (!got.count(a)) { cout << "Account #" << k << ": {" << a.hex() << "}" << " (Brain)" << endl; k++; } for (auto const& u: bare) { cout << "Account #" << k << ": " << toUUID(u) << " (Bare)" << endl; k++; } } } else if (2 < argc && string(argv[2]) == "new") { openWallet(); string name; string lock; string lockHint; lock = createPassword("Enter a passphrase with which to secure this account:"); auto k = makeKey(); h128 u = m_keyManager->import(k.secret(), name, lock, lockHint); cout << "Created key " << toUUID(u) << endl; cout << " ICAP: " << ICAP(k.address()).encoded() << endl; cout << " Address: {" << k.address().hex() << "}" << endl; } else if (3 < argc && string(argv[2]) == "import") { openWallet(); h128 u = m_keyManager->store().importKey(argv[3]); if (!u) { cerr << "Error: reading key file failed" << endl; return false; } string pw; bytesSec s = m_keyManager->store().secret(u, [&](){ return (pw = getPassword("Enter the passphrase for the key: ")); }); if (s.empty()) { cerr << "Error: couldn't decode key or invalid secret size." << endl; return false; } else { string lockHint; string name; m_keyManager->importExisting(u, name, pw, lockHint); auto a = m_keyManager->address(u); cout << "Imported key " << toUUID(u) << endl; cout << " ICAP: " << ICAP(a).encoded() << endl; cout << " Address: {" << a.hex() << "}" << endl; } } else if (3 < argc && string(argv[2]) == "update") { openWallet(); for (int k = 3; k < argc; k++) { string i = argv[k]; h128 u = fromUUID(i); if (isHex(i) || u != h128()) { string newP = createPassword("Enter the new passphrase for the account " + i); auto oldP = [&](){ return getPassword("Enter the current passphrase for the account " + i + ": "); }; bool recoded = false; if (isHex(i)) { recoded = m_keyManager->store().recode( Address(i), newP, oldP, dev::KDF::Scrypt ); } else if (u != h128()) { recoded = m_keyManager->store().recode( u, newP, oldP, dev::KDF::Scrypt ); } if (recoded) cerr << "Re-encoded " << i << endl; else cerr << "Couldn't re-encode " << i << "; key does not exist, corrupt or incorrect passphrase supplied." << endl; } else cerr << "Couldn't re-encode " << i << "; does not represent an address or uuid." << endl; } } else streamAccountHelp(cout); return true; } else return false; }
int main(int argc, char** argv) { setDefaultOrCLocale(); // Init secp256k1 context by calling one of the functions. toPublic(Secret{}); // Init defaults Ethash::init(); NoProof::init(); /// Operating mode. OperationMode mode = OperationMode::Node; /// File name for import/export. string filename; bool safeImport = false; /// Hashes/numbers for export range. string exportFrom = "1"; string exportTo = "latest"; Format exportFormat = Format::Binary; bool ipc = true; string jsonAdmin; ChainParams chainParams; bool upnp = true; WithExisting withExisting = WithExisting::Trust; /// Networking params. string listenIP; unsigned short listenPort = dev::p2p::c_defaultListenPort; string publicIP; string remoteHost; unsigned short remotePort = dev::p2p::c_defaultListenPort; unsigned peers = 11; unsigned peerStretch = 7; std::map<p2p::NodeID, pair<NodeIPEndpoint, bool>> preferredNodes; bool bootstrap = true; bool disableDiscovery = false; bool allowLocalDiscovery = false; static const unsigned NoNetworkID = (unsigned)-1; unsigned networkID = NoNetworkID; /// Mining params unsigned mining = 0; Address author; strings presaleImports; bytes extraData; /// Transaction params // TransactionPriority priority = TransactionPriority::Medium; // double etherPrice = 30.679; // double blockFees = 15.0; u256 askPrice = 0; u256 bidPrice = DefaultGasPrice; bool alwaysConfirm = true; /// Wallet password stuff string masterPassword; bool masterSet = false; /// Whisper bool testingMode = false; fs::path configFile = getDataDir() / fs::path("config.rlp"); bytes b = contents(configFile); strings passwordsToNote; Secrets toImport; if (b.size()) { try { RLP config(b); author = config[1].toHash<Address>(); } catch (...) {} } if (argc > 1 && (string(argv[1]) == "wallet" || string(argv[1]) == "account")) { AccountManager accountm; return !accountm.execute(argc, argv); } MinerCLI miner(MinerCLI::OperationMode::None); bool listenSet = false; bool chainConfigIsSet = false; fs::path configPath; string configJSON; po::options_description clientDefaultMode("CLIENT MODE (default)", c_lineWidth); auto addClientOption = clientDefaultMode.add_options(); addClientOption("mainnet", "Use the main network protocol"); addClientOption("ropsten", "Use the Ropsten testnet"); addClientOption("test", "Testing mode; disable PoW and provide test rpc interface"); addClientOption("config", po::value<string>()->value_name("<file>"), "Configure specialised blockchain using given JSON information\n"); addClientOption("ipc", "Enable IPC server (default: on)"); addClientOption("ipcpath", po::value<string>()->value_name("<path>"), "Set .ipc socket path (default: data directory)"); addClientOption("no-ipc", "Disable IPC server"); addClientOption("admin", po::value<string>()->value_name("<password>"), "Specify admin session key for JSON-RPC (default: auto-generated and printed at " "start-up)"); addClientOption("kill,K", "Kill the blockchain first"); addClientOption("rebuild,R", "Rebuild the blockchain from the existing database"); addClientOption("rescue", "Attempt to rescue a corrupt database\n"); addClientOption("import-presale", po::value<string>()->value_name("<file>"), "Import a pre-sale key; you'll need to specify the password to this key"); addClientOption("import-secret,s", po::value<string>()->value_name("<secret>"), "Import a secret key into the key store"); addClientOption("import-session-secret,S", po::value<string>()->value_name("<secret>"), "Import a secret session into the key store"); addClientOption("master", po::value<string>()->value_name("<password>"), "Give the master password for the key store; use --master \"\" to show a prompt"); addClientOption("password", po::value<string>()->value_name("<password>"), "Give a password for a private key\n"); po::options_description clientTransacting("CLIENT TRANSACTING", c_lineWidth); auto addTransactingOption = clientTransacting.add_options(); addTransactingOption("ask", po::value<u256>()->value_name("<wei>"), ("Set the minimum ask gas price under which no transaction will be mined (default: " + toString(DefaultGasPrice) + ")") .c_str()); addTransactingOption("bid", po::value<u256>()->value_name("<wei>"), ("Set the bid gas price to pay for transactions (default: " + toString(DefaultGasPrice) + ")") .c_str()); addTransactingOption("unsafe-transactions", "Allow all transactions to proceed without verification; EXTREMELY UNSAFE\n"); po::options_description clientMining("CLIENT MINING", c_lineWidth); auto addMininigOption = clientMining.add_options(); addMininigOption("address,a", po::value<Address>()->value_name("<addr>"), "Set the author (mining payout) address (default: auto)"); addMininigOption("mining,m", po::value<string>()->value_name("<on/off/number>"), "Enable mining; optionally for a specified number of blocks (default: off)"); addMininigOption("extra-data", po::value<string>(), "Set extra data for the sealed blocks\n"); po::options_description clientNetworking("CLIENT NETWORKING", c_lineWidth); auto addNetworkingOption = clientNetworking.add_options(); addNetworkingOption("bootstrap,b", "Connect to the default Ethereum peer servers (default unless --no-discovery used)"); addNetworkingOption("no-bootstrap", "Do not connect to the default Ethereum peer servers (default only when --no-discovery is " "used)"); addNetworkingOption("peers,x", po::value<int>()->value_name("<number>"), "Attempt to connect to a given number of peers (default: 11)"); addNetworkingOption("peer-stretch", po::value<int>()->value_name("<number>"), "Give the accepted connection multiplier (default: 7)"); addNetworkingOption("public-ip", po::value<string>()->value_name("<ip>"), "Force advertised public IP to the given IP (default: auto)"); addNetworkingOption("listen-ip", po::value<string>()->value_name("<ip>(:<port>)"), "Listen on the given IP for incoming connections (default: 0.0.0.0)"); addNetworkingOption("listen", po::value<unsigned short>()->value_name("<port>"), "Listen on the given port for incoming connections (default: 30303)"); addNetworkingOption("remote,r", po::value<string>()->value_name("<host>(:<port>)"), "Connect to the given remote host (default: none)"); addNetworkingOption("port", po::value<short>()->value_name("<port>"), "Connect to the given remote port (default: 30303)"); addNetworkingOption("network-id", po::value<unsigned>()->value_name("<n>"), "Only connect to other hosts with this network id"); addNetworkingOption("allow-local-discovery", po::bool_switch(&allowLocalDiscovery), "Include local addresses in the discovery process. Used for testing purposes."); #if ETH_MINIUPNPC addNetworkingOption( "upnp", po::value<string>()->value_name("<on/off>"), "Use UPnP for NAT (default: on)"); #endif stringstream peersetDescriptionStream; peersetDescriptionStream << "Comma delimited list of peers; element format: type:enode://publickey@ipAddress[:port[?discport=port]]\n" " Types:\n" " default Attempt connection when no other peers are available and pinning is disabled\n" " required Keep connected at all times\n\n" " Ports:\n" " The first port argument is the tcp port used for direct communication among peers. If the second port\n" " argument isn't supplied, the first port argument will also be the udp port used for node discovery.\n" " If neither the first nor second port arguments are supplied, a default port of " << dev::p2p::c_defaultListenPort << " will be used for\n" " both peer communication and node discovery."; string peersetDescription = peersetDescriptionStream.str(); addNetworkingOption("peerset", po::value<string>()->value_name("<list>"), peersetDescription.c_str()); addNetworkingOption("no-discovery", "Disable node discovery; implies --no-bootstrap"); addNetworkingOption("pin", "Only accept or connect to trusted peers\n"); std::string snapshotPath; po::options_description importExportMode("IMPORT/EXPORT MODES", c_lineWidth); auto addImportExportOption = importExportMode.add_options(); addImportExportOption( "import,I", po::value<string>()->value_name("<file>"), "Import blocks from file"); addImportExportOption( "export,E", po::value<string>()->value_name("<file>"), "Export blocks to file"); addImportExportOption("from", po::value<string>()->value_name("<n>"), "Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'"); addImportExportOption("to", po::value<string>()->value_name("<n>"), "Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or " "'latest'"); addImportExportOption("only", po::value<string>()->value_name("<n>"), "Equivalent to --export-from n --export-to n"); addImportExportOption( "format", po::value<string>()->value_name("<binary/hex/human>"), "Set export format"); addImportExportOption("dont-check", "Prevent checking some block aspects. Faster importing, but to apply only when the data is " "known to be valid"); addImportExportOption("download-snapshot", po::value<string>(&snapshotPath)->value_name("<path>"), "Download Parity Warp Sync snapshot data to the specified path"); addImportExportOption("import-snapshot", po::value<string>()->value_name("<path>"), "Import blockchain and state data from the Parity Warp Sync snapshot\n"); std::string const logChannels = "block blockhdr bq chain client debug discov error ethcap exec host impolite info net " "overlaydb p2pcap peer rlpx rpc snap statedb sync timer tq trace vmtrace warn warpcap watch"; LoggingOptions loggingOptions; po::options_description loggingProgramOptions( createLoggingProgramOptions(c_lineWidth, loggingOptions, logChannels)); po::options_description generalOptions("GENERAL OPTIONS", c_lineWidth); auto addGeneralOption = generalOptions.add_options(); addGeneralOption("data-dir,d", po::value<string>()->value_name("<path>"), ("Load configuration files and keystore from path (default: " + getDataDir().string() + ")").c_str()); addGeneralOption("version,V", "Show the version and exit"); addGeneralOption("help,h", "Show this help message and exit\n"); po::options_description vmOptions = vmProgramOptions(c_lineWidth); po::options_description dbOptions = db::databaseProgramOptions(c_lineWidth); po::options_description minerOptions = MinerCLI::createProgramOptions(c_lineWidth); po::options_description allowedOptions("Allowed options"); allowedOptions.add(clientDefaultMode) .add(clientTransacting) .add(clientMining) .add(minerOptions) .add(clientNetworking) .add(importExportMode) .add(vmOptions) .add(dbOptions) .add(loggingProgramOptions) .add(generalOptions); po::variables_map vm; try { po::parsed_options parsed = po::parse_command_line(argc, argv, allowedOptions); po::store(parsed, vm); po::notify(vm); } catch (po::error const& e) { cerr << e.what() << "\n"; return AlethErrors::ArgumentProcessingFailure; } miner.interpretOptions(vm); if (vm.count("import-snapshot")) { mode = OperationMode::ImportSnapshot; filename = vm["import-snapshot"].as<string>(); } if (vm.count("version")) { version(); return AlethErrors::Success; } if (vm.count("test")) { testingMode = true; disableDiscovery = true; bootstrap = false; } if (vm.count("peers")) peers = vm["peers"].as<int>(); if (vm.count("peer-stretch")) peerStretch = vm["peer-stretch"].as<int>(); if (vm.count("peerset")) { string peersetStr = vm["peerset"].as<string>(); vector<string> peersetList; boost::split(peersetList, peersetStr, boost::is_any_of(",")); bool parsingError = false; const string peerPattern = "^(default|required):(.*)"; regex rx(peerPattern); smatch match; for (auto const& p : peersetList) { if (regex_match(p, match, rx)) { bool required = match.str(1) == "required"; NodeSpec ns(match.str(2)); if (ns.isValid()) preferredNodes[ns.id()] = make_pair(ns.nodeIPEndpoint(), required); else { parsingError = true; break; } } else { parsingError = true; break; } } if (parsingError) { cerr << "Unrecognized peerset: " << peersetStr << "\n"; return AlethErrors::UnrecognizedPeerset; } } if (vm.count("import-presale")) presaleImports.push_back(vm["import-presale"].as<string>()); if (vm.count("admin")) jsonAdmin = vm["admin"].as<string>(); if (vm.count("ipc")) ipc = true; if (vm.count("no-ipc")) ipc = false; if (vm.count("mining")) { string m = vm["mining"].as<string>(); if (isTrue(m)) mining = ~(unsigned)0; else if (isFalse(m)) mining = 0; else try { mining = stoi(m); } catch (...) { cerr << "Unknown --mining option: " << m << "\n"; return AlethErrors::UnknownMiningOption; } } if (vm.count("bootstrap")) bootstrap = true; if (vm.count("no-bootstrap")) bootstrap = false; if (vm.count("no-discovery")) { disableDiscovery = true; bootstrap = false; } if (vm.count("unsafe-transactions")) alwaysConfirm = false; if (vm.count("data-dir")) setDataDir(vm["data-dir"].as<string>()); if (vm.count("ipcpath")) setIpcPath(vm["ipcpath"].as<string>()); if (vm.count("config")) { try { configPath = vm["config"].as<string>(); configJSON = contentsString(configPath.string()); if (configJSON.empty()) { cerr << "Config file not found or empty (" << configPath.string() << ")\n"; return AlethErrors::ConfigFileEmptyOrNotFound; } } catch (...) { cerr << "Bad --config option: " << vm["config"].as<string>() << "\n"; return AlethErrors::BadConfigOption; } } if (vm.count("extra-data")) { try { extraData = fromHex(vm["extra-data"].as<string>()); } catch (...) { cerr << "Bad " << "--extra-data" << " option: " << vm["extra-data"].as<string>() << "\n"; return AlethErrors::BadExtraDataOption; } } if (vm.count("mainnet")) { chainParams = ChainParams(genesisInfo(eth::Network::MainNetwork), genesisStateRoot(eth::Network::MainNetwork)); chainConfigIsSet = true; } if (vm.count("ropsten")) { chainParams = ChainParams(genesisInfo(eth::Network::Ropsten), genesisStateRoot(eth::Network::Ropsten)); chainConfigIsSet = true; } if (vm.count("ask")) { try { askPrice = vm["ask"].as<u256>(); } catch (...) { cerr << "Bad --ask option: " << vm["ask"].as<string>() << "\n"; return AlethErrors::BadAskOption; } } if (vm.count("bid")) { try { bidPrice = vm["bid"].as<u256>(); } catch (...) { cerr << "Bad --bid option: " << vm["bid"].as<string>() << "\n"; return AlethErrors::BadBidOption; } } if (vm.count("listen-ip")) { listenIP = vm["listen-ip"].as<string>(); listenSet = true; } if (vm.count("listen")) { listenPort = vm["listen"].as<unsigned short>(); listenSet = true; } if (vm.count("public-ip")) { publicIP = vm["public-ip"].as<string>(); } if (vm.count("remote")) { string host = vm["remote"].as<string>(); string::size_type found = host.find_first_of(':'); if (found != std::string::npos) { remoteHost = host.substr(0, found); remotePort = (short)atoi(host.substr(found + 1, host.length()).c_str()); } else remoteHost = host; } if (vm.count("port")) { remotePort = vm["port"].as<short>(); } if (vm.count("import")) { mode = OperationMode::Import; filename = vm["import"].as<string>(); } if (vm.count("export")) { mode = OperationMode::Export; filename = vm["export"].as<string>(); } if (vm.count("password")) passwordsToNote.push_back(vm["password"].as<string>()); if (vm.count("master")) { masterPassword = vm["master"].as<string>(); masterSet = true; } if (vm.count("dont-check")) safeImport = true; if (vm.count("format")) { string m = vm["format"].as<string>(); if (m == "binary") exportFormat = Format::Binary; else if (m == "hex") exportFormat = Format::Hex; else if (m == "human") exportFormat = Format::Human; else { cerr << "Bad " << "--format" << " option: " << m << "\n"; return AlethErrors::BadFormatOption; } } if (vm.count("to")) exportTo = vm["to"].as<string>(); if (vm.count("from")) exportFrom = vm["from"].as<string>(); if (vm.count("only")) exportTo = exportFrom = vm["only"].as<string>(); #if ETH_MINIUPNPC if (vm.count("upnp")) { string m = vm["upnp"].as<string>(); if (isTrue(m)) upnp = true; else if (isFalse(m)) upnp = false; else { cerr << "Bad " << "--upnp" << " option: " << m << "\n"; return AlethErrors::BadUpnpOption; } } #endif if (vm.count("network-id")) try { networkID = vm["network-id"].as<unsigned>(); } catch (...) { cerr << "Bad " << "--network-id" << " option: " << vm["network-id"].as<string>() << "\n"; return AlethErrors::BadNetworkIdOption; } if (vm.count("kill")) withExisting = WithExisting::Kill; if (vm.count("rebuild")) withExisting = WithExisting::Verify; if (vm.count("rescue")) withExisting = WithExisting::Rescue; if (vm.count("address")) try { author = vm["address"].as<Address>(); } catch (BadHexCharacter&) { cerr << "Bad hex in " << "--address" << " option: " << vm["address"].as<string>() << "\n"; return AlethErrors::BadHexValueInAddressOption; } catch (...) { cerr << "Bad " << "--address" << " option: " << vm["address"].as<string>() << "\n"; return AlethErrors::BadAddressOption; } if ((vm.count("import-secret"))) { Secret s(fromHex(vm["import-secret"].as<string>())); toImport.emplace_back(s); } if (vm.count("import-session-secret")) { Secret s(fromHex(vm["import-session-secret"].as<string>())); toImport.emplace_back(s); } if (vm.count("help")) { cout << "NAME:\n" << " aleth " << Version << '\n' << "USAGE:\n" << " aleth [options]\n\n" << "WALLET USAGE:\n"; AccountManager::streamAccountHelp(cout); AccountManager::streamWalletHelp(cout); cout << clientDefaultMode << clientTransacting << clientNetworking << clientMining << minerOptions; cout << importExportMode << dbOptions << vmOptions << loggingProgramOptions << generalOptions; return AlethErrors::Success; } if (!configJSON.empty()) { try { chainParams = chainParams.loadConfig(configJSON, {}, configPath); chainConfigIsSet = true; } catch (...) { cerr << "provided configuration is not well-formatted\n"; cerr << "well-formatted sample: \n" << genesisInfo(eth::Network::MainNetworkTest) << "\n"; return AlethErrors::ConfigFileInvalid; } } setupLogging(loggingOptions); if (!chainConfigIsSet) // default to mainnet if not already set with any of `--mainnet`, `--ropsten`, `--genesis`, `--config` chainParams = ChainParams(genesisInfo(eth::Network::MainNetwork), genesisStateRoot(eth::Network::MainNetwork)); if (loggingOptions.verbosity > 0) cout << EthGrayBold "aleth, a C++ Ethereum client" EthReset << "\n"; miner.execute(); fs::path secretsPath; if (testingMode) secretsPath = boost::filesystem::path(getDataDir()) / "keystore"; else secretsPath = SecretStore::defaultPath(); KeyManager keyManager(KeyManager::defaultPath(), secretsPath); for (auto const& s: passwordsToNote) keyManager.notePassword(s); // the first value is deprecated (never used) writeFile(configFile, rlpList(author, author)); string logbuf; std::string additional; auto getPassword = [&](string const& prompt) { bool s = g_silence; g_silence = true; cout << "\n"; string ret = dev::getPassword(prompt); g_silence = s; return ret; }; auto getResponse = [&](string const& prompt, unordered_set<string> const& acceptable) { bool s = g_silence; g_silence = true; cout << "\n"; string ret; while (true) { cout << prompt; getline(cin, ret); if (acceptable.count(ret)) break; cout << "Invalid response: " << ret << "\n"; } g_silence = s; return ret; }; auto getAccountPassword = [&](Address const& a){ return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): "); }; auto netPrefs = publicIP.empty() ? NetworkConfig(listenIP, listenPort, upnp) : NetworkConfig(publicIP, listenIP ,listenPort, upnp); netPrefs.discovery = !disableDiscovery; netPrefs.allowLocalDiscovery = allowLocalDiscovery; netPrefs.pin = vm.count("pin") != 0; auto nodesState = contents(getDataDir() / fs::path(c_networkConfigFileName)); if (testingMode) chainParams.allowFutureBlocks = true; dev::WebThreeDirect web3(WebThreeDirect::composeClientVersion("aleth"), db::databasePath(), snapshotPath, chainParams, withExisting, netPrefs, &nodesState, testingMode); if (!extraData.empty()) web3.ethereum()->setExtraData(extraData); auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); if (s.size() == 64 || (s.size() == 66 && s.substr(0, 2) == "0x")) return web3.ethereum()->blockChain().number(h256(s)); try { return stol(s); } catch (...) { cerr << "Bad block number/hash option: " << s << "\n"; return AlethErrors::BadBlockNumberHashOption; } }; if (mode == OperationMode::Export) { ofstream fout(filename, std::ofstream::binary); ostream& out = (filename.empty() || filename == "--") ? cout : fout; unsigned last = toNumber(exportTo); for (unsigned i = toNumber(exportFrom); i <= last; ++i) { bytes block = web3.ethereum()->blockChain().block(web3.ethereum()->blockChain().numberHash(i)); switch (exportFormat) { case Format::Binary: out.write((char const*)block.data(), block.size()); break; case Format::Hex: out << toHex(block) << "\n"; break; case Format::Human: out << RLP(block) << "\n"; break; default:; } } return AlethErrors::Success; } if (mode == OperationMode::Import) { ifstream fin(filename, std::ifstream::binary); istream& in = (filename.empty() || filename == "--") ? cin : fin; unsigned alreadyHave = 0; unsigned good = 0; unsigned futureTime = 0; unsigned unknownParent = 0; unsigned bad = 0; chrono::steady_clock::time_point t = chrono::steady_clock::now(); double last = 0; unsigned lastImported = 0; unsigned imported = 0; while (in.peek() != -1) { bytes block(8); in.read((char*)block.data(), 8); block.resize(RLP(block, RLP::LaissezFaire).actualSize()); in.read((char*)block.data() + 8, block.size() - 8); switch (web3.ethereum()->queueBlock(block, safeImport)) { case ImportResult::Success: good++; break; case ImportResult::AlreadyKnown: alreadyHave++; break; case ImportResult::UnknownParent: unknownParent++; break; case ImportResult::FutureTimeUnknown: unknownParent++; futureTime++; break; case ImportResult::FutureTimeKnown: futureTime++; break; default: bad++; break; } // sync chain with queue tuple<ImportRoute, bool, unsigned> r = web3.ethereum()->syncQueue(10); imported += get<2>(r); double e = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - t).count() / 1000.0; if ((unsigned)e >= last + 10) { auto i = imported - lastImported; auto d = e - last; cout << i << " more imported at " << (round(i * 10 / d) / 10) << " blocks/s. " << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << "\n"; last = (unsigned)e; lastImported = imported; } } bool moreToImport = true; while (moreToImport) { this_thread::sleep_for(chrono::seconds(1)); tie(ignore, moreToImport, ignore) = web3.ethereum()->syncQueue(100000); } double e = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - t).count() / 1000.0; cout << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")\n"; return AlethErrors::Success; } try { if (keyManager.exists()) { if (!keyManager.load(masterPassword) && masterSet) { while (true) { masterPassword = getPassword("Please enter your MASTER password: "******"The password you entered is incorrect. If you have forgotten your password, and you wish to start afresh, manually remove the file: " << (getDataDir("ethereum") / fs::path("keys.info")).string() << "\n"; } } } else { if (masterSet) keyManager.create(masterPassword); else keyManager.create(std::string()); } } catch(...) { cerr << "Error initializing key manager: " << boost::current_exception_diagnostic_information() << "\n"; return AlethErrors::KeyManagerInitializationFailure; } for (auto const& presale: presaleImports) importPresale(keyManager, presale, [&](){ return getPassword("Enter your wallet password for " + presale + ": "); }); for (auto const& s: toImport) { keyManager.import(s, "Imported key (UNSAFE)"); } cout << "aleth " << Version << "\n"; if (mode == OperationMode::ImportSnapshot) { try { auto stateImporter = web3.ethereum()->createStateImporter(); auto blockChainImporter = web3.ethereum()->createBlockChainImporter(); SnapshotImporter importer(*stateImporter, *blockChainImporter); auto snapshotStorage(createSnapshotStorage(filename)); importer.import(*snapshotStorage, web3.ethereum()->blockChain().genesisHash()); // continue with regular sync from the snapshot block } catch (...) { cerr << "Error during importing the snapshot: " << boost::current_exception_diagnostic_information() << endl; return AlethErrors::SnapshotImportFailure; } } web3.setIdealPeerCount(peers); web3.setPeerStretch(peerStretch); std::shared_ptr<eth::TrivialGasPricer> gasPricer = make_shared<eth::TrivialGasPricer>(askPrice, bidPrice); Client& c = *(web3.ethereum()); c.setGasPricer(gasPricer); c.setSealer(miner.minerType()); c.setAuthor(author); if (networkID != NoNetworkID) c.setNetworkId(networkID); auto renderFullAddress = [&](Address const& _a) -> std::string { return toUUID(keyManager.uuid(_a)) + " - " + _a.hex(); }; if (author) cout << "Mining Beneficiary: " << renderFullAddress(author) << "\n"; if (bootstrap || !remoteHost.empty() || !disableDiscovery || listenSet || !preferredNodes.empty()) { web3.startNetwork(); cout << "Node ID: " << web3.enode() << "\n"; } else cout << "Networking disabled. To start, use netstart or pass --bootstrap or a remote host.\n"; unique_ptr<rpc::SessionManager> sessionManager; unique_ptr<SimpleAccountHolder> accountHolder; unique_ptr<ModularServer<>> jsonrpcIpcServer; AddressHash allowedDestinations; std::function<bool(TransactionSkeleton const&, bool)> authenticator; if (testingMode) authenticator = [](TransactionSkeleton const&, bool) -> bool { return true; }; else authenticator = [&](TransactionSkeleton const& _t, bool isProxy) -> bool { // "unlockAccount" functionality is done in the AccountHolder. if (!alwaysConfirm || allowedDestinations.count(_t.to)) return true; string r = getResponse(_t.userReadable(isProxy, [&](TransactionSkeleton const& _t) -> pair<bool, string> { h256 contractCodeHash = web3.ethereum()->postState().codeHash(_t.to); if (contractCodeHash == EmptySHA3) return std::make_pair(false, std::string()); // TODO: actually figure out the natspec. we'll need the natspec database here though. return std::make_pair(true, std::string()); }, [&](Address const& _a) { return _a.hex(); } ) + "\nEnter yes/no/always (always to this address): ", {"yes", "n", "N", "no", "NO", "always"}); if (r == "always") allowedDestinations.insert(_t.to); return r == "yes" || r == "always"; }; ExitHandler exitHandler; if (ipc) { using FullServer = ModularServer< rpc::EthFace, rpc::NetFace, rpc::Web3Face, rpc::PersonalFace, rpc::AdminEthFace, rpc::AdminNetFace, rpc::DebugFace, rpc::TestFace >; sessionManager.reset(new rpc::SessionManager()); accountHolder.reset(new SimpleAccountHolder([&](){ return web3.ethereum(); }, getAccountPassword, keyManager, authenticator)); auto ethFace = new rpc::Eth(*web3.ethereum(), *accountHolder.get()); rpc::TestFace* testEth = nullptr; if (testingMode) testEth = new rpc::Test(*web3.ethereum()); jsonrpcIpcServer.reset(new FullServer( ethFace, new rpc::Net(web3), new rpc::Web3(web3.clientVersion()), new rpc::Personal(keyManager, *accountHolder, *web3.ethereum()), new rpc::AdminEth(*web3.ethereum(), *gasPricer.get(), keyManager, *sessionManager.get()), new rpc::AdminNet(web3, *sessionManager.get()), new rpc::Debug(*web3.ethereum()), testEth )); auto ipcConnector = new IpcServer("geth"); jsonrpcIpcServer->addConnector(ipcConnector); ipcConnector->StartListening(); if (jsonAdmin.empty()) jsonAdmin = sessionManager->newSession(rpc::SessionPermissions{{rpc::Privilege::Admin}}); else sessionManager->addSession(jsonAdmin, rpc::SessionPermissions{{rpc::Privilege::Admin}}); cout << "JSONRPC Admin Session Key: " << jsonAdmin << "\n"; } if (web3.isNetworkStarted()) { for (auto const& p: preferredNodes) if (p.second.second) web3.requirePeer(p.first, p.second.first); else web3.addNode(p.first, p.second.first); if (bootstrap) for (auto const& i : defaultBootNodes()) web3.requirePeer(i.first, i.second); if (!remoteHost.empty()) web3.addNode(p2p::NodeID(), remoteHost + ":" + toString(remotePort)); } signal(SIGABRT, &ExitHandler::exitHandler); signal(SIGTERM, &ExitHandler::exitHandler); signal(SIGINT, &ExitHandler::exitHandler); unsigned n = c.blockChain().details().number; if (mining) c.startSealing(); while (!exitHandler.shouldExit()) stopSealingAfterXBlocks(&c, n, mining); if (jsonrpcIpcServer.get()) jsonrpcIpcServer->StopListening(); if (web3.isNetworkStarted()) { web3.stopNetwork(); auto netData = web3.saveNetwork(); if (!netData.empty()) writeFile(getDataDir() / fs::path(c_networkConfigFileName), netData); } return AlethErrors::Success; }