fix: recover witness UTXOs orphaned by a lost consignment#90
fix: recover witness UTXOs orphaned by a lost consignment#90berserker-systems wants to merge 1 commit into
Conversation
A witness invoice can be paid on-chain without its consignment ever being delivered: the proxy can drop a successfully posted consignment (e.g. it restarts and loses its file store), and the sender may then pay the same invoice again with a new TX whose consignment does arrive. This only happens in donation mode, where the sender broadcasts right after posting the consignment; otherwise it waits for the recipient's ACK (which requires the recipient to already hold the consignment) before broadcasting, so a lost consignment cannot leave a confirmed orphan. The first payment's UTXO is quarantined with pending_witness set, but no transfer ever references its TXID, so the flag is never cleared: the UTXO stays unspendable forever and its allocation, received as part of the second consignment's history, lives only in the RGB runtime and never makes it into the DB (understated balance, sends failing with InsufficientAllocationSlots). On refresh, look for pending witness TXOs with no transfer referencing their TXID. When the runtime already holds allocations for one there is nothing left to wait for: save them to the DB as a settled transfer and clear the flag, so both the sats and the assets become usable again. TXOs the runtime knows nothing about are left as-is, since spending them would burn whatever a still-pending consignment may deliver.
f131ccf to
625fa39
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #90 +/- ##
=======================================
Coverage 95.74% 95.75%
=======================================
Files 23 23
Lines 12835 12924 +89
=======================================
+ Hits 12289 12375 +86
- Misses 546 549 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Thank you for this PR and for the clear write-up of the orphan witness UTXO scenario. The problem is real and the test covers the failure path well. We're about to release a large set of changes, including a refactor of how the proxy integration works. We'd prefer not to merge this now, since the surrounding code is likely to change significantly. Could you please rebase this PR once those changes are public? We can then reassess whether this reconciliation logic still works. On that point: the transport proxy is chosen by the receiver, and in practice it should ideally be infrastructure the receiver controls. Relying on third-party proxies is possible, but should be done carefully: users should understand and trust each proxy's data retention and availability guarantees. With a receiver-owned proxy, the failure mode this PR addresses (a consignment posted successfully but later unavailable) becomes much less likely, and we may find that explicit orphan reconciliation is unnecessary altogether. That said, donation mode remains inherently risky regardless of proxy setup. It broadcasts before the recipient has accepted the consignment, which creates several ways things can go wrong, for example the recipient may consider the consignment invalid and refuse it. Wallets using donation mode should treat it as an explicit, operator-controlled option, not a default path, and be aware of these risks. Thanks again for the contribution. We'll revisit this once our upcoming changes are out. |
|
@zoedberg Thank you. Please ping or e-mail me, when we can continue here. |
A witness invoice can be paid on-chain without its consignment ever being delivered: the proxy can drop a successfully posted consignment (e.g. it restarts and loses its file store), and the sender may then pay the same invoice again with a new TX whose consignment does arrive. This only happens in donation mode, where the sender broadcasts right after posting the consignment; otherwise it waits for the recipient's ACK (which requires the recipient to already hold the consignment) before broadcasting, so a lost consignment cannot leave a confirmed orphan. The first payment's UTXO is quarantined with pending_witness set, but no transfer ever references its TXID, so the flag is never cleared: the UTXO stays unspendable forever and its allocation, received as part of the second consignment's history, lives only in the RGB runtime and never makes it into the DB (understated balance, sends failing with InsufficientAllocationSlots).
On refresh, look for pending witness TXOs with no transfer referencing their TXID. When the runtime already holds allocations for one there is nothing left to wait for: save them to the DB as a settled transfer and clear the flag, so both the sats and the assets become usable again. TXOs the runtime knows nothing about are left as-is, since spending them would burn whatever a still-pending consignment may deliver.