Skip to content

Push-on-receive silently dropped after cosigner restart until a client calls GetArkInfo (empty ASP-info cache) #37

@aruokhai

Description

@aruokhai

Summary

After a cosigner-runtime restart, FCM vtxo_received push notifications are silently dropped until at least one client makes an authenticated call that populates the shared ASP-info cache (e.g. GetArkInfo on connect). The incoming VTXO is still discovered via the indexer path (balance updates), but the push that drives background auto-delegate / auto-settle is never sent.

Root cause

vtxo_stream::process_notification reads the shared ASP-info cache directly and bails on a miss:

cosigner-runtime/src/vtxo_stream.rs:60-72

let guard = asp.lock().await;
match guard.info.as_ref() {
    Some(i) => i.clone(),
    None => {
        tracing::warn!("ASP info not cached, skipping VTXO stream notification");
        return;
    }
}

The cache (AspClient.info behind shared.asp_client) is only populated lazily by fetch_asp_info (cosigner-runtime/src/cosigner/handlers/ark.rs:34), which runs from authenticated handlers such as get_ark_info. On a fresh restart with no connected clients, the cache stays empty, so every stream notification is skipped → no pushes.

Note the inconsistency: fetch_asp_info handles a cache miss by calling get_info(), but process_notification does not — it just skips.

Evidence (regtest)

Server log shortly after a restart:

  60.13s  INFO VTXO stream: connected to arkd, listening for events
1190.11s  WARN ASP info not cached, skipping VTXO stream notification
1191.93s  WARN ASP info not cached, skipping VTXO stream notification

The 1190s warning (≈19.8 min after the ~start) coincided exactly with an incoming off-chain receive. No push was sent and the device's background auto-delegate never fired. Opening the app once (which calls GetArkInfo → populates the cache) immediately restored pushes for subsequent receives.

Impact

  • Push-on-receive — and therefore background auto-delegate and the auto-settle that depends on a stored delegate — is dead from server start until some client calls GetArkInfo.
  • Usually masked in production (clients connect frequently), but a user whose app is fully closed across a cosigner restart would not be woken for incoming VTXOs until another GetArkInfo lands. That's exactly the "auto-delegate works in the lab but not in production" failure mode.

Proposed fix (either, ideally both)

  1. Pre-warm on startup — call get_info() once when the VTXO stream connects to arkd (cosigner-runtime/src/main.rs:176vtxo_stream::run_vtxo_stream), before processing notifications.
  2. Fetch-on-miss in the stream — make process_notification fetch-and-cache on a miss (mirror fetch_asp_info's get_info() fallback) instead of skipping. Robust against cache eviction too.

Repro

  1. Start cosigner-runtime fresh (ASP configured), with no clients connected.
  2. Send an off-chain VTXO to a user that has a registered FCM token.
  3. Observe ASP info not cached, skipping VTXO stream notification and no push.
  4. Connect a client (any GetArkInfo call), repeat the send → push now fires.

Files

  • cosigner-runtime/src/vtxo_stream.rs (process_notification)
  • cosigner-runtime/src/cosigner/handlers/ark.rs:34 (fetch_asp_info)
  • cosigner-runtime/src/main.rs:176 (vtxo stream task start)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions