Skip to content

[PR #32] JoinHandle discarded in run_listen — listener panic silent, chain goes dark #95

@obchain

Description

@obchain

PR: #32 feat/07-block-listener
File: crates/charon-cli/src/main.rs — run_listen, inside for loop over chains

Problem

tokio::spawn(async move {
    if let Err(err) = listener.run().await {
        warn!(chain = %name, error = ?err, "listener terminated");
    }
});

JoinHandle dropped immediately. If spawned task panics (unwrap inside ChainProvider::connect or alloy internals), tokio catches panic and marks JoinHandle as panicked — but because handle dropped, panic silently discarded. warn! closure never fires on panic, only on Err. Sender for that chain dropped, meaning no further ChainEvents from that chain, but rx.recv() continues returning events from other chains with no indication chain missing.

Impact

Single-chain panic takes that chain's listener permanently offline for lifetime of process with no observable error, no counter increment, no alert. Single-chain deploy (BSC only): bot runs silently with no events.

Fix

Use tokio::task::JoinSet to collect and supervise handles:

let mut set = tokio::task::JoinSet::new();
for (name, chain_cfg) in config.chain {
    let tx2 = tx.clone();
    set.spawn(async move { ... });
}
drop(tx);
// In select! arm, await set.join_next() and log panics.

Or store handles in Vec<JoinHandle<_>> and poll in drain loop. At minimum, join_all on shutdown should surface panics.

Metadata

Metadata

Assignees

No one assigned

    Labels

    layer:rustRust crates (core / scanner / protocols / executor / cli)pr-reviewFindings from PR review processpriority:p1-coreCore MVP scopetype:featureNew capability or deliverable

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions