Skip to content

vtxo_stream: batch delegate-invalidation + VTXO save into a single sled write #33

@aruokhai

Description

@aruokhai

Problem

In cosigner-runtime/src/cosigner/handlers/vtxo_stream.rs, the delegate-invalidation path writes to two separate sled trees in sequence with no transaction wrapping them:

  • Lines 85-89:
    state.delegate_session = None;
    super::helpers::delete_user_delegate(...);  // sled write #1
    ...
    save_user_vtxos(...);                       // sled write #2
  • Same shape at lines 172-176.

If cosigner-runtime crashes between the two writes, sled is left with:

  • delegate_sessions row deleted ✓
  • vtxo_store row still pointing at outpoints the ASP just told us are spent ✗

Impact

Low in practice — the inconsistency self-heals on the next vtxo_stream message (the ASP re-emits the spent state on reconnect, and apply_stream_update reconciles). But there's a one-stream-update window where a freshly-spawned actor sees stale VTXOs without a covering delegate. A user opening the app in that window could see briefly-outdated state.

Suggested fix

Wrap both writes in a sled Batch (sled supports cross-tree batches) so the post-crash state is either both-applied or both-rolled-back.

Discovered during PR #32 review.

Metadata

Metadata

Assignees

No one assigned

    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