@@ -1006,6 +1006,8 @@ struct controller_impl {
1006
1006
async_t async_aggregation = async_t ::yes; // by default we process incoming votes asynchronously
1007
1007
my_finalizers_t my_finalizers;
1008
1008
std::atomic<bool > writing_snapshot = false ;
1009
+ std::atomic<bool > applying_block = false ;
1010
+ platform_timer& main_thread_timer;
1009
1011
1010
1012
thread_local static platform_timer timer; // a copy for main thread and each read-only thread
1011
1013
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
@@ -1285,6 +1287,7 @@ struct controller_impl {
1285
1287
read_mode( cfg.read_mode ),
1286
1288
thread_pool(),
1287
1289
my_finalizers(cfg.finalizers_dir / config::safety_filename),
1290
+ main_thread_timer(timer), // assumes constructor is called from main thread
1288
1291
wasmif( conf.wasm_runtime, conf.eosvmoc_tierup, db, conf.state_dir, conf.eosvmoc_config, !conf.profile_accounts.empty() )
1289
1292
{
1290
1293
assert (cfg.chain_thread_pool_size > 0 );
@@ -1542,10 +1545,14 @@ struct controller_impl {
1542
1545
auto mark_branch_irreversible = [&, this ](auto & fork_db) {
1543
1546
assert (!irreversible_mode () || fork_db.head ());
1544
1547
const auto & head_id = irreversible_mode () ? fork_db.head ()->id () : chain_head.id ();
1548
+ const auto head_num = block_header::num_from_id (head_id);
1545
1549
// verifies lib is on head branch, otherwise returns an empty branch
1546
- // The new lib needs to be on the head branch because the fork_db.advance_root() below could purge blocks that
1547
- // would be needed to be re-applied on a fork switch from the exiting chain_head.
1548
- auto branch = fork_db.fetch_branch (head_id, new_lib_id);
1550
+ // The new lib needs to be on the head branch because the forkdb.advance_root() below could purge blocks that
1551
+ // would be needed to be re-applied on a fork switch from the exiting chain_head.
1552
+ // Pending LIB can be greater than chain head, for example when syncing, in that case fetch branch from the
1553
+ // pending LIB. If the pending LIB not found on the head branch then fetch_branch returns an empty branch.
1554
+ // Otherwise fetch_branch will return from chain_head to root iff chain_head on pending LIB branch.
1555
+ auto branch = new_lib_num <= head_num ? fork_db.fetch_branch (head_id, new_lib_id) : fork_db.fetch_branch (new_lib_id, head_id);
1549
1556
try {
1550
1557
auto should_process = [&](auto & bsp) {
1551
1558
// Only make irreversible blocks that have been validated. Blocks in the fork database may not be on our current best head
@@ -3780,6 +3787,9 @@ struct controller_impl {
3780
3787
}
3781
3788
}
3782
3789
3790
+ applying_block = true ;
3791
+ auto apply = fc::make_scoped_exit ([&](){ applying_block = false ; });
3792
+
3783
3793
transaction_trace_ptr trace;
3784
3794
3785
3795
size_t packed_idx = 0 ;
@@ -3806,7 +3816,11 @@ struct controller_impl {
3806
3816
std::holds_alternative<transaction_id_type>(receipt.trx );
3807
3817
3808
3818
if ( transaction_failed && !transaction_can_fail) {
3809
- edump ((*trace));
3819
+ if (trace->except ->code () == interrupt_exception::code_value) {
3820
+ ilog (" Interrupt of trx id: ${id}" , (" id" , trace->id ));
3821
+ } else {
3822
+ edump ((*trace));
3823
+ }
3810
3824
throw *trace->except ;
3811
3825
}
3812
3826
@@ -3875,7 +3889,8 @@ struct controller_impl {
3875
3889
} catch ( const boost::interprocess::bad_alloc& ) {
3876
3890
throw ;
3877
3891
} catch ( const fc::exception & e ) {
3878
- edump ((e.to_detail_string ()));
3892
+ if (e.code () != interrupt_exception::code_value)
3893
+ edump ((e.to_detail_string ()));
3879
3894
abort_block ();
3880
3895
throw ;
3881
3896
} catch ( const std::exception & e ) {
@@ -4365,7 +4380,15 @@ struct controller_impl {
4365
4380
log_irreversible ();
4366
4381
transition_to_savanna_if_needed ();
4367
4382
return controller::apply_blocks_result::complete;
4368
- } FC_LOG_AND_RETHROW ( )
4383
+ } catch (fc::exception & e) {
4384
+ if (e.code () != interrupt_exception::code_value) {
4385
+ wlog (" ${d}" , (" d" ,e.to_detail_string ()));
4386
+ FC_RETHROW_EXCEPTION (e, warn, " rethrow" );
4387
+ }
4388
+ throw ;
4389
+ } catch (...) {
4390
+ try { throw ; } FC_LOG_AND_RETHROW ()
4391
+ }
4369
4392
}
4370
4393
4371
4394
controller::apply_blocks_result maybe_apply_blocks ( const forked_callback_t & forked_cb, const trx_meta_cache_lookup& trx_lookup )
@@ -4437,8 +4460,12 @@ struct controller_impl {
4437
4460
} catch ( const boost::interprocess::bad_alloc& ) {
4438
4461
throw ;
4439
4462
} catch (const fc::exception & e) {
4440
- elog (" exception thrown while applying block ${bn} : ${id}, previous ${p}, error: ${e}" ,
4441
- (" bn" , bsp->block_num ())(" id" , bsp->id ())(" p" , bsp->previous ())(" e" , e.to_detail_string ()));
4463
+ if (e.code () == interrupt_exception::code_value) {
4464
+ ilog (" interrupt while applying block ${bn} : ${id}" , (" bn" , bsp->block_num ())(" id" , bsp->id ()));
4465
+ } else {
4466
+ elog (" exception thrown while applying block ${bn} : ${id}, previous ${p}, error: ${e}" ,
4467
+ (" bn" , bsp->block_num ())(" id" , bsp->id ())(" p" , bsp->previous ())(" e" , e.to_detail_string ()));
4468
+ }
4442
4469
except = std::current_exception ();
4443
4470
} catch (const std::exception & e) {
4444
4471
elog (" exception thrown while applying block ${bn} : ${id}, previous ${p}, error: ${e}" ,
@@ -4501,6 +4528,16 @@ struct controller_impl {
4501
4528
return applied_trxs;
4502
4529
}
4503
4530
4531
+ void interrupt_transaction () {
4532
+ // Only interrupt transaction if applying a block. Speculative trxs already have a deadline set so they
4533
+ // have limited run time already. This is to allow killing a long-running transaction in a block being
4534
+ // validated.
4535
+ if (applying_block) {
4536
+ ilog (" Interrupting apply block" );
4537
+ main_thread_timer.expire_now ();
4538
+ }
4539
+ }
4540
+
4504
4541
// @param if_active true if instant finality is active
4505
4542
static checksum256_type calc_merkle ( deque<digest_type>&& digests, bool if_active ) {
4506
4543
if (if_active) {
@@ -5261,6 +5298,10 @@ deque<transaction_metadata_ptr> controller::abort_block() {
5261
5298
return my->abort_block ();
5262
5299
}
5263
5300
5301
+ void controller::interrupt_transaction () {
5302
+ my->interrupt_transaction ();
5303
+ }
5304
+
5264
5305
boost::asio::io_context& controller::get_thread_pool () {
5265
5306
return my->thread_pool .get_executor ();
5266
5307
}
0 commit comments