docs/docs-as-code.md defines the workflow; docs/adr holds 31 ADRs (retroactive, reconstructed from code and changelog) with a template and index. docs/check-docs.sh validates ADR structure, index, cited code paths, relative links and CLAUDE.md/AGENTS.md sync.
26 lines
1.3 KiB
Markdown
26 lines
1.3 KiB
Markdown
# 0008. Progressive verification: show early, spend only after proof
|
|
|
|
- **Status:** Accepted
|
|
- **Area:** SPV
|
|
- **Recorded:** 2026-11-03 (retroactive: reconstructed from code, comments and changelog)
|
|
|
|
## Context
|
|
|
|
On wallets with thousands of historical transactions, blocking the whole sync on every Merkle proof made the app unusable, especially on mobile hardware.
|
|
|
|
## Decision
|
|
|
|
`WalletSynchronizer` raises `PartialResult` as soon as transaction downloads finish, then keeps verifying proofs in the background and refreshes the result periodically. Each cached transaction and UTXO carries a `Verified` flag. The UI marks unverified entries ("verifying…") and shows `PendingVerificationSats` separately. The invariant: `UtxoSpendability.IsSpendable` requires `Verified`, so unverified coins can be displayed but never spent. `SyncOnceAsync` still completes only when verification is finished, and the disk cache stores only the fully verified end state.
|
|
|
|
## Consequences
|
|
|
|
- Fast time-to-usable-balance.
|
|
- A forged balance can be displayed briefly but never spent before the proof failure aborts the sync.
|
|
- Balances have overlapping subsets (immature vs. pending verification); consumers must use `SpendableSats`, never subtract the subsets.
|
|
|
|
## References
|
|
|
|
- `src/Core/Spv/WalletSynchronizer.cs`
|
|
- `src/Core/Wallet/UtxoSpendability.cs`
|
|
- `SECURITY.md`
|