Skip to content

L1 watcher: reset/channel-swap race can terminate the watcher with the reset unprocessed #29

Description

@dghelm

Problem

L1WatcherHandle::revert_to_l1_block enqueues a ResetToBlock command and immediately drops the old notification receiver (crates/watcher/src/handle/mod.rs). If the watcher is mid-step() sending on the old channel at that moment, the send fails with SendError, which the run() loop treats as terminal — it stops the watcher without draining the queued reset.

Result: a dead watcher and a silently stalled node. No further L1 notifications (batches, messages, finalizations) are ever delivered, with only a single warn line as evidence.

This is pre-existing on feat/tsuki-hardfork-2 and independent of the signer-refresh work — any component that calls revert_to_l1_block under load can trigger it.

Reference fix (mine for parts)

PR #7 (closed unmerged) fixed this in commit 7496ee8 via recover_or_stop_on_closed_channel(): on any closed-channel send, drain the command queue for a pending reset and recover onto the fresh channels; stop only if no reset is queued. The command channel is unbounded, so the recovery cannot deadlock behind a full notification channel. The fix is small and extractable on its own, and the PR branch contains a regression test reproducing the race at the Synced send point.

Found during the PR #7 review cycle (test-coverage analysis, confirmed by differential review).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions