Cashu Fault Lab

Repository-generated scenario index

Choose where delivery breaks.

These are the exact fault programs checked into the repository. Each run stays deterministic under the demo seed and links back to its reviewable source.

Scenarios
50
Families
7
Index source
scenarios/**/*.json

Fault family

Concurrency

02 programs
5 commandsconcurrency/cross-transport-storm

cross-transport-duplicate-storm

Injects 49 HTTP and 50 Nostr duplicates on a single delivery. Verifies at-most-once settlement and credit across dual transport storm.

pnpm lab run concurrency/cross-transport-storm --seed demo
View source
3 commandsconcurrency/duplicate-storm

http-duplicate-storm

Injects 99 HTTP duplicates on a single delivery. Verifies the receiver creates exactly one settlement plan and one merchant credit.

pnpm lab run concurrency/duplicate-storm --seed demo
View source

Fault family

Conformance

07 programs
3 commandsconformance/conflict-delivery

conflict-delivery

Sends a delivery that settles, then sends a second delivery under the same delivery ID with different proofs. Verifies the receiver rejects the second delivery with DELIVERY_CONFLICT and never starts a second mint swap or credits the merchant twice.

pnpm lab run conformance/conflict-delivery --seed demo
View source
3 commandsconformance/conflict-proof

conflict-proof

Sends a delivery that settles and consumes proof set A, then sends a second delivery with a new delivery ID reusing the same proofs. Verifies the receiver rejects the second delivery with PROOF_CONFLICT and never starts a second mint swap or credits the merchant twice.

pnpm lab run conformance/conflict-proof --seed demo
View source
3 commandsconformance/conflict-single-use

conflict-single-use

Sends a delivery that settles and claims a single-use request, then sends a second delivery with a new delivery ID and new proofs under the same request. Verifies the receiver rejects the second delivery with SINGLE_USE_CONFLICT and never starts a second mint swap or credits the merchant twice.

pnpm lab run conformance/conflict-single-use --seed demo
View source
3 commandsconformance/created-expired

expiry-created-expired

Advances virtual time past the delivery validity window before the first send. Verifies the receiver rejects the delivery as expired, never starts mint redemption, and never credits the merchant.

pnpm lab run conformance/created-expired --seed demo
View source
1 commandsconformance/delivery-v1

delivery-v1-conformance

Validates delivery-v1 codec conformance: parses pinned wire-format vectors and fingerprint preimages from spec/vectors/.

pnpm lab run conformance/delivery-v1 --seed demo
View source
1 commandsconformance/legacy-nut18

legacy-nut18-codec

Validates legacy NUT-18 codec conformance: parses upstream creqA payment requests with NIP-17 nprofile targets.

pnpm lab run conformance/legacy-nut18 --seed demo
View source
1 commandsconformance/nut26-known-mismatch

nut26-nostr-known-mismatch

Documents the known NUT-26/NUT-18 incompatibility: NIP-04 raw-key vs NIP-17 nprofile transport mapping mismatch.

pnpm lab run conformance/nut26-known-mismatch --seed demo
View source

Fault family

Crash Recovery

15 programs
3 commandscrash-recovery/boundaries/receiver_after_credit_before_receipt_persistence

receiver-after-credit-before-receipt-persistence

Terminates after durable merchant credit and finalizes one monotonic receipt.

pnpm lab run crash-recovery/boundaries/receiver_after_credit_before_receipt_persistence --seed demo
View source
3 commandscrash-recovery/boundaries/receiver_after_mint_request_before_response

receiver-after-mint-request-before-response

Terminates after possible mint consumption and recovers without unsafe redispatch.

pnpm lab run crash-recovery/boundaries/receiver_after_mint_request_before_response --seed demo
View source
3 commandscrash-recovery/boundaries/receiver_after_mint_response_before_output_persistence

receiver-after-mint-response-before-output-persistence

Terminates after mint success and restores the exact outputs before settlement.

pnpm lab run crash-recovery/boundaries/receiver_after_mint_response_before_output_persistence --seed demo
View source
3 commandscrash-recovery/boundaries/receiver_after_output_persistence_before_merchant_credit

receiver-after-output-persistence-before-merchant-credit

Terminates after durable output persistence and credits the merchant exactly once.

pnpm lab run crash-recovery/boundaries/receiver_after_output_persistence_before_merchant_credit --seed demo
View source
3 commandscrash-recovery/boundaries/receiver_after_receipt_persistence_before_response_or_outbox

receiver-after-receipt-persistence-before-response-or-outbox

Terminates after durable settled receipt/outbox state and returns the stable receipt after restart.

pnpm lab run crash-recovery/boundaries/receiver_after_receipt_persistence_before_response_or_outbox --seed demo
View source
3 commandscrash-recovery/boundaries/receiver_before_mint_request

receiver-before-mint-request

Terminates the receiver before mint dispatch and resumes from the prepared delivery.

pnpm lab run crash-recovery/boundaries/receiver_before_mint_request --seed demo
View source
3 commandscrash-recovery/boundaries/sender_after_payload_persistence_before_network_send

sender-after-payload-persistence-before-network-send

Terminates after exact payload persistence and verifies restart sends the stored bytes.

pnpm lab run crash-recovery/boundaries/sender_after_payload_persistence_before_network_send --seed demo
View source
3 commandscrash-recovery/boundaries/sender_after_reservation_before_payload_persistence

sender-after-reservation-before-payload-persistence

Terminates after durable proof reservation and verifies the exact reservation is reused.

pnpm lab run crash-recovery/boundaries/sender_after_reservation_before_payload_persistence --seed demo
View source
3 commandscrash-recovery/boundaries/sender_after_send_before_response

sender-after-send-before-response

Terminates after delivery dispatch and verifies retry converges on the same identity.

pnpm lab run crash-recovery/boundaries/sender_after_send_before_response --seed demo
View source
3 commandscrash-recovery/boundaries/sender_before_proof_reservation

sender-before-proof-reservation

Terminates the funded sender before proof reservation and verifies deterministic retry after restart.

pnpm lab run crash-recovery/boundaries/sender_before_proof_reservation --seed demo
View source
4 commandscrash-recovery/external-receiver-restart-after-settlement

external-receiver-restart-after-settlement

An external receiver adapter settles a delivery, restarts, then accepts the same delivery again without creating a second merchant credit.

pnpm lab run crash-recovery/external-receiver-restart-after-settlement --seed demo
View source
6 commandscrash-recovery/mint-response-lost

crash-recovery-mint-response-lost

Mint commits the swap but drops the response. Receiver restarts, recovers via NUT-19 replay or NUT-09 restore, and settles without double credit.

pnpm lab run crash-recovery/mint-response-lost --seed demo
View source
5 commandscrash-recovery/nut19-cache-hit-recovery

nut19-cache-hit-recovery

Mint commits the swap and drops the response. Receiver restart replays the byte-identical NUT-19 cached swap request inside TTL and settles without NUT-09 restore or double credit.

pnpm lab run crash-recovery/nut19-cache-hit-recovery --seed demo
View source
6 commandscrash-recovery/receiver-restart-mid-swap

crash-recovery-receiver-restart-mid-swap

Receiver accepts a delivery and starts redemption, then restarts before the swap completes. After clearing the mint fault, the receiver recovers via NUT-09 restore and settles without double credit.

pnpm lab run crash-recovery/receiver-restart-mid-swap --seed demo
View source
7 commandscrash-recovery/sender-restart-mid-delivery

crash-recovery-sender-restart-mid-delivery

Mint commits the swap but drops the response. Receiver restarts and recovers via NUT-09, then sender restarts and resumes the in-flight delivery, converging on the settled receipt without a second mint swap.

pnpm lab run crash-recovery/sender-restart-mid-delivery --seed demo
View source

Fault family

Retry

04 programs
3 commandsretry/cross-transport-fallback

http-nostr-fallback

Drops the HTTP response so the sender falls back to Nostr transport. Verifies both transports converge on the same settled receipt.

pnpm lab run retry/cross-transport-fallback --seed demo
View source
3 commandsretry/nostr-response-lost

nostr-response-lost

Drops the first Nostr response. Verifies sender retries through NIP-17 gift-wrap delivery and the receiver deduplicates.

pnpm lab run retry/nostr-response-lost --seed demo
View source
3 commandsretry/request-lost

http-request-lost

Drops the first HTTP request before it reaches the receiver. Verifies sender resends the entire delivery payload.

pnpm lab run retry/request-lost --seed demo
View source
3 commandsretry/response-lost

http-response-lost

Drops the first HTTP response. Verifies sender retries with the same delivery ID and payload bytes, converging on a settled receipt.

pnpm lab run retry/response-lost --seed demo
View source

Fault family

Security

04 programs
3 commandssecurity/cors

security-cors

Probes CORS origin enforcement. Verifies trusted origins can access the payment endpoint and attacker origins are blocked.

pnpm lab run security/cors --seed demo
View source
3 commandssecurity/malformed-input

security-malformed-input

Sends malformed payloads (invalid JSON, non-UTF-8, oversized). Verifies all inputs are rejected with stable, deterministic error codes.

pnpm lab run security/malformed-input --seed demo
View source
3 commandssecurity/redirect-leak

security-redirect-leak

Probes that HTTP redirects are disabled. Verifies proof bearer material is never leaked to attacker-controlled redirect targets.

pnpm lab run security/redirect-leak --seed demo
View source
3 commandssecurity/ssrf

security-ssrf

