Skip to content

Commit dd5a078

Browse files
committed
GH-284 Add timelimit to apply_blocks and return if complete or incomplete
1 parent 346e84e commit dd5a078

File tree

5 files changed

+54
-30
lines changed

5 files changed

+54
-30
lines changed

libraries/chain/controller.cpp

+30-15
Original file line numberDiff line numberDiff line change
@@ -1826,8 +1826,9 @@ struct controller_impl {
18261826
// loading from snapshot without a block log so fork_db can't be considered valid
18271827
fork_db_reset_root_to_chain_head();
18281828
} else if( !except_ptr && !check_shutdown() && !irreversible_mode() && forkdb.head()) {
1829-
// applies all blocks up to forkdb head from forkdb
1830-
maybe_apply_blocks(forked_callback_t{}, trx_meta_cache_lookup{});
1829+
// applies all blocks up to forkdb head from forkdb, shouldn't return incomplete, but if it does loop until complete
1830+
while (maybe_apply_blocks(forked_callback_t{}, trx_meta_cache_lookup{}) == controller::apply_blocks_result::incomplete)
1831+
;
18311832
auto head = forkdb.head();
18321833
ilog( "reversible blocks replayed to ${bn} : ${id}", ("bn", head->block_num())("id", head->id()) );
18331834
}
@@ -2008,7 +2009,9 @@ struct controller_impl {
20082009
// See comment below about pause-at-block for why `|| conf.num_configured_p2p_peers > 0`
20092010
if (chain_head_is_root || conf.num_configured_p2p_peers > 0) {
20102011
ilog("applying branch from fork database ending with block: ${id}", ("id", pending_head->id()));
2011-
maybe_apply_blocks(forked_callback_t{}, trx_meta_cache_lookup{});
2012+
// applies all blocks up to forkdb head from forkdb, shouldn't return incomplete, but if it does loop until complete
2013+
while (maybe_apply_blocks(forked_callback_t{}, trx_meta_cache_lookup{}) == controller::apply_blocks_result::incomplete)
2014+
;
20122015
}
20132016
}
20142017
} else {
@@ -4296,23 +4299,25 @@ struct controller_impl {
42964299
} FC_LOG_AND_RETHROW( )
42974300
}
42984301

4299-
void apply_blocks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup) {
4302+
controller::apply_blocks_result apply_blocks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup) {
43004303
try {
43014304
if( !irreversible_mode() ) {
4302-
maybe_apply_blocks( cb, trx_lookup );
4303-
} else {
4304-
log_irreversible();
4305-
transition_to_savanna_if_needed();
4305+
return maybe_apply_blocks( cb, trx_lookup );
43064306
}
4307+
4308+
log_irreversible();
4309+
transition_to_savanna_if_needed();
4310+
return controller::apply_blocks_result::complete;
43074311
} FC_LOG_AND_RETHROW( )
43084312
}
43094313

4310-
void maybe_apply_blocks( const forked_callback_t& forked_cb, const trx_meta_cache_lookup& trx_lookup )
4314+
controller::apply_blocks_result maybe_apply_blocks( const forked_callback_t& forked_cb, const trx_meta_cache_lookup& trx_lookup )
43114315
{
4316+
controller::apply_blocks_result result = controller::apply_blocks_result::complete;
43124317
auto do_apply_blocks = [&](auto& forkdb) {
43134318
auto new_head = forkdb.head(); // use best head
43144319
if (!new_head)
4315-
return; // nothing to do, forkdb at root
4320+
return;// nothing to do, forkdb at root
43164321
auto [new_head_branch, old_head_branch] = forkdb.fetch_branch_from( new_head->id(), chain_head.id() );
43174322

43184323
bool switch_fork = !old_head_branch.empty();
@@ -4358,9 +4363,17 @@ struct controller_impl {
43584363
try {
43594364
bool applied = apply_block( bsp, bsp->is_valid() ? controller::block_status::validated
43604365
: controller::block_status::complete, trx_lookup );
4361-
if (!switch_fork && (!applied || check_shutdown())) {
4362-
shutdown();
4363-
break;
4366+
if (!switch_fork) { // always complete a switch fork
4367+
if (!applied || check_shutdown()) {
4368+
shutdown();
4369+
break; // result should be complete since we are shutting down
4370+
}
4371+
// Break every ~500ms to allow other tasks (e.g. get_info, SHiP) opportunity to run. User expected
4372+
// to call apply_blocks again if this returns incomplete.
4373+
if (!replaying && fc::time_point::now() - start > fc::milliseconds(500)) {
4374+
result = controller::apply_blocks_result::incomplete;
4375+
break;
4376+
}
43644377
}
43654378
} catch ( const std::bad_alloc& ) {
43664379
throw;
@@ -4417,6 +4430,8 @@ struct controller_impl {
44174430
};
44184431

44194432
fork_db.apply<void>(do_apply_blocks);
4433+
4434+
return result;
44204435
}
44214436

44224437
deque<transaction_metadata_ptr> abort_block() {
@@ -5179,9 +5194,9 @@ void controller::set_async_aggregation(async_t val) {
51795194
my->async_aggregation = val;
51805195
}
51815196

5182-
void controller::apply_blocks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup) {
5197+
controller::apply_blocks_result controller::apply_blocks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup) {
51835198
validate_db_available_size();
5184-
my->apply_blocks(cb, trx_lookup);
5199+
return my->apply_blocks(cb, trx_lookup);
51855200
}
51865201

51875202

libraries/chain/include/eosio/chain/controller.hpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,20 @@ namespace eosio::chain {
230230
void set_async_voting(async_t val);
231231
void set_async_aggregation(async_t val);
232232

233-
/// Apply any blocks that are ready from the forkdb
234-
void apply_blocks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup);
235-
236233
struct accepted_block_result {
237234
const bool is_new_best_head = false; // true if new best head
238235
std::optional<block_handle> block; // empty optional if block is unlinkable
239236
};
240237
// thread-safe
241238
accepted_block_result accept_block( const block_id_type& id, const signed_block_ptr& b ) const;
242239

240+
/// Apply any blocks that are ready from the forkdb
241+
enum class apply_blocks_result {
242+
complete, // all ready blocks in forkdb have been applied
243+
incomplete // time limit reached, additional blocks may be available in forkdb to process
244+
};
245+
apply_blocks_result apply_blocks(const forked_callback_t& cb, const trx_meta_cache_lookup& trx_lookup);
246+
243247
boost::asio::io_context& get_thread_pool();
244248

245249
const chainbase::database& db()const;

plugins/chain_interface/include/eosio/chain/plugin_interface.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace eosio::chain::plugin_interface {
3030
namespace incoming {
3131
namespace methods {
3232
// synchronously push a block/trx to a single provider, block_state_legacy_ptr may be null
33-
using block_sync = method_decl<chain_plugin_interface, bool(const signed_block_ptr&, const block_id_type&, const block_handle&), first_provider_policy>;
33+
using block_sync = method_decl<chain_plugin_interface, controller::apply_blocks_result(const signed_block_ptr&, const block_id_type&, const block_handle&), first_provider_policy>;
3434
using transaction_async = method_decl<chain_plugin_interface, void(const packed_transaction_ptr&, bool, transaction_metadata::trx_type, bool, next_function<transaction_trace_ptr>), first_provider_policy>;
3535
}
3636
}

plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class producer_plugin : public appbase::plugin<producer_plugin> {
8181
virtual void plugin_shutdown();
8282
void handle_sighup() override;
8383

84-
bool on_incoming_block();
84+
controller::apply_blocks_result on_incoming_block();
8585

8686
void pause();
8787
void resume();

plugins/producer_plugin/producer_plugin.cpp

+15-10
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
892892

893893
// called on incoming blocks from net_plugin on the main thread. Will notify controller to process any
894894
// blocks ready in the fork database.
895-
bool on_incoming_block() {
895+
controller::apply_blocks_result on_incoming_block() {
896896
auto now = fc::time_point::now();
897897
_time_tracker.add_idle_time(now);
898898

@@ -905,12 +905,14 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
905905
("num", fhead.block_num())("id", fhead.id()));
906906
}
907907
_time_tracker.add_other_time();
908-
return true; // return true because block was accepted
908+
// return complete as we are producing and don't want to be interrupted right now. Next start_block will
909+
// give an opportunity for this incoming block to be processed.
910+
return controller::apply_blocks_result::complete;
909911
}
910912

911913
// no reason to abort_block if we have nothing ready to process
912914
if (chain.head().id() == chain.fork_db_head().id()) {
913-
return true; // return true as nothing failed
915+
return controller::apply_blocks_result::complete; // nothing to do
914916
}
915917

916918
// start a new speculative block, adds to time tracker which includes this method's time
@@ -919,21 +921,22 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
919921
// abort the pending block
920922
abort_block();
921923

924+
controller::apply_blocks_result result = controller::apply_blocks_result::complete;
922925
try {
923-
chain.apply_blocks(
926+
result = chain.apply_blocks(
924927
[this](const transaction_metadata_ptr& trx) { _unapplied_transactions.add_forked(trx); },
925928
[this](const transaction_id_type& id) { return _unapplied_transactions.get_trx(id); });
926929
} catch (const guard_exception& e) {
927930
chain_plugin::handle_guard_exception(e);
928-
return false;
931+
return controller::apply_blocks_result::complete; // shutting down
929932
} catch (const std::bad_alloc&) {
930933
chain_apis::api_base::handle_bad_alloc();
931934
} catch (boost::interprocess::bad_alloc&) {
932935
chain_apis::api_base::handle_db_exhaustion();
933936
} catch (const fork_database_exception& e) {
934937
fc_elog(_log, "Cannot recover from ${e}. Shutting down.", ("e", e.to_detail_string()));
935938
appbase::app().quit();
936-
return false;
939+
return controller::apply_blocks_result::complete; // shutting down
937940
} catch (const fc::exception& e) {
938941
throw;
939942
} catch (const std::exception& e) {
@@ -945,7 +948,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
945948
_production_enabled = true;
946949
}
947950

948-
return true;
951+
return result;
949952
}
950953

951954
void restart_speculative_block() {
@@ -1650,7 +1653,7 @@ void producer_plugin::handle_sighup() {
16501653
fc::logger::update(transient_trx_failed_trace_logger_name, _transient_trx_failed_trace_log);
16511654
}
16521655

1653-
bool producer_plugin::on_incoming_block() {
1656+
controller::apply_blocks_result producer_plugin::on_incoming_block() {
16541657
return my->on_incoming_block();
16551658
}
16561659

@@ -1992,8 +1995,10 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
19921995

19931996
abort_block();
19941997

1995-
chain.apply_blocks([this](const transaction_metadata_ptr& trx) { _unapplied_transactions.add_forked(trx); },
1996-
[this](const transaction_id_type& id) { return _unapplied_transactions.get_trx(id); });
1998+
auto r = chain.apply_blocks([this](const transaction_metadata_ptr& trx) { _unapplied_transactions.add_forked(trx); },
1999+
[this](const transaction_id_type& id) { return _unapplied_transactions.get_trx(id); });
2000+
if (r != controller::apply_blocks_result::complete)
2001+
return start_block_result::failed;
19972002

19982003
if (chain.should_terminate()) {
19992004
app().quit();

0 commit comments

Comments
 (0)