-
Notifications
You must be signed in to change notification settings - Fork 35.6k
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
Allow UTXO locks to be written to wallet DB #23065
Allow UTXO locks to be written to wallet DB #23065
Conversation
Concept ACK Thanks a lot for improving privacy and working on this issue. Will test it in few minutes. |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
Tested on Pop!_OS and everything works as expected. Steps that I followed for testing: Check default behavior ✅
Use the new argument to save locked UTXO in database ✅
Errors ✅
ℹ️ It also works for descriptor wallets
@meshcollider Thanks for adding this option :) It will improve privacy and few projects were also dependent on this feature. Example: https://github.com/p2pderivatives/p2pderivatives-client#known-limitations |
Concept ACK |
Thanks, addressed both review suggestions. Happy to make GUI changes persistent too, it would be a very simple change. Can discuss if it is a useful change. |
I think it is. People who use manual coin control will likely manually selected specfic UTXOs for single tx and lock unspent for longer term. And longer term should survive bitcoin-qt restarts. At least that looks to me more intuitive. Also, from privacy perspective, it is better to have some unwanted UTXO locked longer than spend it accidentally. |
Sure, added persistent locking to the GUI now then 👍 |
tACK 687d65f Changes since last review:
|
Not sure if this error in CI is related to PR: https://github.com/bitcoin/bitcoin/pull/23065/checks?check_run_id=3682608670 |
Looks unrelated, it looks like some random windows socket issue:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reACK 2d3ed88
Changes since last review:
Argument name changed which can be used to save the state of UTXO lock in db as suggested in #23065 (comment)
-store_lock
+persistent
I think this needs also release note about existing behaviour change in the GUI. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK.
I have some questions though:
- lock(utxo, persistent=false) but utxo already has persisted lock - should delete from db?
- unlock(utxo, persistent=false) but utxo already has persisted lock - should delete from db?
- maybe unlock should be sensible to the existing lock (persisted or not)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In CWallet::AddToSpends
we should remove persisted lock?
I don't think we should allow re-locking in any case, better to require explicitly unlocking then locking again.
I was thinking a lot about this while writing the PR. It does make sense to me that unlock would simply remove any locks, persistent or not. But I am not sure if there are some use cases that would benefit from the functionality - persistently lock a UTXO and then temporarily unlock it for a while for some reason? I'm happy to change this if people agree. Good points about AddToSpends and the release notes, will fix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just always persist? What are the cons of that? If someone wants no locks then just call lockunspent true
after load.
Not sure about this. It's a much larger behavior change (downstream software probably relies on starting with a clean slate after restart), and if this behavior really turns out to be more popular it could always be done later. |
Not only restart, even How about a startup flag like If we keep this approach then it needs a way to select I just think a (good) behavior change looks saner to reason about. |
Please don't add another startup option that subtly changes behavior over all wallets 😄 |
@meshcollider I think you should mention that only manual locks can be persisted. Funding calls result in memory-only locks. |
The GUI change needs a release note. |
I'll leave any potential behaviour changes with |
@@ -2260,22 +2260,36 @@ bool CWallet::DisplayAddress(const CTxDestination& dest) | |||
return signer_spk_man->DisplayAddress(scriptPubKey, signer); | |||
} | |||
|
|||
void CWallet::LockCoin(const COutPoint& output) | |||
bool CWallet::LockCoin(const COutPoint& output, WalletBatch* batch) | |||
{ | |||
AssertLockHeld(cs_wallet); | |||
setLockedCoins.insert(output); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lock(utxo, persistent=false) but utxo already has persisted lock - should delete from db?
I don't think we should allow re-locking in any case, better to require explicitly unlocking then locking again.
If you want to implement this breaking change then use the return value of insert()
to know if the output was already locked and return false.
Otherwise, the lock can be persisted but not in memory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise, the lock can be persisted but not in memory.
Sorry, I'm not sure how this could happen. Upon thinking further, I think its fine to upgrade a memory-only lock to a persistent lock (this is useful if fundrawtransaction locked the spends and we want to persistently lock them afterward). But how could we end up with a persistent lock not in memory?
EDIT: I've updated the PR to allow persistently locking even if we already have a lock, to allow upgrading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But how could we end up with a persistent lock not in memory?
Right, doesn't happen now that unlock clears from memory and db.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But does it make sense to allow memory-only lock if it is already persisted?
EDIT: looks like this is not possible since lockunspent RPC checks if unspent is already locked.
gh pr checkout 23065 |
ACK d96b000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK d96b000
Many changes since last review: https://github.com/bitcoin/bitcoin/compare/2d3ed88..d96b000, agree that changes about GUI should be mentioned in release notes and few things looked confusing in above discussion so tested again.
2.5 and 3.5 doesn't look correct IMO. Also agree with @promag that very few people will be affected if this is made persistent by default in CLI and GUI. Infact people might start using this after this change. |
No? There's also a test for that case. Perhaps you are looking at a previous revision. |
Thanks @prayank23 for your detailed testing!
Yes, I decided it isn't worth the overhead of checking if the persistent lock exists in the database, if someone wants to lock the same output twice persistently then I don't see why that should error. It will, however, error if you try and lock un-persistently if the lock already exists -- this is to avoid confusion about downgrading a persistent lock to non-persistent (not allowed).
As @achow101 mentioned, this doesn't seem to be the case. I manually tested 3.5 and cannot replicate the issue -- the lock is definitely cleared persistently and does not remain locked for me. Could you check you built the latest version? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested ACK d96b000 on Ubuntu 20.04
2.5 and 3.5 doesn't look correct IMO.
I also cannot replicate the issues. The steps mentioned in 2.5 and 3.5 worked as expected in my tests.
Steps that I did for 2.5:
PR23065.mp4 |
Oh, apologies @prayank23 , I misread your comment. That behaviour is intended:
We discussed this briefly on IRC at the wallet meeting and decided this approach made the most sense. (By the way, if you start bitcoind with the -daemon flag you don't need to use two terminal windows :) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK d96b000
nit: I will be using persistence parameter set to true every time or GUI so 2.5 and 3.5 isn't an issue for me personally. Can be confusing for some users.
@prayank23 Thanks! Happy to discuss changing the default after this is merged as a follow-up. |
Addresses and closes #22368
As per that issue (and its predecessor #14907), there seems to be some interest in allowing unspent outputs to be locked persistently. This PR does so by adding a flag to lockunspent to store the change in the wallet database. Defaults to false, so there is no change in default behaviour.
Edit: GUI commit changes default behaviour. UTXOs locked/unlocked via the GUI are now persistent.