From 60e8a8d7607dd183e4d208d25c3cf729825acb50 Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 14 Jan 2019 13:54:27 -0500 Subject: [PATCH 1/4] shut down without calling exit --- libraries/app/application.cpp | 18 ++++++++++-------- libraries/app/application_impl.hxx | 2 +- .../app/include/graphene/app/application.hpp | 12 ++++++++++-- programs/delayed_node/main.cpp | 10 ++++++++-- programs/witness_node/main.cpp | 12 ++++++++++-- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index f2cf80285d..3cf7cff63b 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -318,7 +318,7 @@ void application_impl::set_dbg_init_key( graphene::chain::genesis_state_type& ge genesis.initial_witness_candidates[i].block_signing_key = init_pubkey; } -void application_impl::startup() +bool application_impl::startup() { try { fc::create_directories(_data_dir / "blockchain"); @@ -454,7 +454,7 @@ void application_impl::startup() { elog("Failed to load file from ${path}", ("path", _options->at("api-access").as().string())); - std::exit(EXIT_FAILURE); + return false; } } else @@ -475,6 +475,7 @@ void application_impl::startup() reset_p2p_node(_data_dir); reset_websocket_server(); reset_websocket_tls_server(); + return true; } FC_LOG_AND_RETHROW() } optional< api_access_info > application_impl::get_api_access_info(const string& username)const @@ -1000,7 +1001,7 @@ void application::set_program_options(boost::program_options::options_descriptio configuration_file_options.add(_cfg_options); } -void application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options) +bool application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options) { my->_data_dir = data_dir; my->_options = &options; @@ -1018,7 +1019,7 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti << "\nWould you like to replace it? [y/N] "; char response = std::cin.get(); if( toupper(response) != 'Y' ) - return; + return false; } std::cerr << "Updating genesis state in file " << genesis_out.generic_string() << "\n"; @@ -1027,7 +1028,7 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti } fc::json::save_to_file(genesis_state, genesis_out); - std::exit(EXIT_SUCCESS); + return false; } if ( options.count("io-threads") ) @@ -1058,16 +1059,17 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti if(es_ah_conflict_counter > 1) { elog("Can't start program with elasticsearch and account_history plugin at the same time"); - std::exit(EXIT_FAILURE); + return false; } if (!it.empty()) enable_plugin(it); } + return true; } -void application::startup() +bool application::startup() { try { - my->startup(); + return my->startup(); } catch ( const fc::exception& e ) { elog( "${e}", ("e",e.to_detail_string()) ); throw; diff --git a/libraries/app/application_impl.hxx b/libraries/app/application_impl.hxx index 9f601bce79..f5368da6a1 100644 --- a/libraries/app/application_impl.hxx +++ b/libraries/app/application_impl.hxx @@ -42,7 +42,7 @@ class application_impl : public net::node_delegate void set_dbg_init_key( graphene::chain::genesis_state_type& genesis, const std::string& init_key ); - void startup(); + bool startup(); fc::optional< api_access_info > get_api_access_info(const string& username)const; diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index 4892bb9a27..96684a65a0 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -50,9 +50,17 @@ namespace graphene { namespace app { void set_program_options( boost::program_options::options_description& command_line_options, boost::program_options::options_description& configuration_file_options )const; - void initialize(const fc::path& data_dir, const boost::program_options::variables_map&options); + /** + * Initializes the application + * @returns true if the calling method should continue, false otherwise + */ + bool initialize(const fc::path& data_dir, const boost::program_options::variables_map&options); void initialize_plugins( const boost::program_options::variables_map& options ); - void startup(); + /*** + * Performs startup + * @returns true if the calling method should continue, false otherwise + */ + bool startup(); void shutdown(); void startup_plugins(); void shutdown_plugins(); diff --git a/programs/delayed_node/main.cpp b/programs/delayed_node/main.cpp index 0ba1e6944d..76d68c7bec 100644 --- a/programs/delayed_node/main.cpp +++ b/programs/delayed_node/main.cpp @@ -163,10 +163,15 @@ int main(int argc, char** argv) { if( !options.count("plugins") ) options.insert( std::make_pair( "plugins", bpo::variable_value(std::string("delayed_node account_history market_history"), true) ) ); - node.initialize(data_dir, options); + if (!node.initialize(data_dir, options)) + return 0; + node.initialize_plugins( options ); - node.startup(); + if (!node.startup()) + { + return 0; + } node.startup_plugins(); fc::promise::ptr exit_promise = new fc::promise("UNIX Signal Handler"); @@ -180,6 +185,7 @@ int main(int argc, char** argv) { int signal = exit_promise->wait(); ilog("Exiting from signal ${n}", ("n", signal)); node.shutdown_plugins(); + node.shutdown(); return 0; } catch( const fc::exception& e ) { elog("Exiting with error:\n${e}", ("e", e.to_detail_string())); diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 07c17a9010..0d5cbd1cfd 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -120,10 +120,18 @@ int main(int argc, char** argv) { app::load_configuration_options(data_dir, cfg_options, options); bpo::notify(options); - node->initialize(data_dir, options); + if (!node->initialize(data_dir, options)) + { + delete node; + return 0; + } node->initialize_plugins( options ); - node->startup(); + if (!node->startup()) + { + delete node; + return 0; + } node->startup_plugins(); fc::promise::ptr exit_promise = new fc::promise("UNIX Signal Handler"); From 7c3968b589a07fa40eb64d4b050784c4440de78a Mon Sep 17 00:00:00 2001 From: John Jones Date: Mon, 14 Jan 2019 13:55:13 -0500 Subject: [PATCH 2/4] prevent segfault when destructing application obj --- libraries/chain/db_management.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/chain/db_management.cpp b/libraries/chain/db_management.cpp index 231cc3ebc9..16e38f43da 100644 --- a/libraries/chain/db_management.cpp +++ b/libraries/chain/db_management.cpp @@ -223,6 +223,9 @@ void database::open( void database::close(bool rewind) { + if (!_opened) + return; + // TODO: Save pending tx's on close() clear_pending(); From 3b0891a17ec6dbd210a29973394ee109c5623781 Mon Sep 17 00:00:00 2001 From: John Jones Date: Tue, 15 Jan 2019 10:06:07 -0500 Subject: [PATCH 3/4] keep return value --- libraries/app/application.cpp | 16 ++++++++-------- libraries/app/application_impl.hxx | 2 +- .../app/include/graphene/app/application.hpp | 12 ++++++++---- programs/delayed_node/main.cpp | 16 ++++++++-------- programs/witness_node/main.cpp | 15 +++++++++------ 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 3cf7cff63b..6ae8dfea78 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -318,7 +318,7 @@ void application_impl::set_dbg_init_key( graphene::chain::genesis_state_type& ge genesis.initial_witness_candidates[i].block_signing_key = init_pubkey; } -bool application_impl::startup() +uint8_t application_impl::startup() { try { fc::create_directories(_data_dir / "blockchain"); @@ -454,7 +454,7 @@ bool application_impl::startup() { elog("Failed to load file from ${path}", ("path", _options->at("api-access").as().string())); - return false; + return EXIT_FAILURE; } } else @@ -475,7 +475,7 @@ bool application_impl::startup() reset_p2p_node(_data_dir); reset_websocket_server(); reset_websocket_tls_server(); - return true; + return DO_NOT_EXIT; } FC_LOG_AND_RETHROW() } optional< api_access_info > application_impl::get_api_access_info(const string& username)const @@ -1001,7 +1001,7 @@ void application::set_program_options(boost::program_options::options_descriptio configuration_file_options.add(_cfg_options); } -bool application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options) +uint8_t application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options) { my->_data_dir = data_dir; my->_options = &options; @@ -1019,7 +1019,7 @@ bool application::initialize(const fc::path& data_dir, const boost::program_opti << "\nWould you like to replace it? [y/N] "; char response = std::cin.get(); if( toupper(response) != 'Y' ) - return false; + return EXIT_FAILURE; } std::cerr << "Updating genesis state in file " << genesis_out.generic_string() << "\n"; @@ -1028,7 +1028,7 @@ bool application::initialize(const fc::path& data_dir, const boost::program_opti } fc::json::save_to_file(genesis_state, genesis_out); - return false; + return EXIT_SUCCESS; } if ( options.count("io-threads") ) @@ -1059,14 +1059,14 @@ bool application::initialize(const fc::path& data_dir, const boost::program_opti if(es_ah_conflict_counter > 1) { elog("Can't start program with elasticsearch and account_history plugin at the same time"); - return false; + return EXIT_FAILURE; } if (!it.empty()) enable_plugin(it); } return true; } -bool application::startup() +uint8_t application::startup() { try { return my->startup(); diff --git a/libraries/app/application_impl.hxx b/libraries/app/application_impl.hxx index f5368da6a1..25f7ee9d4c 100644 --- a/libraries/app/application_impl.hxx +++ b/libraries/app/application_impl.hxx @@ -42,7 +42,7 @@ class application_impl : public net::node_delegate void set_dbg_init_key( graphene::chain::genesis_state_type& genesis, const std::string& init_key ); - bool startup(); + uint8_t startup(); fc::optional< api_access_info > get_api_access_info(const string& username)const; diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index 96684a65a0..579f49fdc0 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -29,6 +29,10 @@ #include +#ifndef DO_NOT_EXIT + #define DO_NOT_EXIT 254 +#endif + namespace graphene { namespace app { namespace detail { class application_impl; } using std::string; @@ -52,15 +56,15 @@ namespace graphene { namespace app { boost::program_options::options_description& configuration_file_options )const; /** * Initializes the application - * @returns true if the calling method should continue, false otherwise + * @returns DO_NOT_EXIT if the calling method should continue, otherwise EXIT_SUCCESS or EXIT_FAILURE */ - bool initialize(const fc::path& data_dir, const boost::program_options::variables_map&options); + uint8_t initialize(const fc::path& data_dir, const boost::program_options::variables_map&options); void initialize_plugins( const boost::program_options::variables_map& options ); /*** * Performs startup - * @returns true if the calling method should continue, false otherwise + * @returns DO_NOT_EXIT if the calling method should continue, otherwise EXIT_SUCCESS or EXIT_FAILURE */ - bool startup(); + uint8_t startup(); void shutdown(); void startup_plugins(); void shutdown_plugins(); diff --git a/programs/delayed_node/main.cpp b/programs/delayed_node/main.cpp index 76d68c7bec..ff2284962a 100644 --- a/programs/delayed_node/main.cpp +++ b/programs/delayed_node/main.cpp @@ -163,15 +163,15 @@ int main(int argc, char** argv) { if( !options.count("plugins") ) options.insert( std::make_pair( "plugins", bpo::variable_value(std::string("delayed_node account_history market_history"), true) ) ); - if (!node.initialize(data_dir, options)) - return 0; + uint8_t ret_val; + if ( (ret_val = node.initialize(data_dir, options)) != DO_NOT_EXIT ) + return ret_val; node.initialize_plugins( options ); - if (!node.startup()) - { - return 0; - } + if ( (ret_val = node.startup()) != DO_NOT_EXIT ) + return ret_val; + node.startup_plugins(); fc::promise::ptr exit_promise = new fc::promise("UNIX Signal Handler"); @@ -186,10 +186,10 @@ int main(int argc, char** argv) { ilog("Exiting from signal ${n}", ("n", signal)); node.shutdown_plugins(); node.shutdown(); - return 0; + return EXIT_SUCCESS; } catch( const fc::exception& e ) { elog("Exiting with error:\n${e}", ("e", e.to_detail_string())); - return 1; + return EXIT_FAILURE; } } diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 0d5cbd1cfd..dabcdd46a8 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -120,18 +120,21 @@ int main(int argc, char** argv) { app::load_configuration_options(data_dir, cfg_options, options); bpo::notify(options); - if (!node->initialize(data_dir, options)) + + uint8_t ret_val; + if ( ( ret_val = node->initialize(data_dir, options)) != DO_NOT_EXIT ) { delete node; - return 0; + return ret_val; } node->initialize_plugins( options ); - if (!node->startup()) + if ( (ret_val = node->startup()) != DO_NOT_EXIT ) { delete node; - return 0; + return ret_val; } + node->startup_plugins(); fc::promise::ptr exit_promise = new fc::promise("UNIX Signal Handler"); @@ -154,7 +157,7 @@ int main(int argc, char** argv) { node->shutdown_plugins(); node->shutdown(); delete node; - return 0; + return EXIT_SUCCESS; } catch( const fc::exception& e ) { // deleting the node can yield, so do this outside the exception handler unhandled_exception = e; @@ -165,7 +168,7 @@ int main(int argc, char** argv) { elog("Exiting with error:\n${e}", ("e", unhandled_exception->to_detail_string())); node->shutdown(); delete node; - return 1; + return EXIT_FAILURE; } } From 46e248ed30de0e207c53bdf9c1e10f970949fb23 Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 18 Jan 2019 13:42:21 -0500 Subject: [PATCH 4/4] Remove create-genesis-json --- libraries/app/application.cpp | 65 ++++--------------- libraries/app/application_impl.hxx | 4 +- .../app/include/graphene/app/application.hpp | 16 +---- programs/delayed_node/main.cpp | 8 +-- programs/witness_node/main.cpp | 14 +--- 5 files changed, 22 insertions(+), 85 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 6ae8dfea78..c89ec21be0 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -318,7 +318,7 @@ void application_impl::set_dbg_init_key( graphene::chain::genesis_state_type& ge genesis.initial_witness_candidates[i].block_signing_key = init_pubkey; } -uint8_t application_impl::startup() +void application_impl::startup() { try { fc::create_directories(_data_dir / "blockchain"); @@ -444,18 +444,14 @@ uint8_t application_impl::startup() if( _options->count("api-access") ) { - if(fc::exists(_options->at("api-access").as())) - { - _apiaccess = fc::json::from_file( _options->at("api-access").as() ).as( 20 ); - ilog( "Using api access file from ${path}", - ("path", _options->at("api-access").as().string()) ); - } - else - { - elog("Failed to load file from ${path}", - ("path", _options->at("api-access").as().string())); - return EXIT_FAILURE; - } + fc::path api_access_file = _options->at("api-access").as(); + + FC_ASSERT( fc::exists(api_access_file), + "Failed to load file from ${path}", ("path", api_access_file) ); + + _apiaccess = fc::json::from_file( api_access_file ).as( 20 ); + ilog( "Using api access file from ${path}", + ("path", api_access_file) ); } else { @@ -475,7 +471,6 @@ uint8_t application_impl::startup() reset_p2p_node(_data_dir); reset_websocket_server(); reset_websocket_tls_server(); - return DO_NOT_EXIT; } FC_LOG_AND_RETHROW() } optional< api_access_info > application_impl::get_api_access_info(const string& username)const @@ -986,10 +981,6 @@ void application::set_program_options(boost::program_options::options_descriptio ; command_line_options.add(configuration_file_options); command_line_options.add_options() - ("create-genesis-json", bpo::value(), - "Path to create a Genesis State at. If a well-formed JSON file exists at the path, it will be parsed and any " - "missing fields in a Genesis State will be added, and any unknown fields will be removed. If no file or an " - "invalid file is found, it will be replaced with an example Genesis State.") ("replay-blockchain", "Rebuild object graph by replaying all blocks without validation") ("revalidate-blockchain", "Rebuild object graph by replaying all blocks with full validation") ("resync-blockchain", "Delete all blocks and re-sync with network from scratch") @@ -1001,36 +992,11 @@ void application::set_program_options(boost::program_options::options_descriptio configuration_file_options.add(_cfg_options); } -uint8_t application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options) +void application::initialize(const fc::path& data_dir, const boost::program_options::variables_map& options) { my->_data_dir = data_dir; my->_options = &options; - if( options.count("create-genesis-json") ) - { - fc::path genesis_out = options.at("create-genesis-json").as(); - genesis_state_type genesis_state = detail::create_example_genesis(); - if( fc::exists(genesis_out) ) - { - try { - genesis_state = fc::json::from_file(genesis_out).as( 20 ); - } catch(const fc::exception& e) { - std::cerr << "Unable to parse existing genesis file:\n" << e.to_string() - << "\nWould you like to replace it? [y/N] "; - char response = std::cin.get(); - if( toupper(response) != 'Y' ) - return EXIT_FAILURE; - } - - std::cerr << "Updating genesis state in file " << genesis_out.generic_string() << "\n"; - } else { - std::cerr << "Creating example genesis state in file " << genesis_out.generic_string() << "\n"; - } - fc::json::save_to_file(genesis_state, genesis_out); - - return EXIT_SUCCESS; - } - if ( options.count("io-threads") ) { const uint16_t num_threads = options["io-threads"].as(); @@ -1057,19 +1023,16 @@ uint8_t application::initialize(const fc::path& data_dir, const boost::program_o if(it == "elasticsearch") ++es_ah_conflict_counter; - if(es_ah_conflict_counter > 1) { - elog("Can't start program with elasticsearch and account_history plugin at the same time"); - return EXIT_FAILURE; - } + FC_ASSERT(es_ah_conflict_counter <= 1, "Can't start program with elasticsearch and account_history plugin at the same time"); + if (!it.empty()) enable_plugin(it); } - return true; } -uint8_t application::startup() +void application::startup() { try { - return my->startup(); + my->startup(); } catch ( const fc::exception& e ) { elog( "${e}", ("e",e.to_detail_string()) ); throw; diff --git a/libraries/app/application_impl.hxx b/libraries/app/application_impl.hxx index 25f7ee9d4c..2d5d48080d 100644 --- a/libraries/app/application_impl.hxx +++ b/libraries/app/application_impl.hxx @@ -36,13 +36,13 @@ class application_impl : public net::node_delegate { } - ~application_impl() + virtual ~application_impl() { } void set_dbg_init_key( graphene::chain::genesis_state_type& genesis, const std::string& init_key ); - uint8_t startup(); + void startup(); fc::optional< api_access_info > get_api_access_info(const string& username)const; diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index 579f49fdc0..4892bb9a27 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -29,10 +29,6 @@ #include -#ifndef DO_NOT_EXIT - #define DO_NOT_EXIT 254 -#endif - namespace graphene { namespace app { namespace detail { class application_impl; } using std::string; @@ -54,17 +50,9 @@ namespace graphene { namespace app { void set_program_options( boost::program_options::options_description& command_line_options, boost::program_options::options_description& configuration_file_options )const; - /** - * Initializes the application - * @returns DO_NOT_EXIT if the calling method should continue, otherwise EXIT_SUCCESS or EXIT_FAILURE - */ - uint8_t initialize(const fc::path& data_dir, const boost::program_options::variables_map&options); + void initialize(const fc::path& data_dir, const boost::program_options::variables_map&options); void initialize_plugins( const boost::program_options::variables_map& options ); - /*** - * Performs startup - * @returns DO_NOT_EXIT if the calling method should continue, otherwise EXIT_SUCCESS or EXIT_FAILURE - */ - uint8_t startup(); + void startup(); void shutdown(); void startup_plugins(); void shutdown_plugins(); diff --git a/programs/delayed_node/main.cpp b/programs/delayed_node/main.cpp index ff2284962a..ac44686d46 100644 --- a/programs/delayed_node/main.cpp +++ b/programs/delayed_node/main.cpp @@ -163,14 +163,10 @@ int main(int argc, char** argv) { if( !options.count("plugins") ) options.insert( std::make_pair( "plugins", bpo::variable_value(std::string("delayed_node account_history market_history"), true) ) ); - uint8_t ret_val; - if ( (ret_val = node.initialize(data_dir, options)) != DO_NOT_EXIT ) - return ret_val; - + node.initialize(data_dir, options); node.initialize_plugins( options ); - if ( (ret_val = node.startup()) != DO_NOT_EXIT ) - return ret_val; + node.startup(); node.startup_plugins(); diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index dabcdd46a8..41bbce769f 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -121,20 +121,10 @@ int main(int argc, char** argv) { bpo::notify(options); - uint8_t ret_val; - if ( ( ret_val = node->initialize(data_dir, options)) != DO_NOT_EXIT ) - { - delete node; - return ret_val; - } + node->initialize(data_dir, options); node->initialize_plugins( options ); - if ( (ret_val = node->startup()) != DO_NOT_EXIT ) - { - delete node; - return ret_val; - } - + node->startup(); node->startup_plugins(); fc::promise::ptr exit_promise = new fc::promise("UNIX Signal Handler");