From c1313b199fe320c8d3e7ba01577378dfb85009cf Mon Sep 17 00:00:00 2001 From: ismaelsadeeq Date: Fri, 3 Jul 2026 15:28:29 +0100 Subject: [PATCH] init: wake genesis wait after ImportBlocks() returns If shutdown interrupts ImportBlocks() before genesis activation, no blockTip notification is sent. The wait predicate allows shutdown to occur, but the condition variable is never notified, so init can remain stuck waiting for genesis activation. Notify the tip condition variable after ImportBlocks() returns so interrupted imports wake the wait and let it observe the shutdown request. Add test coverage for interrupting startup after reindex block files import begins, which exercises the path where ImportBlocks() can return before genesis activation. --- src/init.cpp | 8 +++++++- test/functional/feature_init.py | 9 +++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 0e72443cc33..290f0936807 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2045,10 +2045,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } /// \anchor initload - node.background_init_thread = std::thread(&util::TraceThread, "initload", [=, &chainman, &args, &node] { + node.background_init_thread = std::thread(&util::TraceThread, "initload", [=, &chainman, &args, &kernel_notifications, &node] { ScheduleBatchPriority(); // Import blocks and ActivateBestChain() ImportBlocks(chainman, vImportFiles); + // An interrupted import may return without activating genesis. Wake + // the init thread's genesis wait, which is otherwise only notified + // on blockTip, and that never fires when the import was interrupted + // before activating genesis. This wakeup lets the wait observe the + // shutdown request. + WITH_LOCK(kernel_notifications.m_tip_block_mutex, kernel_notifications.m_tip_block_cv.notify_all()); WITH_LOCK(::cs_main, chainman.UpdateIBDStatus()); if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogInfo("Stopping after block import"); diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py index ad20e39cda8..18faba33b3b 100755 --- a/test/functional/feature_init.py +++ b/test/functional/feature_init.py @@ -63,6 +63,7 @@ class InitTest(BitcoinTestFramework): node.process.terminate() assert_equal(0, node.process.wait()) + reindex_log_line = b'Reindexing block file blk00000.dat' lines_to_terminate_after = [ b'Validating signatures for all blocks', b'scheduler thread start', @@ -87,16 +88,20 @@ class InitTest(BitcoinTestFramework): ] if self.is_wallet_compiled(): lines_to_terminate_after.append(b'Verifying wallet') + lines_to_terminate_after.append(reindex_log_line) for terminate_line in lines_to_terminate_after: self.log.info(f"Starting node and will terminate after line {terminate_line}") with node.busy_wait_for_debug_log([terminate_line]): + extra_args = [*ALL_INDEX_ARGS] + if terminate_line == reindex_log_line: + extra_args += ['-reindex'] if platform.system() == 'Windows': # CREATE_NEW_PROCESS_GROUP is required in order to be able # to terminate the child without terminating the test. - node.start(extra_args=ALL_INDEX_ARGS, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) + node.start(extra_args=extra_args, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) else: - node.start(extra_args=ALL_INDEX_ARGS) + node.start(extra_args=extra_args) self.log.debug("Terminating node after terminate line was found") sigterm_node()