diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 0c1b096737..a4be1c536c 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1070,6 +1070,12 @@ struct controller_impl { }); } + bool fork_db_validated_block_exists( const block_id_type& id ) const { + return fork_db.apply([&](const auto& forkdb) { + return forkdb.validated_block_exists(id); + }); + } + signed_block_ptr fork_db_fetch_block_by_id( const block_id_type& id ) const { return fork_db.apply([&](const auto& forkdb) { auto bsp = forkdb.get_block(id); @@ -4930,6 +4936,14 @@ bool controller::block_exists(const block_id_type& id) const { return false; } +bool controller::validated_block_exists(const block_id_type& id) const { + bool exists = my->fork_db_validated_block_exists(id); + if( exists ) return true; + std::optional sbh = my->blog.read_block_header_by_num( block_header::num_from_id(id) ); + if( sbh && sbh->calculate_id() == id ) return true; + return false; +} + std::optional controller::fetch_block_header_by_id( const block_id_type& id )const { auto sb_ptr = my->fork_db_fetch_block_by_id(id); if( sb_ptr ) return *static_cast(sb_ptr.get()); diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 5cda182450..c054836dc5 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -128,6 +128,7 @@ namespace eosio::chain { bsp_t get_block_impl( const block_id_type& id, include_root_t include_root = include_root_t::no ) const; bool block_exists_impl( const block_id_type& id ) const; + bool validated_block_exists_impl( const block_id_type& id ) const; void reset_root_impl( const bsp_t& root_bs ); void rollback_head_to_root_impl(); void advance_root_impl( const block_id_type& id ); @@ -664,7 +665,19 @@ namespace eosio::chain { return index.find( id ) != index.end(); } - // ------------------ fork_database ------------------------- + template + bool fork_database_t::validated_block_exists(const block_id_type& id) const { + std::lock_guard g( my->mtx ); + return my->validated_block_exists_impl(id); + } + + template + bool fork_database_impl::validated_block_exists_impl(const block_id_type& id) const { + auto itr = index.find( id ); + return itr != index.end() && bs_accessor_t::is_valid(*(*itr)); + } + +// ------------------ fork_database ------------------------- fork_database::fork_database(const std::filesystem::path& data_dir) : data_dir(data_dir) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 0eeed40015..fc9044aece 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -276,7 +276,8 @@ namespace eosio::chain { // thread-safe signed_block_ptr fetch_block_by_id( const block_id_type& id )const; // thread-safe - bool block_exists( const block_id_type& id)const; + bool block_exists(const block_id_type& id) const; + bool validated_block_exists(const block_id_type& id) const; // thread-safe std::optional fetch_block_header_by_number( uint32_t block_num )const; // thread-safe diff --git a/libraries/chain/include/eosio/chain/fork_database.hpp b/libraries/chain/include/eosio/chain/fork_database.hpp index 4f26eb547a..39d37cef00 100644 --- a/libraries/chain/include/eosio/chain/fork_database.hpp +++ b/libraries/chain/include/eosio/chain/fork_database.hpp @@ -51,6 +51,7 @@ namespace eosio::chain { bsp_t get_block( const block_id_type& id, include_root_t include_root = include_root_t::no ) const; bool block_exists( const block_id_type& id ) const; + bool validated_block_exists( const block_id_type& id ) const; /** * Purges any existing blocks from the fork database and resets the root block_header_state to the provided value. diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index db0d97c3dd..852f2a0d1d 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3847,7 +3847,7 @@ namespace eosio { uint32_t lib = cc.last_irreversible_block_num(); try { - if( blk_num <= lib ) { + if( blk_num <= lib || cc.validated_block_exists(blk_id) ) { c->strand.post( [sync_master = my_impl->sync_master.get(), &dispatcher = my_impl->dispatcher, c, blk_id, blk_num]() { dispatcher.add_peer_block( blk_id, c->connection_id ); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index d0cb33fbbc..976a08b77a 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -677,18 +677,14 @@ class producer_plugin_impl : public std::enable_shared_from_thistimestamp < fc::minutes(5) || (blk_num % 1000 == 0)) // only log every 1000 during sync fc_dlog(_log, "received incoming block ${n} ${id}", ("n", blk_num)("id", id)); - // start a new speculative block, speculative start_block may have been interrupted - auto ensure = fc::make_scoped_exit([this]() { - // avoid schedule_production_loop if in_producing_mode(); speculative block was not interrupted and we don't want to abort block - if (!in_producing_mode()) { - schedule_production_loop(); - } else { - _time_tracker.add_other_time(); - } - }); - auto& chain = chain_plug->chain(); + // de-dupe here... no point in aborting block if we already know the block; avoid exception in create_block_handle_future + if (chain.validated_block_exists(id)) { + _time_tracker.add_other_time(); + return true; // return true because the block was already accepted + } + EOS_ASSERT(block->timestamp < (now + fc::seconds(7)), block_from_the_future, "received a block from the future, ignoring it: ${id}", ("id", id)); // start processing of block @@ -701,9 +697,13 @@ class producer_plugin_impl : public std::enable_shared_from_this