Skip to content

db: Preserve OOR dispatch idempotency keys - #1109

Open
bhandras wants to merge 1 commit into
mainfrom
agent/preserve-oor-idempotency-key
Open

db: Preserve OOR dispatch idempotency keys#1109
bhandras wants to merge 1 commit into
mainfrom
agent/preserve-oor-idempotency-key

Conversation

@bhandras

@bhandras bhandras commented Aug 6, 2026

Copy link
Copy Markdown
Member

Summary

  • make the first non-empty outgoing dispatch key immutable when a same-session incoming lifecycle omits it or a later write supplies a different key
  • retain the first validated, artifact-bearing outgoing recipient-proof snapshot while terminal outgoing and incoming state continue advancing in the shared current snapshot
  • keep outgoing status advancing independently, so an incoming failure cannot release a successful outgoing key while a genuinely failed outgoing transfer still permits a retry
  • backfill only known artifact-bearing v16 phases and leave terminal or local-update legacy snapshots untrusted so replay fails closed
  • make the v17-to-v16 downgrade release failed outgoing keys before recreating v16's current-status-only unique index

Motivation

Outgoing and incoming OOR lifecycles share one session registry row. When a sender observes its own OOR output or change, the incoming upsert carries no dispatch key and has an incoming snapshot. Replacing the row previously erased both the outgoing identity and the recipient proof. A later lost-response retry could either admit a second transfer or fail closed because the incoming snapshot cannot prove the original recipient.

Terminal outgoing snapshots also intentionally omit Ark artifacts because they are resume no-ops. The durable proof therefore must be the first earlier canonical snapshot whose Ark PSBT decodes to recipient outputs, not merely the latest outgoing snapshot.

This is a prerequisite for the restart-safe credit-redemption fix in lightninglabs/swapdk-server#298.

Causal proof

Before the query change, TestOORSessionRegistryIncomingUpsertPreservesIdempotencyKey failed because the incoming upsert changed durable-dispatch-key to the empty value.

After preserving only the key, the real RPC regression still failed: keyed replay found the original session but returned no recipient outpoint because it tried to decode the incoming snapshot.

The final regressions prove that the real outgoing bridge first persists decodable recipient proof, a terminal update omits proof without overwriting it, a following incoming update preserves the original key and proof, and SendOOR(existing_only=true) returns the exact original outpoint with one total wallet selection. They also cover attempted same-session key replacement, legacy terminal/local-update fail-closed behavior, and an exact downgrade state containing both a released failed row and its successful retry.

Verification

  • focused registry, bridge, migration, downgrade, and RPC regressions on SQLite
  • focused registry/migration/downgrade regressions on PostgreSQL
  • full db, oor, and waved unit packages
  • full PostgreSQL db package
  • focused race tests for DB migration/upsert, outgoing proof, and RPC replay
  • focused trace-log run with no unexpected error logs
  • independent invariant audit with no blockers
  • make lint-changed-local
  • strict Go documentation audit for changed declarations
  • make sqlc-check
  • make tidy-module-check
  • make fmt-changed-check
  • make commitmsg-lint range="origin/main..HEAD"

@bhandras
bhandras force-pushed the agent/preserve-oor-idempotency-key branch from 6b4cdef to 1657f1f Compare August 6, 2026 17:39
@bhandras
bhandras marked this pull request as draft August 6, 2026 17:54
Incoming lifecycle records omit the outgoing dispatch key.

Replacing that key with NULL lets a retry admit a duplicate transfer.

Keep the prior non-NULL key while advancing the shared session row.
@bhandras
bhandras force-pushed the agent/preserve-oor-idempotency-key branch from 1657f1f to e0dbb21 Compare August 6, 2026 18:04
@bhandras
bhandras marked this pull request as ready for review August 6, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant