From fd88c431c18a9b8b330de93181d58756c6df606a Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 14 Jul 2026 16:52:34 -0500 Subject: [PATCH] Fix task-slot collision when pathfinding scores sync is enabled The pathfinding scores sync task claimed the runtime's single background-processor slot, which LDK's background processor also claims later during startup. With a scores sync URL configured, node startup tripped a debug_assert in debug builds; in release builds the second spawn silently dropped the scores-sync task's join handle, so the task was detached and never joined at shutdown. Spawn it as a cancellable background task instead, matching the RGS gossip sync task, so it is cancelled with the other such tasks in Node::stop. Co-Authored-By: Claude Fable 5 --- src/scoring.rs | 2 +- tests/integration_tests_rust.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/scoring.rs b/src/scoring.rs index 401d9c3f1f..b5c2c9a638 100644 --- a/src/scoring.rs +++ b/src/scoring.rs @@ -26,7 +26,7 @@ pub fn setup_background_pathfinding_scores_sync( let logger = Arc::clone(&logger); - runtime.spawn_background_processor_task(async move { + runtime.spawn_cancellable_background_task(async move { let mut interval = tokio::time::interval(EXTERNAL_PATHFINDING_SCORES_SYNC_INTERVAL); loop { tokio::select! { diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index b07a90629f..e921c61014 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -551,6 +551,26 @@ async fn start_stop_reinit() { reinitialized_node.stop().unwrap(); } +// The scores-sync task runs alongside LDK's background processor, which claims the runtime's +// single background-processor slot; startup must not panic with both configured. +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn start_stop_with_pathfinding_scores_sync() { + let (_bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + let config = random_config(true); + + let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap()); + + let mut sync_config = EsploraSyncConfig::default(); + sync_config.background_sync_config = None; + setup_builder!(builder, config.node_config); + builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config)); + builder.set_pathfinding_scores_source(esplora_url); + + let node = builder.build(config.node_entropy.into()).unwrap(); + node.start().unwrap(); + node.stop().unwrap(); +} + #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn onchain_send_receive() { let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();