-
Notifications
You must be signed in to change notification settings - Fork 267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Abandon transactions whose ancestors have been double spent #2818
Conversation
When a transaction is directly double-spent, bitcoind is able to automatically detect it and free up wallet inputs that are used in double-spent transactions. However, when a transaction becomes invalid because one of its ancestors is double-spent, bitcoind is not able to detect it and will keep wallet inputs locked forever. The only cases where this can happen are: - splice transactions when a commitment transaction that is not based on the latest splice is confirmed - anchor transactions in the above case, or when a different version of the commitment confirms (e.g. remote commit while we're trying to CPFP ou local commit) When we detect that this happened, we abandon the corresponding transactions, which ensures that we don't end up with unusable liquidity in our wallet. We also remove cases where we eagerly abandoned transactions, which could lead us to double-spend ourselves inadvertently because the abandoned transaction could still confirm while we reused its inputs in another transaction (which is a real issue when using 0-conf).
eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala
Outdated
Show resolved
Hide resolved
eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisher.scala
Show resolved
Hide resolved
Codecov ReportAttention:
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #2818 +/- ##
==========================================
+ Coverage 85.86% 85.89% +0.02%
==========================================
Files 216 217 +1
Lines 18228 18296 +68
Branches 772 793 +21
==========================================
+ Hits 15652 15715 +63
- Misses 2576 2581 +5
|
eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala
Outdated
Show resolved
Hide resolved
Someone brought this up to me today, and I'm thinking that this is a problem that should be solved in Bitcoin Core as well so that workarounds with Edit: Is the issue that the parent transaction that ends up being conflicted does not belong to the wallet? |
It would be awesome if the Bitcoin Core wallet automatically handled that for us, but it looks hard, because in those cases the ancestor transaction that ends up being double-spent indeed doesn't belong to the wallet. Bitcoin Core has no good reason to track that transaction, so it just looks like the child transaction is orphaned, but it cannot know whether it's permanent or temporary (if the ancestors are later reintroduced in the mempool because they were simply evicted). On the lightning side, we do have more information because we need to track those ancestors, so it feels ok to handle those cases ourselves. To do it on the Bitcoin Core side, I believe you'd have to always track all the ancestors of any wallet transaction, even ancestors that are external to the wallet, and properly detect when they're double-spent: do you think that should be Bitcoin Core's responsibility? |
Yes, with a parent unrelated to the wallet, this may be difficult for Bitcoin Core to handle. I've opened bitcoin/bitcoin#29435 to discuss possible solutions in Core. |
All ancestors or just the unconfirmed ancestors? |
When a transaction is directly double-spent, bitcoind is able to automatically detect it and free up wallet inputs that are used in double-spent transactions. However, when a transaction becomes invalid because one of its ancestors is double-spent, bitcoind is not able to detect it and will keep wallet inputs locked forever.
The only cases where this can happen are:
When we detect that this happened, we abandon the corresponding transactions, which ensures that we don't end up with unusable liquidity in our wallet.
We also remove cases where we eagerly abandoned transactions, which could lead us to double-spend ourselves inadvertently because the abandoned transaction could still confirm while we reused its inputs in another transaction (which is a real issue when using 0-conf).