From c1afd1ce8ba08ad997299d053bc861d9f5ec9a00 Mon Sep 17 00:00:00 2001 From: 2rdzy <232089760+2rdzy@users.noreply.github.com> Date: Thu, 8 Oct 2026 12:31:42 +0200 Subject: [PATCH] init: wake genesis wait after interrupted import An interrupted import may return from ImportBlocks without activating genesis. The init thread's wait for genesis is only woken by blockTip, which never fires in that case, so a shutdown request arriving during -reindex can leave startup blocked forever. Notify m_tip_block_cv after the import so the wait can observe the shutdown request. Adapted from bitcoin/bitcoin#35652. --- src/init.cpp | 8 +++++++- test/functional/feature_init.py | 7 +++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 70615a191be1..a85aa8c7848d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1839,10 +1839,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) vImportFiles.push_back(fs::PathFromString(strFile)); } - 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()); if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); if (!(Assert(node.shutdown_request))()) { diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py index 7c157b5267de..1da7cb11849a 100755 --- a/test/functional/feature_init.py +++ b/test/functional/feature_init.py @@ -62,6 +62,7 @@ def check_clean_start(): node.wait_for_rpc_connection() assert_equal(200, node.getblockcount()) + reindex_log_line = b'Reindexing block file blk00000.dat' lines_to_terminate_after = [ b'Validating signatures for all blocks', b'scheduler thread start', @@ -85,17 +86,19 @@ def check_clean_start(): ] if self.is_wallet_compiled(): lines_to_terminate_after.append(b'Verifying wallet') + lines_to_terminate_after.append(reindex_log_line) args = ['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'] for terminate_line in lines_to_terminate_after: self.log.info(f"Starting node and will exit after line {terminate_line}") with node.busy_wait_for_debug_log([terminate_line]): + extra_args = ['-reindex'] if terminate_line == reindex_log_line else [*args] 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=args, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) + node.start(extra_args=extra_args, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) else: - node.start(extra_args=args) + node.start(extra_args=extra_args) self.log.debug("Terminating node after terminate line was found") sigterm_node()