From c52caca76d534142d785764fb56463ac4d7c0bab Mon Sep 17 00:00:00 2001 From: Tommi Niemi Date: Sat, 31 Jan 2026 20:48:01 +0700 Subject: [PATCH] fix(supervisor): initialize subscriptions before chain scanning fixes race condition where ibc events emitted during or after chain scanning would be lost because event subscriptions weren't active yet. previously the startup order was: 1. chain scanning and worker spawning 2. subscription initialization events emitted between scanning completion and subscription init were lost. for packet events, recovery required clearing interval (if enabled). for handshake events, recovery required hermes restart. the fix moves subscription initialization before chain scanning: 1. subscription initialization 2. chain scanning and worker spawning events now queue in the subscription buffer during scanning and are processed once batch workers are spawned. closes #2748 --- crates/relayer/src/supervisor.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/relayer/src/supervisor.rs b/crates/relayer/src/supervisor.rs index c994ac6585..b91e45846f 100644 --- a/crates/relayer/src/supervisor.rs +++ b/crates/relayer/src/supervisor.rs @@ -173,6 +173,13 @@ pub fn spawn_supervisor_tasks( let workers = Arc::new(RwLock::new(WorkerMap::new())); let client_state_filter = Arc::new(RwLock::new(FilterPolicy::default())); + // Initialize event subscriptions BEFORE scanning chains. + // This prevents a race condition where IBC events emitted during or after + // the chain scan would be lost because subscriptions weren't active yet. + // Events will queue in the subscription buffer and be processed once + // batch workers are spawned. See: https://github.com/informalsystems/hermes/issues/2748 + let subscriptions = init_subscriptions(&config, &mut registry.write())?; + // Only scan when needed if should_scan(&config, &options) { let scan = chain_scanner( @@ -194,8 +201,6 @@ pub fn spawn_supervisor_tasks( .spawn_workers(scan); } - let subscriptions = init_subscriptions(&config, &mut registry.write())?; - let batch_tasks = spawn_batch_workers( &config, registry.clone(),