diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 4e0e0e542f..92bef4b2b3 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -2550,12 +2550,15 @@ namespace eosio { validate_reversible_available_size(); my->push_block(block_state_future); } + bool controller::in_immutable_mode()const { + return (db_mode_is_immutable(get_read_mode())); + } transaction_trace_ptr controller::push_transaction(const transaction_metadata_ptr &trx, fc::time_point deadline, uint32_t billed_cpu_time_us) { validate_db_available_size(); - EOS_ASSERT(get_read_mode() != chain::db_read_mode::READ_ONLY, transaction_type_exception, - "push transaction not allowed in read-only mode"); + EOS_ASSERT( !in_immutable_mode(), transaction_type_exception, + "push transaction not allowed in read-only mode" ); EOS_ASSERT(trx && !trx->implicit && !trx->scheduled, transaction_type_exception, "Implicit/Scheduled transaction not allowed"); return my->push_transaction(trx, deadline, billed_cpu_time_us, billed_cpu_time_us > 0); @@ -2564,6 +2567,8 @@ namespace eosio { transaction_trace_ptr controller::push_scheduled_transaction(const transaction_id_type &trxid, fc::time_point deadline, uint32_t billed_cpu_time_us) { + EOS_ASSERT( !in_immutable_mode(), transaction_type_exception, + "push scheduled transaction not allowed in read-only mode" ); validate_db_available_size(); return my->push_scheduled_transaction(trxid, deadline, billed_cpu_time_us, billed_cpu_time_us > 0); } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 4519088080..1a4d0b6e98 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -55,6 +55,10 @@ namespace eosio { IRREVERSIBLE }; + inline bool db_mode_is_immutable(db_read_mode m) { + return db_read_mode::READ_ONLY == m || db_read_mode::IRREVERSIBLE ==m; + } + enum class validation_mode { FULL, LIGHT @@ -344,6 +348,8 @@ namespace eosio { validation_mode get_validation_mode() const; + bool in_immutable_mode() const; + void set_subjective_cpu_leeway(fc::microseconds leeway); void set_greylist_limit(uint32_t limit); diff --git a/libraries/fc b/libraries/fc index c5a8f6f335..dfd0c8b689 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit c5a8f6f3355eb23c0270043c990559aa941f5361 +Subproject commit dfd0c8b689c12b0b886ec9ae5c6da33ad62abaf8 diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 82d15a6e86..a64c4d8366 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1059,8 +1059,8 @@ if( options.count(name) ) { \ } void chain_apis::read_write::validate() const { - EOS_ASSERT(db.get_read_mode() != chain::db_read_mode::READ_ONLY, missing_chain_api_plugin_exception, - "Not allowed, node in read-only mode"); + EOS_ASSERT( !db.in_immutable_mode(), missing_chain_api_plugin_exception, + "Not allowed, node in read-only mode" ); } void chain_plugin::accept_block(const signed_block_ptr &block) { diff --git a/plugins/http_plugin/http_plugin.cpp b/plugins/http_plugin/http_plugin.cpp index 627776d208..9ae0a4d148 100644 --- a/plugins/http_plugin/http_plugin.cpp +++ b/plugins/http_plugin/http_plugin.cpp @@ -645,6 +645,8 @@ namespace eosio { if (my->thread_pool) { my->thread_pool->stop(); } + + app().post( 0, [me = my](){} ); // keep my pointer alive until queue is drained } void http_plugin::add_handler(const string &url, const url_handler &handler) { diff --git a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp index bc6d5ad648..791dbab249 100644 --- a/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp +++ b/plugins/http_plugin/include/eosio/http_plugin/http_plugin.hpp @@ -111,7 +111,7 @@ namespace eosio { get_supported_apis_result get_supported_apis() const; private: - std::unique_ptr my; + std::shared_ptr my; }; /** diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 7170c1abd2..7df757bf68 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -26,7 +26,7 @@ namespace eosio { chain_id_type chain_id; ///< used to identify chain fc::sha256 node_id; ///< used to identify peers and prevent self-connect chain::public_key_type key; ///< authentication key; may be a producer or peer key, or empty - tstamp time; + tstamp time{0}; fc::sha256 token; ///< digest of time to prove we own the private key of the key above chain::signature_type sig; ///< signature for the digest string p2p_address; @@ -36,7 +36,7 @@ namespace eosio { block_id_type head_id; string os; string agent; - int16_t generation; + int16_t generation{0}; }; @@ -75,15 +75,15 @@ namespace eosio { struct go_away_message { go_away_message (go_away_reason r = no_reason) : reason(r), node_id() {} - go_away_reason reason; + go_away_reason reason{no_reason}; fc::sha256 node_id; ///< for duplicate notification }; struct time_message { - tstamp org; //!< origin timestamp - tstamp rec; //!< receive timestamp - tstamp xmt; //!< transmit timestamp - mutable tstamp dst; //!< destination timestamp + tstamp org{0}; //!< origin timestamp + tstamp rec{0}; //!< receive timestamp + tstamp xmt{0}; //!< transmit timestamp + mutable tstamp dst{0}; //!< destination timestamp }; enum id_list_modes { @@ -128,8 +128,8 @@ namespace eosio { }; struct sync_request_message { - uint32_t start_block; - uint32_t end_block; + uint32_t start_block{0}; + uint32_t end_block{0}; }; using net_message = static_variant connector_check; unique_ptr transaction_check; unique_ptr keepalive_timer; - boost::asio::steady_timer::duration connector_period; - boost::asio::steady_timer::duration txn_exp_period; - boost::asio::steady_timer::duration resp_expected_period; + boost::asio::steady_timer::duration connector_period{0}; + boost::asio::steady_timer::duration txn_exp_period{0}; + boost::asio::steady_timer::duration resp_expected_period{0}; boost::asio::steady_timer::duration keepalive_interval{std::chrono::seconds{32}}; int max_cleanup_time_ms = 0; @@ -289,6 +289,7 @@ namespace eosio { constexpr auto def_send_buffer_size = 1024*1024*def_send_buffer_size_mb; constexpr auto def_max_write_queue_size = def_send_buffer_size*10; constexpr auto def_max_trx_in_progress_size = 100*1024*1024; // 100 MB + constexpr auto def_max_consecutive_rejected_blocks = 13; // num of rejected blocks before disconnect constexpr auto def_max_clients = 25; // 0 for unlimited clients constexpr auto def_max_nodes_per_host = 1; constexpr auto def_conn_retry_wait = 30; @@ -348,7 +349,7 @@ namespace eosio { */ struct peer_block_state { block_id_type id; - uint32_t block_num; + uint32_t block_num{0}; }; typedef multi_index_container< @@ -361,7 +362,7 @@ namespace eosio { struct update_block_num { - uint32_t new_bnum; + uint32_t new_bnum{0}; update_block_num(uint32_t bnum) : new_bnum(bnum) {} void operator() (node_transaction_state& nts) { nts.block_num = new_bnum; @@ -379,9 +380,9 @@ namespace eosio { :start_block( start ), end_block( end ), last( last_acted ), start_time(time_point::now()) {} - uint32_t start_block; - uint32_t end_block; - uint32_t last; ///< last sent or received + uint32_t start_block{0}; + uint32_t end_block{0}; + uint32_t last{0}; ///< last sent or received time_point start_time; ///< time request made or received }; @@ -498,6 +499,7 @@ namespace eosio { bool connecting = false; bool syncing = false; uint16_t protocol_version = 0; + uint16_t consecutive_rejected_blocks = 0; string peer_addr; unique_ptr response_expected; go_away_reason no_retry = no_reason; @@ -528,7 +530,7 @@ namespace eosio { double offset{0}; //!< peer offset static const size_t ts_buffer_size{32}; - char ts[ts_buffer_size]; //!< working buffer for making human readable timestamps + char ts[ts_buffer_size]{}; //!< working buffer for making human readable timestamps /** @} */ bool connected(); @@ -571,11 +573,11 @@ namespace eosio { void enqueue( const net_message &msg, bool trigger_send = true ); void enqueue_block( const signed_block_ptr& sb, bool trigger_send = true, bool to_sync_queue = false); void enqueue_buffer( const std::shared_ptr>& send_buffer, - bool trigger_send, int priority, go_away_reason close_after_send, + bool trigger_send, go_away_reason close_after_send, bool to_sync_queue = false); void cancel_sync(go_away_reason); void flush_queues(); - bool enqueue_sync_block(); + void enqueue_sync_block(); void request_sync_blocks(uint32_t start, uint32_t end); void cancel_wait(); @@ -586,10 +588,9 @@ namespace eosio { void queue_write(const std::shared_ptr>& buff, bool trigger_send, - int priority, std::function callback, bool to_sync_queue = false); - void do_queue_write(int priority); + void do_queue_write(); bool add_peer_block(const peer_block_state& pbs); bool peer_has_block(const block_id_type& blkid); @@ -660,12 +661,12 @@ namespace eosio { in_sync }; - uint32_t sync_known_lib_num; - uint32_t sync_last_requested_num; - uint32_t sync_next_expected_num; - uint32_t sync_req_span; + uint32_t sync_known_lib_num{0}; + uint32_t sync_last_requested_num{0}; + uint32_t sync_next_expected_num{0}; + uint32_t sync_req_span{0}; connection_ptr source; - stages state; + stages state{in_sync}; chain_plugin* chain_plug = nullptr; @@ -797,6 +798,7 @@ namespace eosio { flush_queues(); connecting = false; syncing = false; + consecutive_rejected_blocks = 0; if( last_req ) { my_impl->dispatcher->retry_fetch(shared_from_this()); } @@ -817,7 +819,7 @@ namespace eosio { for(auto tx = my_impl->local_txns.begin(); tx != my_impl->local_txns.end(); ++tx ){ const bool found = known_ids.find( tx->id ) != known_ids.cend(); if( !found ) { - queue_write( tx->serialized_txn, true, priority::low, []( boost::system::error_code ec, std::size_t ) {} ); + queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); } } } @@ -826,7 +828,7 @@ namespace eosio { for(const auto& t : ids) { auto tx = my_impl->local_txns.get().find(t); if( tx != my_impl->local_txns.end() ) { - queue_write( tx->serialized_txn, true, priority::low, []( boost::system::error_code ec, std::size_t ) {} ); + queue_write( tx->serialized_txn, true, []( boost::system::error_code ec, std::size_t ) {} ); } } } @@ -938,7 +940,6 @@ namespace eosio { void connection::queue_write(const std::shared_ptr>& buff, bool trigger_send, - int priority, std::function callback, bool to_sync_queue) { if( !buffer_queue.add_write_queue( buff, callback, to_sync_queue )) { @@ -948,11 +949,11 @@ namespace eosio { return; } if( buffer_queue.is_out_queue_empty() && trigger_send) { - do_queue_write( priority ); + do_queue_write(); } } - void connection::do_queue_write(int priority) { + void connection::do_queue_write() { if( !buffer_queue.ready_to_send() ) return; connection_wptr c(shared_from_this()); @@ -965,8 +966,8 @@ namespace eosio { buffer_queue.fill_out_buffer( bufs ); boost::asio::async_write(*socket, bufs, - boost::asio::bind_executor(strand, [c, socket=socket, priority]( boost::system::error_code ec, std::size_t w ) { - app().post(priority, [c, priority, ec, w]() { + boost::asio::bind_executor(strand, [c, socket=socket]( boost::system::error_code ec, std::size_t w ) { + app().post(priority::high, [c, ec, w]() { try { auto conn = c.lock(); if(!conn) @@ -987,7 +988,7 @@ namespace eosio { } conn->buffer_queue.clear_out_queue(); conn->enqueue_sync_block(); - conn->do_queue_write( priority ); + conn->do_queue_write(); } catch(const std::exception &ex) { auto conn = c.lock(); @@ -1026,26 +1027,28 @@ namespace eosio { } } - bool connection::enqueue_sync_block() { - if (!peer_requested) - return false; - uint32_t num = ++peer_requested->last; - bool trigger_send = num == peer_requested->start_block; - if(num == peer_requested->end_block) { - peer_requested.reset(); - fc_ilog( logger, "completing enqueue_sync_block ${num} to ${p}", ("num", num)("p", peer_name()) ); - } - try { - controller& cc = my_impl->chain_plug->chain(); - signed_block_ptr sb = cc.fetch_block_by_number(num); - if(sb) { - enqueue_block( sb, trigger_send, true); - return true; + void connection::enqueue_sync_block() { + connection_wptr c(shared_from_this()); + app().post( priority::low, [c]() { + auto conn = c.lock(); + if(!conn) return; + if( !conn->peer_requested ) + return; + uint32_t num = ++conn->peer_requested->last; + if( num == conn->peer_requested->end_block ) { + conn->peer_requested.reset(); + fc_ilog( logger, "completing enqueue_sync_block ${num} to ${p}", ("num", num)( "p", conn->peer_name() ) ); } - } catch ( ... ) { - fc_wlog( logger, "write loop exception" ); - } - return false; + try { + controller& cc = my_impl->chain_plug->chain(); + signed_block_ptr sb = cc.fetch_block_by_number( num ); + if( sb ) { + conn->enqueue_block( sb, true, true ); + } + } catch( ... ) { + fc_wlog( logger, "write loop exception" ); + } + } ); } void connection::enqueue( const net_message& m, bool trigger_send ) { @@ -1066,7 +1069,7 @@ namespace eosio { ds.write( header, header_size ); fc::raw::pack( ds, m ); - enqueue_buffer( send_buffer, trigger_send, priority::low, close_after_send ); + enqueue_buffer( send_buffer, trigger_send, close_after_send ); } template< typename T> @@ -1102,15 +1105,15 @@ namespace eosio { } void connection::enqueue_block( const signed_block_ptr& sb, bool trigger_send, bool to_sync_queue) { - enqueue_buffer( create_send_buffer( sb ), trigger_send, priority::low, no_reason, to_sync_queue); + enqueue_buffer( create_send_buffer( sb ), trigger_send, no_reason, to_sync_queue); } void connection::enqueue_buffer( const std::shared_ptr>& send_buffer, - bool trigger_send, int priority, go_away_reason close_after_send, + bool trigger_send, go_away_reason close_after_send, bool to_sync_queue) { connection_wptr weak_this = shared_from_this(); - queue_write(send_buffer,trigger_send, priority, + queue_write(send_buffer,trigger_send, [weak_this, close_after_send](boost::system::error_code ec, std::size_t ) { connection_ptr conn = weak_this.lock(); if (conn) { @@ -1587,7 +1590,7 @@ namespace eosio { } void sync_manager::rejected_block(const connection_ptr& c, uint32_t blk_num) { - if (state != in_sync ) { + if ( ++c->consecutive_rejected_blocks > def_max_consecutive_rejected_blocks ) { fc_wlog( logger, "block ${bn} not accepted from ${p}, closing connection", ("bn",blk_num)("p",c->peer_name()) ); sync_last_requested_num = 0; source.reset(); @@ -1675,7 +1678,7 @@ namespace eosio { send_buffer = create_send_buffer( bs->block ); } fc_dlog(logger, "bcast block ${b} to ${p}", ("b", bnum)("p", cp->peer_name())); - cp->enqueue_buffer( send_buffer, true, priority::high, no_reason ); + cp->enqueue_buffer( send_buffer, true, no_reason ); } } @@ -1692,6 +1695,7 @@ namespace eosio { } fc_dlog(logger, "canceling wait on ${p}", ("p",c->peer_name())); + c->consecutive_rejected_blocks = 0; c->cancel_wait(); } @@ -2235,7 +2239,7 @@ namespace eosio { void net_plugin_impl::send_transaction_to_all(const std::shared_ptr>& send_buffer, VerifierFunc verify) { for( auto &c : connections) { if( c->current() && verify( c )) { - c->enqueue_buffer( send_buffer, true, priority::low, no_reason ); + c->enqueue_buffer( send_buffer, true, no_reason ); } } } @@ -2543,7 +2547,7 @@ namespace eosio { fc_dlog(logger, "got a packed transaction, cancel wait"); peer_ilog(c, "received packed_transaction"); controller& cc = my_impl->chain_plug->chain(); - if( cc.get_read_mode() == eosio::db_read_mode::READ_ONLY ) { + if( db_mode_is_immutable(cc.get_read_mode()) ) { fc_dlog(logger, "got a txn in read-only mode - dropping"); return; } @@ -3111,7 +3115,7 @@ namespace eosio { my->incoming_transaction_ack_subscription = app().get_channel().subscribe(boost::bind(&net_plugin_impl::transaction_ack, my.get(), _1)); - if( cc.get_read_mode() == chain::db_read_mode::READ_ONLY ) { + if( cc.in_immutable_mode() ) { my->max_nodes_per_host = 0; fc_ilog( logger, "node in read-only mode setting max_nodes_per_host to 0 to prevent connections" ); } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index f207602aee..3fbf37140b 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1301,7 +1301,7 @@ enum class tx_category { producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { chain::controller& chain = chain_plug->chain(); - if( chain.get_read_mode() == chain::db_read_mode::READ_ONLY ) + if( chain.in_immutable_mode() ) return start_block_result::waiting; fc_dlog(_log, "Starting block at ${time}", ("time", fc::time_point::now())); diff --git a/unittests/forked_tests.cpp b/unittests/forked_tests.cpp index cf666b06ab..7dc6e6daf3 100644 --- a/unittests/forked_tests.cpp +++ b/unittests/forked_tests.cpp @@ -409,7 +409,7 @@ BOOST_AUTO_TEST_SUITE(forked_tests) BOOST_CHECK_EQUAL(head_block_num, read_only.control->fork_db_head_block_num()); BOOST_CHECK_EQUAL(head_block_num, read_only.control->head_block_num()); - tester irreversible(setup_policy::old_bios_only, db_read_mode::IRREVERSIBLE); + tester irreversible(setup_policy::none, db_read_mode::IRREVERSIBLE); push_blocks(c, irreversible); BOOST_CHECK_EQUAL(head_block_num, irreversible.control->fork_db_pending_head_block_num()); BOOST_CHECK_EQUAL(last_irreversible_block_num, irreversible.control->fork_db_head_block_num());