diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index eb60ec697d..1cb4f7eb81 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -3901,7 +3901,7 @@ struct controller_impl { // extract current block extension and previous header extension auto block_exts = b->validate_and_extract_extensions(); const finality_extension* prev_finality_ext = prev.header_extension(); - std::optional finality_ext = b->extract_header_extension(f_ext_id); + std::optional finality_ext = b->extract_header_extension(f_ext_id); const auto qc_ext_itr = block_exts.find(qc_ext_id); bool qc_extension_present = (qc_ext_itr != block_exts.end()); @@ -4101,10 +4101,12 @@ struct controller_impl { assert(is_proper_savanna_block == b->is_proper_svnn_block()); std::optional qc = verify_basic_block_invariants(id, b, prev); - + log_and_drop_future verify_qc_future; if constexpr (is_proper_savanna_block) { if (qc) { - verify_qc(prev, *qc); + verify_qc_future = post_async_task(thread_pool.get_executor(), [this, &qc, &prev] { + verify_qc(prev, *qc); + }); } } @@ -4128,11 +4130,19 @@ struct controller_impl { EOS_ASSERT( id == bsp->id(), block_validate_exception, "provided id ${id} does not match block id ${bid}", ("id", id)("bid", bsp->id()) ); + if constexpr (is_proper_savanna_block) { + assert(!!qc == verify_qc_future.valid()); + if (qc) { + verify_qc_future.get(); + } integrate_received_qc_to_block(bsp); // Save the received QC as soon as possible, no matter whether the block itself is valid or not consider_voting(bsp, use_thread_pool_t::no); + } else { + assert(!verify_qc_future.valid()); } + if (!should_terminate(bsp->block_num())) { forkdb.add(bsp, ignore_duplicate_t::yes); if constexpr (is_proper_savanna_block) diff --git a/libraries/chain/include/eosio/chain/thread_utils.hpp b/libraries/chain/include/eosio/chain/thread_utils.hpp index 97971eec2a..ad450e696c 100644 --- a/libraries/chain/include/eosio/chain/thread_utils.hpp +++ b/libraries/chain/include/eosio/chain/thread_utils.hpp @@ -82,6 +82,37 @@ namespace eosio { namespace chain { } }; + /** + * Wrap a std::future so that any exception on destruction is caught, logged, and dropped. + * @tparam Response future type + */ + template + struct log_and_drop_future { + log_and_drop_future() = default; + explicit log_and_drop_future(std::future&& f) : fut(f) {}; + + // Only call on default constructed log_and_drop_future. + log_and_drop_future& operator=(std::future&& f) { + assert(!fut.valid()); + fut = std::move(f); + return *this; + } + + Response get() { cancel(); return fut.get(); } + bool valid() const { return fut.valid(); } + void cancel() { fut_exit_scope_handler.cancel(); } + private: + std::future fut; + fc::scoped_exit> fut_exit_scope_handler = [this] { + if (fut.valid()) { + try { + fut.get(); + } FC_LOG_AND_DROP() + } + }; + }; + + inline std::string set_current_thread_name_to_typename(const std::type_info& tinfo, const unsigned i) { std::string tn = boost::core::demangle(tinfo.name()); const size_t offset = tn.rfind("::"); @@ -294,5 +325,3 @@ namespace eosio { namespace chain { } } } // eosio::chain - -