diff --git a/libraries/custom_appbase/include/sysio/chain/wire_application.hpp b/libraries/custom_appbase/include/sysio/chain/wire_application.hpp new file mode 100644 index 0000000000..b37bfbfd52 --- /dev/null +++ b/libraries/custom_appbase/include/sysio/chain/wire_application.hpp @@ -0,0 +1,303 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Standard setup for wire applications. +*/ +namespace sysio::chain { + +struct wire_application_config { + bool enable_logging_config = true; + bool enable_deep_mind_logging = false; + bool enable_resource_monitor = true; + bool sighup_loads_logging_config = true; + uint16_t default_http_port = 8888; +}; + +enum return_codes { + OTHER_FAIL = -2, + INITIALIZE_FAIL = -1, + SUCCESS = 0, + BAD_ALLOC = 1, + DATABASE_DIRTY = 2, + FIXED_REVERSIBLE = SUCCESS, + EXTRACTED_GENESIS = SUCCESS, + NODE_MANAGEMENT_SUCCESS = 5 +}; + +namespace detail { + +using namespace appbase; + +void log_non_default_options(const std::vector>& options) { + using namespace std::string_literals; + auto mask_private = [](const string& v) -> std::string { + if (auto parts = fc::split(v, ','); parts.size() > 1) { + return std::accumulate(std::next(parts.begin()), std::prev(parts.end()), parts[0], + [](const string& acc, const string& part) { return acc + "," + part; }) + ",***"; + } + return "***"s; + }; + + string result; + for (const auto& op : options) { + bool mask = false; + if (op.string_key == "peer-private-key"s + || op.string_key == "p2p-auto-bp-peer"s) { + mask = true; + } + std::string v; + for (auto i = op.value.cbegin(), b = op.value.cbegin(), e = op.value.cend(); i != e; ++i) { + if (i != b) + v += ", "; + if (op.string_key == "signature-provider"s) + v += mask_private(*i); + else if (mask) + v += "***"; + else + v += *i; + } + + if (!result.empty()) + result += ", "; + + if (v.empty()) { + result += op.string_key; + } else { + result += op.string_key; + result += " = "; + result += v; + } + } + ilog("Non-default options: ${v}", ("v", result)); +} + +fc::logging_config& add_deep_mind_logger(fc::logging_config& config) { + config.appenders.push_back(fc::appender_config("deep-mind", "dmlog")); + + fc::logger_config dmlc; + dmlc.name = "deep-mind"; + dmlc.level = fc::log_level::debug; + dmlc.enabled = true; + dmlc.appenders.push_back("deep-mind"); + + config.loggers.push_back(dmlc); + return config; +} + +void configure_logging(const std::filesystem::path& config_path, bool enable_deep_mind) { + try { + try { + if (std::filesystem::exists(config_path)) { + fc::configure_logging(config_path); + } else { + auto cfg = fc::logging_config::default_config(); + + if (enable_deep_mind) + fc::configure_logging(add_deep_mind_logger(cfg)); + } + } catch (...) { + elog("Error reloading logging.json"); + throw; + } + } catch (const fc::exception& e) { + elogf("{}", e.to_detail_string()); + } catch (const boost::exception& e) { + elogf("{}", boost::diagnostic_information(e)); + } catch (const std::exception& e) { + elogf("{}", e.what()); + } catch (...) { + // empty + } +} + +} // namespace detail + +void logging_conf_handler(bool enable_deep_mind_logging) { + auto config_path = appbase::app().get_logging_conf(); + if (std::filesystem::exists(config_path)) { + ilog("Received HUP. Reloading logging configuration from ${p}.", ("p", config_path.string())); + } else { + ilog("Received HUP. No log config found at ${p}, setting to default.", ("p", config_path.string())); + } + detail::configure_logging(config_path, enable_deep_mind_logging); + fc::log_config::initialize_appenders(); +} + +void initialize_logging(const wire_application_config& cfg) { + if (!cfg.enable_logging_config) { + appbase::app().set_sighup_callback([]{}); + return; + } + + auto config_path = appbase::app().get_logging_conf(); + if (std::filesystem::exists(config_path)) { + fc::configure_logging(config_path); // intentionally allowing exceptions to escape + } else if (cfg.enable_deep_mind_logging) { + auto cfg = fc::logging_config::default_config(); + fc::configure_logging(detail::add_deep_mind_logger(cfg)); + } + + fc::log_config::initialize_appenders(); + auto sighup_cb = [cfg]() { logging_conf_handler(cfg.enable_deep_mind_logging); }; + appbase::app().set_sighup_callback(sighup_cb); +} + +class wire_application { +public: + explicit wire_application(const wire_application_config& cfg) : cfg_(cfg) { + exe_name_ = fc::program_name(); + ilogf("{} started", exe_name_); + + uint32_t short_hash = 0; + fc::from_hex(sysio::version::version_hash(), reinterpret_cast(&short_hash), sizeof(short_hash)); + + app_->set_version(htonl(short_hash)); + app_->set_version_string(sysio::version::version_client()); + app_->set_full_version_string(sysio::version::version_full()); + + auto root = fc::app_path(); + app_->set_default_data_dir(root / "sysio" / exe_name_ / "data"); + app_->set_default_config_dir(root / "sysio" / exe_name_ / "config"); + http_plugin::set_defaults({ + .default_unix_socket_path = "", + .default_http_port = cfg_.default_http_port, + .server_header = exe_name_ + "/" + app_->version_string() + }); + } + wire_application(const wire_application&) = delete; + wire_application& operator=(const wire_application&) = delete; + wire_application(wire_application&&) = delete; + wire_application& operator=(wire_application&&) = delete; + ~wire_application() { + if (last_result_ != NODE_MANAGEMENT_SUCCESS) { + detail::log_non_default_options(app_->get_parsed_options()); + auto full_ver = app_->version_string() == app_->full_version_string() ? "" : app_->full_version_string(); + ilogf("{} version {} {}", exe_name_, app_->version_string(), full_ver); + ilogf("{} successfully exiting", exe_name_); + } + } + + template + return_codes init(int argc, char** argv) { + try { + auto init_logging = [cfg=cfg_]() { initialize_logging(cfg); }; + if (!app_->initialize(argc, argv, init_logging)) { + const auto& opts = app_->get_options(); + if (opts.contains("help") || opts.contains("version") || opts.contains("full-version") || opts.contains("print-default-config")) { + last_result_ = NODE_MANAGEMENT_SUCCESS; + } else { + last_result_ = INITIALIZE_FAIL; + } + return last_result_; + } + + set_stop_executor_cb([]{}); + + if (cfg_.enable_resource_monitor) { + if (auto resmon_plugin = app_->find_plugin()) { + resmon_plugin->initialize(app_->get_options()); + resmon_plugin->monitor_directory(app_->data_dir()); + } else { + elog("resource_monitor_plugin failed to initialize"); + last_result_ = INITIALIZE_FAIL; + return last_result_; + } + } + + ilogf("{} version {} {}", exe_name_, app_->version_string(), + app_->version_string() == app_->full_version_string() ? "" : app_->full_version_string()); + ilogf("{} using configuration file {}", exe_name_, app_->full_config_file_path().string()); + ilogf("{} data directory is {}", exe_name_, app_->data_dir().string()); + detail::log_non_default_options(app_->get_parsed_options()); + } catch (...) { + return handle_exception(); + } + return SUCCESS; + } + + // Must call after init + template + void set_stop_executor_cb(Function&& f) { + auto cb = [f=std::forward(f)]() { + ilog("appbase quit called"); + f(); + appbase::app().get_io_context().stop(); + }; + app_->set_stop_executor_cb(cb); + } + + return_codes exec() { + try { + app_->startup(); + app_->set_thread_priority_max(); + app_->exec(); + } catch (...) { + return handle_exception(); + } + return SUCCESS; + } + + return_codes handle_exception() { + try { + last_result_ = OTHER_FAIL; + throw; + } catch (const fc::exception& e) { + if (e.code() == fc::std_exception_code) { + if (e.top_message().find("atabase dirty flag set") != std::string::npos) { + elog("database dirty flag set (likely due to unclean shutdown): replay required"); + last_result_ = DATABASE_DIRTY; + } else { + elogf("{}", e.to_detail_string()); + last_result_ = OTHER_FAIL; + } + } else if (e.code() == interrupt_exception::code_value) { + ilog("Interrupted, successfully exiting"); + last_result_ = SUCCESS; + } else { + elogf("{}", e.to_detail_string()); + last_result_ = OTHER_FAIL; + } + } catch (const boost::interprocess::bad_alloc& e) { + elog("bad alloc"); + last_result_ = BAD_ALLOC; + } catch (const boost::exception& e) { + elogf("{}", boost::diagnostic_information(e)); + last_result_ = OTHER_FAIL; + } catch (const std::runtime_error& e) { + if (std::string(e.what()).find("atabase dirty flag set") != std::string::npos) { + elog("database dirty flag set (likely due to unclean shutdown): replay required"); + last_result_ = DATABASE_DIRTY; + } else { + elogf("{}", e.what()); + last_result_ = OTHER_FAIL; + } + } catch (const std::exception& e) { + elogf("{}", e.what()); + last_result_ = OTHER_FAIL; + } catch (...) { + elog("unknown exception"); + last_result_ = OTHER_FAIL; + } + return last_result_; + } + +private: + appbase::scoped_app app_; + std::string exe_name_; + wire_application_config cfg_; + return_codes last_result_ = SUCCESS; +}; + +} // namespace sysio::chain \ No newline at end of file diff --git a/plugins/outpost_ethereum_client_plugin/src/outpost_ethereum_client_plugin.cpp b/plugins/outpost_ethereum_client_plugin/src/outpost_ethereum_client_plugin.cpp index 1a2d34faf6..90c52d1f52 100644 --- a/plugins/outpost_ethereum_client_plugin/src/outpost_ethereum_client_plugin.cpp +++ b/plugins/outpost_ethereum_client_plugin/src/outpost_ethereum_client_plugin.cpp @@ -10,6 +10,8 @@ namespace { constexpr auto option_name_client = "outpost-ethereum-client"; constexpr auto option_abi_file = "ethereum-abi-file"; +auto _register_outpost_ethereum_client_plugin = application::register_plugin(); + [[maybe_unused]] inline fc::logger& logger() { static fc::logger log{"outpost_ethereum_client_plugin"}; return log; @@ -27,6 +29,7 @@ class outpost_ethereum_client_plugin_impl { std::scoped_lock lock(mutex); for (auto& filename : file_names) { + FC_ASSERT_FMT(exists(filename), "File does not exist: {}", filename.string()); auto file_path = std::filesystem::absolute(filename); ilogf("Loading ABI file: {}", file_path.string()); if (!std::ranges::none_of(_abi_files, [&](const auto& f) { return f.first == file_path; })) { @@ -102,7 +105,7 @@ outpost_ethereum_client_plugin::outpost_ethereum_client_plugin() : my( void outpost_ethereum_client_plugin::set_program_options(options_description& cli, options_description& cfg) { cfg.add_options()( option_name_client, - boost::program_options::value>()->multitoken()->required(), + boost::program_options::value>()->multitoken(), "Outpost Ethereum Client spec, the plugin supports 1 to many clients in a given process" "`,,[,]`")( option_abi_file, diff --git a/programs/examples/cranker-example/src/main.cpp b/programs/examples/cranker-example/src/main.cpp index 62bb4bfd7e..20cb80102a 100644 --- a/programs/examples/cranker-example/src/main.cpp +++ b/programs/examples/cranker-example/src/main.cpp @@ -1,213 +1,41 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include #include -#include -#include -#include - using namespace appbase; using namespace sysio; - -namespace detail { - - -fc::logging_config& add_deep_mind_logger(fc::logging_config& config) { - config.appenders.push_back(fc::appender_config("deep-mind", "dmlog")); - - fc::logger_config dmlc; - dmlc.name = "deep-mind"; - dmlc.level = fc::log_level::debug; - dmlc.enabled = true; - dmlc.appenders.push_back("deep-mind"); - - config.loggers.push_back(dmlc); - - return config; -} - -void configure_logging(const std::filesystem::path& config_path) { - try { - try { - if (std::filesystem::exists(config_path)) { - fc::configure_logging(config_path); - } else { - auto cfg = fc::logging_config::default_config(); - - fc::configure_logging(::detail::add_deep_mind_logger(cfg)); - } - } catch (...) { - elog("Error reloading logging.json"); - throw; - } - } catch (const fc::exception& e) { - elogf("{}", e.to_detail_string()); - } catch (const boost::exception& e) { - elogf("{}", boost::diagnostic_information(e)); - } catch (const std::exception& e) { - elogf("{}", e.what()); - } catch (...) { - // empty - } -} - -} // namespace detail - -void logging_conf_handler() { - auto config_path = app().get_logging_conf(); - if (std::filesystem::exists(config_path)) { - ilog("Received HUP. Reloading logging configuration from ${p}.", ("p", config_path.string())); - } else { - ilog("Received HUP. No log config found at ${p}, setting to default.", ("p", config_path.string())); - } - ::detail::configure_logging(config_path); - fc::log_config::initialize_appenders(); -} - -void initialize_logging() { - auto config_path = app().get_logging_conf(); - if (std::filesystem::exists(config_path)) - fc::configure_logging(config_path); // intentionally allowing exceptions to escape - else { - auto cfg = fc::logging_config::default_config(); - - fc::configure_logging(::detail::add_deep_mind_logger(cfg)); - } - - fc::log_config::initialize_appenders(); - - app().set_sighup_callback(logging_conf_handler); -} - -enum return_codes { - OTHER_FAIL = -2, - INITIALIZE_FAIL = -1, - SUCCESS = 0, - BAD_ALLOC = 1, - DATABASE_DIRTY = 2, - FIXED_REVERSIBLE = SUCCESS, - EXTRACTED_GENESIS = SUCCESS, - NODE_MANAGEMENT_SUCCESS = 5 -}; +using namespace sysio::chain; int main(int argc, char** argv) { - auto exe_name = fc::program_name(); - ilogf("{} started", exe_name); - - try { - appbase::scoped_app app; + wire_application exe{wire_application_config{}}; - auto on_exit = fc::make_scoped_exit([&]() { - auto full_ver = app->version_string() == app->full_version_string() ? "" : app->full_version_string(); - ilogf("{} version {} {}", exe_name, app->version_string(), full_ver); - }); - uint32_t short_hash = 0; - fc::from_hex(sysio::version::version_hash(), reinterpret_cast(&short_hash), sizeof(short_hash)); + auto r = exe.init(argc, argv); + if (r != SUCCESS) + return r == NODE_MANAGEMENT_SUCCESS ? SUCCESS : r; - app->set_version(htonl(short_hash)); - app->set_version_string(sysio::version::version_client()); - app->set_full_version_string(sysio::version::version_full()); + auto& cron_plug = app().get_plugin(); + auto& eth_plug = app().get_plugin(); + auto eth_clients = eth_plug.get_clients(); + FC_ASSERT(!eth_clients.empty(), "At least 1 ethereum client must be configured"); + auto eth_client = eth_clients[0]; - auto root = fc::app_path(); - app->set_default_data_dir(root / "sysio" / exe_name / "data"); - app->set_default_config_dir(root / "sysio" / exe_name / "config"); - - // chain_plugin, net_plugin - if (!app->initialize(argc, argv, initialize_logging)) { - const auto& opts = app->get_options(); - if (opts.contains("help") || opts.contains("version") || opts.contains("full-version") || - opts.contains("print-default-config")) { - on_exit.cancel(); - return SUCCESS; - } - return INITIALIZE_FAIL; - } - auto& cron_plug = app->get_plugin(); - auto& eth_plug = app->get_plugin(); - auto eth_clients = eth_plug.get_clients(); - FC_ASSERT(!eth_clients.empty(), "At least 1 ethereum client must be configured"); - auto eth_client = eth_clients[0]; - - app->set_stop_executor_cb([&app, &cron_plug]() { - ilog("appbase quit called"); - cron_plug.cron_service().stop(); - app->get_io_context().stop(); - }); - - ilogf("{} version {} {}", exe_name, app->version_string(), - app->version_string() == app->full_version_string() ? "" : app->full_version_string()); - ilogf("{} using configuration file {}", exe_name, app->full_config_file_path().string()); - ilogf("{} data directory is {}", exe_name, app->data_dir().string()); - - cron_plug.add_job( - { - .milliseconds = {0}, - .seconds = {5, 15, 25, 35, 45, 55} + cron_plug.add_job( + { + .milliseconds = {0}, + .seconds = {5, 15, 25, 35, 45, 55} }, - [&]() { - auto now = std::chrono::utc_clock::now(); - auto now_str = std::format("{:%H:%M:%S}", now); - ilogf("{}: Getting ethereum gas price", now_str); - - auto current_price = eth_client->client->get_gas_price(); - ilogf("{}: Current Price> {}WEI", now_str, current_price.str()); - }, - cron_service::job_metadata_t{ - .one_at_a_time = true, .tags = {"ethereum", "gas"}, .label = "cron_5s_heartbeat"}); + [&]() { + auto now = std::chrono::utc_clock::now(); + auto now_str = std::format("{:%H:%M:%S}", now); + ilogf("{}: Getting ethereum gas price", now_str); - app->startup(); - app->set_thread_priority_max(); - app->exec(); - } catch (const fc::exception& e) { - if (e.code() == fc::std_exception_code) { - if (e.top_message().find("atabase dirty flag set") != std::string::npos) { - elog("database dirty flag set (likely due to unclean shutdown): replay required"); - return DATABASE_DIRTY; - } - } else if (e.code() == interrupt_exception::code_value) { - ilog("Interrupted, successfully exiting"); - return SUCCESS; - } - elogf("{}", e.to_detail_string()); - return OTHER_FAIL; - } catch (const boost::interprocess::bad_alloc& e) { - elog("bad alloc"); - return BAD_ALLOC; - } catch (const boost::exception& e) { - elogf("{}", boost::diagnostic_information(e)); - return OTHER_FAIL; - } catch (const std::runtime_error& e) { - if (std::string(e.what()).find("atabase dirty flag set") != std::string::npos) { - elog("database dirty flag set (likely due to unclean shutdown): replay required"); - return DATABASE_DIRTY; - } - elogf("{}", e.what()); - return OTHER_FAIL; - } catch (const std::exception& e) { - elogf("{}", e.what()); - return OTHER_FAIL; - } catch (...) { - elog("unknown exception"); - return OTHER_FAIL; - } + auto current_price = eth_client->client->get_gas_price(); + ilogf("{}: Current Price> {}WEI", now_str, current_price.str()); + }, + cron_service::job_metadata_t{ + .one_at_a_time = true, .tags = {"ethereum", "gas"}, .label = "cron_5s_heartbeat"}); - ilogf("{} successfully exiting", exe_name); - return SUCCESS; + return exe.exec(); } diff --git a/programs/nodeop/main.cpp b/programs/nodeop/main.cpp index 7e566a5ee6..c4b7e0f808 100644 --- a/programs/nodeop/main.cpp +++ b/programs/nodeop/main.cpp @@ -1,256 +1,25 @@ -#include +#include #include -#include #include #include #include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "config.hpp" using namespace appbase; using namespace sysio; -namespace detail { - -void log_non_default_options(const std::vector>& options) { - using namespace std::string_literals; - // TODO: @jglanz reimplement - // auto mask_private = [](const string& v) { - // auto [pub_key_str, spec_type_str, spec_data] = signature_provider_manager_plugin::parse_signature_provider_spec(v); - // return pub_key_str + "=" + spec_type_str + ":***"; - // }; - - string result; - for (const auto& op : options) { - bool mask = false; - if (op.string_key == "peer-private-key"s - || op.string_key == "p2p-auto-bp-peer"s) { - mask = true; - } - std::string v; - for (auto i = op.value.cbegin(), b = op.value.cbegin(), e = op.value.cend(); i != e; ++i) { - if (i != b) - v += ", "; - if (op.string_key == "signature-provider"s) - v += *i;// TODO @jglanz mask_private(*i); - else if (mask) - v += "***"; - else - v += *i; - } - - if (!result.empty()) - result += ", "; - - if (v.empty()) { - result += op.string_key; - } else { - result += op.string_key; - result += " = "; - result += v; - } - } - ilog("Non-default options: ${v}", ("v", result)); -} - -fc::logging_config& add_deep_mind_logger(fc::logging_config& config) { - config.appenders.push_back( - fc::appender_config( "deep-mind", "dmlog" ) - ); - - fc::logger_config dmlc; - dmlc.name = "deep-mind"; - dmlc.level = fc::log_level::debug; - dmlc.enabled = true; - dmlc.appenders.push_back("deep-mind"); - - config.loggers.push_back( dmlc ); - - return config; -} - -void configure_logging(const std::filesystem::path& config_path) -{ - try { - try { - if( std::filesystem::exists( config_path ) ) { - fc::configure_logging( config_path ); - } else { - auto cfg = fc::logging_config::default_config(); - - fc::configure_logging( ::detail::add_deep_mind_logger(cfg) ); - } - } catch (...) { - elog("Error reloading logging.json"); - throw; - } - } catch (const fc::exception& e) { - elog("${e}", ("e",e.to_detail_string())); - } catch (const boost::exception& e) { - elog("${e}", ("e",boost::diagnostic_information(e))); - } catch (const std::exception& e) { - elog("${e}", ("e",e.what())); - } catch (...) { - // empty - } -} - -} // namespace detail - -void logging_conf_handler() -{ - auto config_path = app().get_logging_conf(); - if( std::filesystem::exists( config_path ) ) { - ilog( "Received HUP. Reloading logging configuration from ${p}.", ("p", config_path.string()) ); - } else { - ilog( "Received HUP. No log config found at ${p}, setting to default.", ("p", config_path.string()) ); - } - ::detail::configure_logging( config_path ); - fc::log_config::initialize_appenders(); -} - -void initialize_logging() -{ - auto config_path = app().get_logging_conf(); - if(std::filesystem::exists(config_path)) - fc::configure_logging(config_path); // intentionally allowing exceptions to escape - else { - auto cfg = fc::logging_config::default_config(); - - fc::configure_logging( ::detail::add_deep_mind_logger(cfg) ); - } - - fc::log_config::initialize_appenders(); - - app().set_sighup_callback(logging_conf_handler); -} - -enum return_codes { - OTHER_FAIL = -2, - INITIALIZE_FAIL = -1, - SUCCESS = 0, - BAD_ALLOC = 1, - DATABASE_DIRTY = 2, - FIXED_REVERSIBLE = SUCCESS, - EXTRACTED_GENESIS = SUCCESS, - NODE_MANAGEMENT_SUCCESS = 5 -}; - int main(int argc, char** argv) { + wire_application exe{wire_application_config{.enable_deep_mind_logging = true}}; - ilog("nodeos started"); - - try { - appbase::scoped_app app; - auto on_exit = fc::make_scoped_exit([&]() { - ilog("${name} version ${ver} ${fv}", - ("name", nodeop::config::node_executable_name)("ver", app->version_string()) - ("fv", app->version_string() == app->full_version_string() ? "" : app->full_version_string()) ); - ::detail::log_non_default_options(app->get_parsed_options()); - }); - uint32_t short_hash = 0; - fc::from_hex(sysio::version::version_hash(), (char*)&short_hash, sizeof(short_hash)); - - app->set_version(htonl(short_hash)); - app->set_version_string(sysio::version::version_client()); - app->set_full_version_string(sysio::version::version_full()); - - auto root = fc::app_path(); - app->set_default_data_dir(root / "sysio" / nodeop::config::node_executable_name / "data" ); - app->set_default_config_dir(root / "sysio" / nodeop::config::node_executable_name / "config" ); - http_plugin::set_defaults({ - .default_unix_socket_path = "", - .default_http_port = 8888, - .server_header = nodeop::config::node_executable_name + "/" + app->version_string() - }); - if(!app->initialize(argc, argv, initialize_logging)) { - const auto& opts = app->get_options(); - if( opts.contains("help") || opts.contains("version") || opts.contains("full-version") || opts.contains("print-default-config") ) { - on_exit.cancel(); - return SUCCESS; - } - return INITIALIZE_FAIL; - } - producer_plugin& prod_plug = app->get_plugin(); - app->set_stop_executor_cb([&app, &prod_plug]() { - ilog("appbase quit called"); - prod_plug.interrupt(); - app->get_io_context().stop(); - }); - if (auto resmon_plugin = app->find_plugin()) { - resmon_plugin->monitor_directory(app->data_dir()); - } else { - elog("resource_monitor_plugin failed to initialize"); - return INITIALIZE_FAIL; - } - ilog("${name} version ${ver} ${fv}", - ("name", nodeop::config::node_executable_name)("ver", app->version_string()) - ("fv", app->version_string() == app->full_version_string() ? "" : app->full_version_string()) ); - ilog("${name} using configuration file ${c}", ("name", nodeop::config::node_executable_name)("c", app->full_config_file_path().string())); - ilog("${name} data directory is ${d}", ("name", nodeop::config::node_executable_name)("d", app->data_dir().string())); - ::detail::log_non_default_options(app->get_parsed_options()); - app->startup(); - app->set_thread_priority_max(); - app->exec(); - } catch( const extract_genesis_state_exception& e ) { - return EXTRACTED_GENESIS; - } catch( const fixed_reversible_db_exception& e ) { - return FIXED_REVERSIBLE; - } catch( const node_management_success& e ) { - return NODE_MANAGEMENT_SUCCESS; - } catch( const fc::exception& e ) { + auto r = exe.init(argc, argv); + if (r != SUCCESS) + return r == NODE_MANAGEMENT_SUCCESS ? SUCCESS : r; - if( e.code() == fc::std_exception_code ) { - if( e.top_message().find( "atabase dirty flag set" ) != std::string::npos ) { - elog( "database dirty flag set (likely due to unclean shutdown): replay required" ); - return DATABASE_DIRTY; - } - } else if (e.code() == interrupt_exception::code_value) { - ilog("Interrupted, successfully exiting"); - return SUCCESS; - } - elog( "${e}", ("e", e.to_detail_string())); - return OTHER_FAIL; - } catch( const boost::interprocess::bad_alloc& e ) { - elog("bad alloc"); - return BAD_ALLOC; - } catch( const boost::exception& e ) { - elog("${e}", ("e",boost::diagnostic_information(e))); - return OTHER_FAIL; - } catch( const std::runtime_error& e ) { - if( std::string(e.what()).find("atabase dirty flag set") != std::string::npos ) { - elog( "database dirty flag set (likely due to unclean shutdown): replay required" ); - return DATABASE_DIRTY; - } else { - elog( "${e}", ("e",e.what())); - } - return OTHER_FAIL; - } catch( const std::exception& e ) { - elog("${e}", ("e",e.what())); - return OTHER_FAIL; - } catch( ... ) { - elog("unknown exception"); - return OTHER_FAIL; - } + producer_plugin& prod_plug = app().get_plugin(); + exe.set_stop_executor_cb([&prod_plug]() { + prod_plug.interrupt(); + }); - ilog("${name} successfully exiting", ("name", nodeop::config::node_executable_name)); - return SUCCESS; + return exe.exec(); }