Harden XMR signer outbound reliability and scanner state
Summary
This MR ports and completes the XMR outbound reliability hardening on top of current develop.
It focuses on making the signer sidecar safe across FROST retries, Bifrost retries, daemon race windows, restarts, and XMR scanner reconciliation. The main goal is that a signed XMR transaction only becomes durable local spend state after the sidecar can prove the transaction is daemon-visible and the outbound metadata matches the signed transaction.
What changed
FROST / DKG compatibility
- Filter local self entries from DKG/signing maps before passing peer maps to Serai FROST internals.
- Carry the local participant index through signing sessions so
partialandcombinecan safely remove Bifrost-echoed self payloads. - Fix the single-node monovault DKG/signing path that can otherwise fail with participant-count mismatches.
- Change DKG finalize so it stores the final key under the group key but does not auto-register a raw group-key vault. Bifrost remains responsible for registering the THOR pubkey alias through
/vaults/register.
Scanner / inbound observation
- Extract XMR arbitrary-data notes from scanned wallet outputs.
- Persist notes in output records.
- Preserve notes when rescans merge output state.
- Preserve notes through collision-aware credited-output accounting.
- Return notes in scanner transfer responses so memo-bearing XMR deposits are observed correctly.
Outbound proof and spent refs
- Require daemon visibility before non-mocknet
mark-spentmutates tracked inputs. - Verify imported spent refs against transaction key images.
- Verify outbound metadata using
tx_key, destination address, amount, and fee. - Require local wallet-output proof bytes for imported spent refs.
- Reject unknown spent refs atomically before mutating local output state.
- Make repeated spent-ref imports idempotent.
- Restrict
skip_verificationto mocknet.
Retry and reservation safety
- Track outgoing transfer status and timestamps.
- Store selected spent refs on outgoing records.
- Release reserved inputs when combine fails.
- Release unmarked local outgoing records when broadcast fails or when the daemon does not expose the transaction after publish.
- Require post-publish daemon visibility before returning broadcast success.
- Preserve durable marked-spent state once import has succeeded.
- Unreserve inputs held by expired or cleared signing sessions.
Idempotency
- Scope idempotency by route + msg_id + payload hash.
- Replay only exact same requests.
- Reject same-route
msg_idreuse with a different payload. - Avoid stale broadcast replay if the exact transaction is no longer daemon-visible.
API route fix
- Replace Axum
{param}routes with:param. - Restores dynamic endpoints such as:
/v1/monero/balance/:vault_pub_key/v1/monero/outputs/:vault_pub_key/v1/monero/addresses/:vault_pub_key/v1/monero/chain/block/:height/v1/monero/chain/tx/:tx_hash/exists
Why
The previous sidecar state model could leave local XMR outputs reserved or marked in situations where no durable daemon-visible spend existed. That could break signer retries by making the local wallet appear exhausted, or let incomplete/self-consistent metadata become a retry guard before the sidecar had verified the actual transaction.
This MR makes the durability boundary explicit:
- FROST combine may create a signed transaction and local outgoing proof.
- Broadcast must prove daemon visibility.
- Mark-spent must prove transaction inputs and outbound metadata.
- Only then are selected inputs treated as durable spent state.
Tests added
- DKG finalize does not auto-register a raw group-key vault.
- Router construction catches invalid Axum dynamic route syntax.
- Signing peer payload maps filter local participant entries.
- Idempotency hashes are stable and reject conflicting payloads.
- Scanner scan height is vault-scoped.
- Credited outputs preserve stored XMR notes.
- Spent-ref marking rejects unknown refs and key-image conflicts without partial mutation.
- Spent-ref marking is idempotent on replay.
- Unmarked outgoing rollback unreserves inputs.
- Marked-spent outgoing records remain durable.