// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers // // This file is part of Bytecoin. // // Bytecoin 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. // // Bytecoin 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 Bytecoin. If not, see . #include "version.h" #include #include #include "DaemonCommandsHandler.h" #include "Common/SignalHandler.h" #include "Common/PathTools.h" #include "crypto/hash.h" #include "CryptoNoteCore/Core.h" #include "CryptoNoteCore/CoreConfig.h" #include "CryptoNoteCore/Currency.h" #include "CryptoNoteCore/MinerConfig.h" #include "CryptoNoteProtocol/CryptoNoteProtocolHandler.h" #include "P2p/NetNode.h" #include "P2p/NetNodeConfig.h" #include "Rpc/RpcServer.h" #include "Rpc/RpcServerConfig.h" #include "version.h" #include #if defined(WIN32) #include #endif using Common::JsonValue; using namespace CryptoNote; using namespace Logging; namespace po = boost::program_options; namespace { const command_line::arg_descriptor arg_config_file = {"config-file", "Specify configuration file", std::string(CryptoNote::CRYPTONOTE_NAME) + ".conf"}; const command_line::arg_descriptor arg_os_version = {"os-version", ""}; const command_line::arg_descriptor arg_log_file = {"log-file", "", ""}; const command_line::arg_descriptor arg_log_level = {"log-level", "", 2}; // info level const command_line::arg_descriptor arg_console = {"no-console", "Disable daemon console commands"}; const command_line::arg_descriptor arg_testnet_on = {"testnet", "Used to deploy test nets. Checkpoints and hardcoded seeds are ignored, " "network id is changed. Use it with --data-dir flag. The wallet must be launched with --testnet flag.", false}; } bool command_line_preprocessor(const boost::program_options::variables_map& vm, LoggerRef& logger); JsonValue buildLoggerConfiguration(Level level, const std::string& logfile) { JsonValue loggerConfiguration(JsonValue::OBJECT); loggerConfiguration.insert("globalLevel", static_cast(level)); JsonValue& cfgLoggers = loggerConfiguration.insert("loggers", JsonValue::ARRAY); JsonValue& fileLogger = cfgLoggers.pushBack(JsonValue::OBJECT); fileLogger.insert("type", "file"); fileLogger.insert("filename", logfile); fileLogger.insert("level", static_cast(TRACE)); JsonValue& consoleLogger = cfgLoggers.pushBack(JsonValue::OBJECT); consoleLogger.insert("type", "console"); consoleLogger.insert("level", static_cast(TRACE)); consoleLogger.insert("pattern", "%T %L "); return loggerConfiguration; } int main(int argc, char* argv[]) { #ifdef WIN32 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif LoggerManager logManager; LoggerRef logger(logManager, "daemon"); try { po::options_description desc_cmd_only("Command line options"); po::options_description desc_cmd_sett("Command line options and settings options"); command_line::add_arg(desc_cmd_only, command_line::arg_help); command_line::add_arg(desc_cmd_only, command_line::arg_version); command_line::add_arg(desc_cmd_only, arg_os_version); // tools::get_default_data_dir() can't be called during static initialization command_line::add_arg(desc_cmd_only, command_line::arg_data_dir, Tools::getDefaultDataDirectory()); command_line::add_arg(desc_cmd_only, arg_config_file); command_line::add_arg(desc_cmd_sett, arg_log_file); command_line::add_arg(desc_cmd_sett, arg_log_level); command_line::add_arg(desc_cmd_sett, arg_console); command_line::add_arg(desc_cmd_sett, arg_testnet_on); RpcServerConfig::initOptions(desc_cmd_sett); CoreConfig::initOptions(desc_cmd_sett); NetNodeConfig::initOptions(desc_cmd_sett); MinerConfig::initOptions(desc_cmd_sett); po::options_description desc_options("Allowed options"); desc_options.add(desc_cmd_only).add(desc_cmd_sett); po::variables_map vm; bool r = command_line::handle_error_helper(desc_options, [&]() { po::store(po::parse_command_line(argc, argv, desc_options), vm); if (command_line::get_arg(vm, command_line::arg_help)) { std::cout << CryptoNote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL; std::cout << desc_options << std::endl; return false; } std::string data_dir = command_line::get_arg(vm, command_line::arg_data_dir); std::string config = command_line::get_arg(vm, arg_config_file); boost::filesystem::path data_dir_path(data_dir); boost::filesystem::path config_path(config); if (!config_path.has_parent_path()) { config_path = data_dir_path / config_path; } boost::system::error_code ec; if (boost::filesystem::exists(config_path, ec)) { po::store(po::parse_config_file(config_path.string().c_str(), desc_cmd_sett), vm); } po::notify(vm); return true; }); if (!r) return 1; auto modulePath = Common::NativePathToGeneric(argv[0]); auto cfgLogFile = Common::NativePathToGeneric(command_line::get_arg(vm, arg_log_file)); if (cfgLogFile.empty()) { cfgLogFile = Common::ReplaceExtenstion(modulePath, ".log"); } else { if (!Common::HasParentPath(cfgLogFile)) { cfgLogFile = Common::CombinePath(Common::GetPathDirectory(modulePath), cfgLogFile); } } Level cfgLogLevel = static_cast(static_cast(Logging::ERROR) + command_line::get_arg(vm, arg_log_level)); // configure logging logManager.configure(buildLoggerConfiguration(cfgLogLevel, cfgLogFile)); logger(INFO) << CryptoNote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG; if (command_line_preprocessor(vm, logger)) { return 0; } logger(INFO) << "Module folder: " << argv[0]; bool testnet_mode = command_line::get_arg(vm, arg_testnet_on); if (testnet_mode) { logger(INFO) << "Starting in testnet mode!"; } //create objects and link them CryptoNote::CurrencyBuilder currencyBuilder(logManager); currencyBuilder.testnet(testnet_mode); CryptoNote::Currency currency = currencyBuilder.currency(); CryptoNote::core ccore(currency, nullptr, logManager); CryptoNote::Checkpoints checkpoints(logManager); for (const auto& cp : CryptoNote::CHECKPOINTS) { checkpoints.add_checkpoint(cp.height, cp.blockId); } if (!testnet_mode) { ccore.set_checkpoints(std::move(checkpoints)); } CoreConfig coreConfig; coreConfig.init(vm); NetNodeConfig netNodeConfig; netNodeConfig.init(vm); netNodeConfig.setTestnet(testnet_mode); MinerConfig minerConfig; minerConfig.init(vm); RpcServerConfig rpcConfig; rpcConfig.init(vm); System::Dispatcher dispatcher; CryptoNote::CryptoNoteProtocolHandler cprotocol(currency, dispatcher, ccore, nullptr, logManager); CryptoNote::NodeServer p2psrv(dispatcher, cprotocol, logManager); CryptoNote::RpcServer rpcServer(dispatcher, logManager, ccore, p2psrv); cprotocol.set_p2p_endpoint(&p2psrv); ccore.set_cryptonote_protocol(&cprotocol); DaemonCommandsHandler dch(ccore, p2psrv, logManager); // initialize objects logger(INFO) << "Initializing p2p server..."; if (!p2psrv.init(netNodeConfig)) { logger(ERROR, BRIGHT_RED) << "Failed to initialize p2p server."; return 1; } logger(INFO) << "P2p server initialized OK"; //logger(INFO) << "Initializing core rpc server..."; //if (!rpc_server.init(vm)) { // logger(ERROR, BRIGHT_RED) << "Failed to initialize core rpc server."; // return 1; //} // logger(INFO, BRIGHT_GREEN) << "Core rpc server initialized OK on port: " << rpc_server.get_binded_port(); // initialize core here logger(INFO) << "Initializing core..."; if (!ccore.init(coreConfig, minerConfig, true)) { logger(ERROR, BRIGHT_RED) << "Failed to initialize core"; return 1; } logger(INFO) << "Core initialized OK"; // start components if (!command_line::has_arg(vm, arg_console)) { dch.start_handling(); } logger(INFO) << "Starting core rpc server on address " << rpcConfig.getBindAddress(); rpcServer.start(rpcConfig.bindIp, rpcConfig.bindPort); logger(INFO) << "Core rpc server started ok"; Tools::SignalHandler::install([&dch, &p2psrv] { dch.stop_handling(); p2psrv.sendStopSignal(); }); logger(INFO) << "Starting p2p net loop..."; p2psrv.run(); logger(INFO) << "p2p net loop stopped"; dch.stop_handling(); //stop components logger(INFO) << "Stopping core rpc server..."; rpcServer.stop(); //deinitialize components logger(INFO) << "Deinitializing core..."; ccore.deinit(); logger(INFO) << "Deinitializing p2p..."; p2psrv.deinit(); ccore.set_cryptonote_protocol(NULL); cprotocol.set_p2p_endpoint(NULL); } catch (const std::exception& e) { logger(ERROR, BRIGHT_RED) << "Exception: " << e.what(); return 1; } logger(INFO) << "Node stopped."; return 0; } bool command_line_preprocessor(const boost::program_options::variables_map &vm, LoggerRef &logger) { bool exit = false; if (command_line::get_arg(vm, command_line::arg_version)) { std::cout << CryptoNote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL; exit = true; } if (command_line::get_arg(vm, arg_os_version)) { std::cout << "OS: " << Tools::get_os_version_string() << ENDL; exit = true; } if (exit) { return true; } return false; }