diff --git a/nano/nano_node/daemon.cpp b/nano/nano_node/daemon.cpp index bbb46335c9..6752bde692 100644 --- a/nano/nano_node/daemon.cpp +++ b/nano/nano_node/daemon.cpp @@ -74,158 +74,156 @@ void nano::daemon::run (std::filesystem::path const & data_path, nano::node_flag nano::network_params network_params{ nano::network_constants::active_network }; nano::daemon_config config{ data_path, network_params }; - auto error = nano::read_node_config_toml (data_path, config, flags.config_overrides); + if (auto error = nano::read_node_config_toml (data_path, config, flags.config_overrides)) + { + logger.critical (nano::log::type::daemon, "Error deserializing node config: {}", error.get_message ()); + std::exit (1); + } + if (auto error = nano::flags_config_conflicts (flags, config.node)) + { + logger.critical (nano::log::type::daemon, "Error parsing command line options: {}", error.message ()); + std::exit (1); + } nano::set_use_memory_pools (config.node.use_memory_pools); - if (!error) + std::shared_ptr io_ctx = std::make_shared (); + + auto opencl = nano::opencl_work::create (config.opencl_enable, config.opencl, logger, config.node.network_params.work); + nano::opencl_work_func_t opencl_work_func; + if (opencl) { - error = nano::flags_config_conflicts (flags, config.node); + opencl_work_func = [&opencl] (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { + return opencl->generate_work (version_a, root_a, difficulty_a, ticket_a); + }; } - if (!error) + nano::work_pool opencl_work (config.node.network_params.network, config.node.work_threads, config.node.pow_sleep_interval, opencl_work_func); + try { - std::shared_ptr io_ctx = std::make_shared (); + // This avoids a blank prompt during any node initialization delays + logger.info (nano::log::type::daemon, "Starting up Nano node..."); - auto opencl = nano::opencl_work::create (config.opencl_enable, config.opencl, logger, config.node.network_params.work); - nano::opencl_work_func_t opencl_work_func; - if (opencl) + // Print info about number of logical cores detected, those are used to decide how many IO, worker and signature checker threads to spawn + logger.info (nano::log::type::daemon, "Hardware concurrency: {} ( configured: {} )", std::thread::hardware_concurrency (), nano::hardware_concurrency ()); + + nano::set_file_descriptor_limit (OPEN_FILE_DESCRIPTORS_LIMIT); + auto const file_descriptor_limit = nano::get_file_descriptor_limit (); + logger.info (nano::log::type::daemon, "File descriptors limit: {}", file_descriptor_limit); + if (file_descriptor_limit < OPEN_FILE_DESCRIPTORS_LIMIT) { - opencl_work_func = [&opencl] (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic & ticket_a) { - return opencl->generate_work (version_a, root_a, difficulty_a, ticket_a); - }; + logger.warn (nano::log::type::daemon, "File descriptors limit is lower than the {} recommended. Node was unable to change it.", OPEN_FILE_DESCRIPTORS_LIMIT); } - nano::work_pool opencl_work (config.node.network_params.network, config.node.work_threads, config.node.pow_sleep_interval, opencl_work_func); - try - { - // This avoids a blank prompt during any node initialization delays - logger.info (nano::log::type::daemon, "Starting up Nano node..."); - - // Print info about number of logical cores detected, those are used to decide how many IO, worker and signature checker threads to spawn - logger.info (nano::log::type::daemon, "Hardware concurrency: {} ( configured: {} )", std::thread::hardware_concurrency (), nano::hardware_concurrency ()); - nano::set_file_descriptor_limit (OPEN_FILE_DESCRIPTORS_LIMIT); - auto const file_descriptor_limit = nano::get_file_descriptor_limit (); - logger.info (nano::log::type::daemon, "File descriptors limit: {}", file_descriptor_limit); - if (file_descriptor_limit < OPEN_FILE_DESCRIPTORS_LIMIT) - { - logger.warn (nano::log::type::daemon, "File descriptors limit is lower than the {} recommended. Node was unable to change it.", OPEN_FILE_DESCRIPTORS_LIMIT); - } - - // for the daemon start up, if the user hasn't specified a port in - // the config, we must use the default peering port for the network - // - if (!config.node.peering_port.has_value ()) - { - config.node.peering_port = network_params.network.default_node_port; - } + // for the daemon start up, if the user hasn't specified a port in + // the config, we must use the default peering port for the network + // + if (!config.node.peering_port.has_value ()) + { + config.node.peering_port = network_params.network.default_node_port; + } - auto node = std::make_shared (io_ctx, data_path, config.node, opencl_work, flags); - if (!node->init_error ()) - { - auto network_label = node->network_params.network.get_current_network_as_string (); - std::time_t dateTime = std::time (nullptr); + auto node = std::make_shared (io_ctx, data_path, config.node, opencl_work, flags); + if (!node->init_error ()) + { + auto network_label = node->network_params.network.get_current_network_as_string (); + std::time_t dateTime = std::time (nullptr); - logger.info (nano::log::type::daemon, "Network: {}", network_label); - logger.info (nano::log::type::daemon, "Version: {}", NANO_VERSION_STRING); - logger.info (nano::log::type::daemon, "Data path: '{}'", node->application_path.string ()); - logger.info (nano::log::type::daemon, "Build info: {}", BUILD_INFO); - logger.info (nano::log::type::daemon, "Database backend: {}", node->store.vendor_get ()); - logger.info (nano::log::type::daemon, "Start time: {:%c} UTC", fmt::gmtime (dateTime)); + logger.info (nano::log::type::daemon, "Network: {}", network_label); + logger.info (nano::log::type::daemon, "Version: {}", NANO_VERSION_STRING); + logger.info (nano::log::type::daemon, "Data path: '{}'", node->application_path.string ()); + logger.info (nano::log::type::daemon, "Build info: {}", BUILD_INFO); + logger.info (nano::log::type::daemon, "Database backend: {}", node->store.vendor_get ()); + logger.info (nano::log::type::daemon, "Start time: {:%c} UTC", fmt::gmtime (dateTime)); - // IO context runner should be started first and stopped last to allow asio handlers to execute during node start/stop - runner = std::make_unique (io_ctx, logger, node->config.io_threads, nano::thread_role::name::io_daemon); + // IO context runner should be started first and stopped last to allow asio handlers to execute during node start/stop + runner = std::make_unique (io_ctx, logger, node->config.io_threads, nano::thread_role::name::io_daemon); - node->start (); + node->start (); - std::atomic stopped{ false }; + std::atomic stopped{ false }; - std::unique_ptr ipc_server = std::make_unique (*node, config.rpc); - std::unique_ptr rpc_process; - std::unique_ptr rpc_handler; - std::shared_ptr rpc; + std::unique_ptr ipc_server = std::make_unique (*node, config.rpc); + std::unique_ptr rpc_process; + std::unique_ptr rpc_handler; + std::shared_ptr rpc; - if (config.rpc_enable) + if (config.rpc_enable) + { + // In process RPC + if (!config.rpc.child_process.enable) { - if (!config.rpc.child_process.enable) + auto stop_callback = [this, &stopped] () { + logger.warn (nano::log::type::daemon, "RPC stop request received, stopping..."); + stopped = true; + stopped.notify_all (); + }; + + // Launch rpc in-process + nano::rpc_config rpc_config{ config.node.network_params.network }; + if (auto error = nano::read_rpc_config_toml (data_path, rpc_config, flags.rpc_config_overrides)) { - auto stop_callback = [this, &stopped] () { - logger.warn (nano::log::type::daemon, "RPC stop request received, stopping..."); - stopped = true; - stopped.notify_all (); - }; - - // Launch rpc in-process - nano::rpc_config rpc_config{ config.node.network_params.network }; - auto error = nano::read_rpc_config_toml (data_path, rpc_config, flags.rpc_config_overrides); - if (error) - { - std::cout << error.get_message () << std::endl; - std::exit (1); - } - - rpc_handler = std::make_unique (*node, *ipc_server, config.rpc, stop_callback); - rpc = nano::get_rpc (io_ctx, rpc_config, *rpc_handler); - rpc->start (); + logger.critical (nano::log::type::daemon, "Error deserializing RPC config: {}", error.get_message ()); + std::exit (1); } - else + + rpc_handler = std::make_unique (*node, *ipc_server, config.rpc, stop_callback); + rpc = nano::get_rpc (io_ctx, rpc_config, *rpc_handler); + rpc->start (); + } + else + { + // Spawn a child rpc process + if (!std::filesystem::exists (config.rpc.child_process.rpc_path)) { - // Spawn a child rpc process - if (!std::filesystem::exists (config.rpc.child_process.rpc_path)) - { - throw std::runtime_error (std::string ("RPC is configured to spawn a new process however the file cannot be found at: ") + config.rpc.child_process.rpc_path); - } + throw std::runtime_error (std::string ("RPC is configured to spawn a new process however the file cannot be found at: ") + config.rpc.child_process.rpc_path); + } - auto network = node->network_params.network.get_current_network_as_string (); + auto network = node->network_params.network.get_current_network_as_string (); - rpc_process = std::make_unique (config.rpc.child_process.rpc_path, "--daemon", "--data_path", data_path.string (), "--network", network); - } - debug_assert (rpc || rpc_process); + rpc_process = std::make_unique (config.rpc.child_process.rpc_path, "--daemon", "--data_path", data_path.string (), "--network", network); } + debug_assert (rpc || rpc_process); + } - auto signal_handler = [this, &stopped] (int signum) { - logger.warn (nano::log::type::daemon, "Interrupt signal received ({}), stopping...", to_signal_name (signum)); - stopped = true; - stopped.notify_all (); - }; - - nano::signal_manager sigman; - // keep trapping Ctrl-C to avoid a second Ctrl-C interrupting tasks started by the first - sigman.register_signal_handler (SIGINT, signal_handler, true); - // sigterm is less likely to come in bunches so only trap it once - sigman.register_signal_handler (SIGTERM, signal_handler, false); + auto signal_handler = [this, &stopped] (int signum) { + logger.warn (nano::log::type::daemon, "Interrupt signal received ({}), stopping...", to_signal_name (signum)); + stopped = true; + stopped.notify_all (); + }; - // Keep running until stopped flag is set - stopped.wait (false); + nano::signal_manager sigman; + // keep trapping Ctrl-C to avoid a second Ctrl-C interrupting tasks started by the first + sigman.register_signal_handler (SIGINT, signal_handler, true); + // sigterm is less likely to come in bunches so only trap it once + sigman.register_signal_handler (SIGTERM, signal_handler, false); - logger.info (nano::log::type::daemon, "Stopping..."); + // Keep running until stopped flag is set + stopped.wait (false); - if (rpc) - { - rpc->stop (); - } - ipc_server->stop (); - node->stop (); - io_ctx->stop (); - runner->join (); + logger.info (nano::log::type::daemon, "Stopping..."); - if (rpc_process) - { - rpc_process->wait (); - } + if (rpc) + { + rpc->stop (); } - else + ipc_server->stop (); + node->stop (); + io_ctx->stop (); + runner->join (); + + if (rpc_process) { - logger.critical (nano::log::type::daemon, "Error initializing node"); + rpc_process->wait (); } } - catch (std::runtime_error const & e) + else { - logger.critical (nano::log::type::daemon, "Error while running node: {}", e.what ()); + logger.critical (nano::log::type::daemon, "Error initializing node"); } } - else + catch (std::runtime_error const & e) { - logger.critical (nano::log::type::daemon, "Error deserializing config: {}", error.get_message ()); + logger.critical (nano::log::type::daemon, "Error while running node: {}", e.what ()); } logger.info (nano::log::type::daemon, "Daemon stopped");