Probes that DNS rebinding to private IPs is blocked. Verifies proof material is never sent to internal network addresses.

pnpm lab run security/ssrf --seed demo
View source

Fault family

Wallet Doctor

09 programs
2 commandswallet-doctor/del-chain-break

Del-chain break across two relays

A spend rolls over change everywhere but the deletion only reaches one relay; the stale spent token stays live elsewhere, so a naive merge double-counts proofs the mint no longer backs.

pnpm lab wallet-doctor run del-chain-break --seed demo
View source
2 commandswallet-doctor/deletion-not-propagated

Standalone deletion reaches one relay

An unspent token is deleted on one relay without a successor while another relay still serves it.

pnpm lab wallet-doctor run deletion-not-propagated --seed demo
View source
2 commandswallet-doctor/ghost-balance

Ghost balance after off-relay spend

The wallet spends proofs at the mint but publishes nothing; relays keep serving the old token, so applications show sats that are already gone.

pnpm lab wallet-doctor run ghost-balance --seed demo
View source
1 commandswallet-doctor/healthy

Healthy replicated wallet

A minted token event reaches every relay and all proofs stay unspent; the doctor must report zero findings.

pnpm lab wallet-doctor run healthy --seed demo
View source
4 commandswallet-doctor/missing-wallet-event

Wallet metadata absent from every relay

Both relays lose the replaceable kind 17375 event while token state remains readable.

pnpm lab wallet-doctor run missing-wallet-event --seed demo
View source
2 commandswallet-doctor/orphaned-proofs

Orphaned proofs after delete without rollover

A deletion reaches every relay but no successor token event exists; the proofs are still unspent at the mint and recoverable, yet no application can see them.

pnpm lab wallet-doctor run orphaned-proofs --seed demo
View source
2 commandswallet-doctor/partial-publish-partition

Partial publish with stale predecessor

A spend publishes the rollover and deletion only to the first relay; other relays still serve the spent predecessor, partitioning the successor and breaking the del chain.

pnpm lab wallet-doctor run partial-publish-partition --seed demo
View source
2 commandswallet-doctor/relay-partition

Relay-side history partition

One relay withholds every kind:7375 token event; applications reading only that relay see an empty wallet while the mint-verified balance is intact.

pnpm lab wallet-doctor run relay-partition --seed demo
View source
2 commandswallet-doctor/wallet-event-fork

Wallet event missing on one relay

One relay withholds the kind:17375 wallet event; applications reading only that relay do not recognize the wallet at all while balances are intact elsewhere.

pnpm lab wallet-doctor run wallet-event-fork --seed demo
View source

Fault family

Wallet Lifecycle

09 programs
4 commandswallet-lifecycle/concurrent-resume

Concurrent resume

Concurrent resume calls race on one ambiguous operation and must produce one economic effect.

pnpm lab run wallet-lifecycle/concurrent-resume --seed demo
View source
4 commandswallet-lifecycle/melt-paid-response-lost

Melt paid response lost

The invoice settles but the melt response is lost; resume must prove one settlement and recover change.

pnpm lab run wallet-lifecycle/melt-paid-response-lost --seed demo
View source
5 commandswallet-lifecycle/melt-pending-restart

Melt pending restart

A pending asynchronous melt survives adapter restart and remains reserved until independently settled.

pnpm lab run wallet-lifecycle/melt-pending-restart --seed demo
View source
4 commandswallet-lifecycle/mint-response-lost

Mint response lost

The mint commits issuance but the first mint response is lost; resume must recover the same output plan.

pnpm lab run wallet-lifecycle/mint-response-lost --seed demo
View source
5 commandswallet-lifecycle/receive-crash-before-save

Receive crash before save

A receive-side swap commits before the wallet saves outputs; restart and resume must converge once.

pnpm lab run wallet-lifecycle/receive-crash-before-save --seed demo
View source
4 commandswallet-lifecycle/restore-duplicate

Restore duplicate

A restore request is duplicated byte-for-byte; recovered outputs must be persisted and credited once.

pnpm lab run wallet-lifecycle/restore-duplicate --seed demo
View source
4 commandswallet-lifecycle/security-quote-redaction

Security quote redaction

Malformed quote responses and failure artifacts must never expose quote credentials or request bodies.

pnpm lab run wallet-lifecycle/security-quote-redaction --seed demo
View source
5 commandswallet-lifecycle/stale-quote

Stale quote

A stale quote poll cannot regress a monotonic quote state or release ambiguous inputs.

pnpm lab run wallet-lifecycle/stale-quote --seed demo
View source
4 commandswallet-lifecycle/swap-response-lost

Swap response lost

The swap commits but its response is lost; recovery must not create a fresh output plan.

pnpm lab run wallet-lifecycle/swap-response-lost --seed demo
View source