-
Notifications
You must be signed in to change notification settings - Fork 38.8k
Allow creating blank (empty) wallets (alternative) #15226
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
Conversation
9233a56 to
575dd54
Compare
575dd54 to
c0bfc2d
Compare
|
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. |
|
Concept ACK |
d93a8df to
c0bfc2d
Compare
|
Concept ACK, thanks for saving me some work :-) Are you sure older clients will understand this mandatory flag? Testing this is a good use of #12134, though such test should be in a separate PR to prevent a long wait. |
|
This should probably replace #14938 on the high priority list: https://github.com/bitcoin/bitcoin/projects/8 |
Sjors
left a comment
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.
Other than my questions and remarks c0bfc2d7160e7c861d9a3e678e1dd9b6213a8a86 looks good.
Just tested with 0.17 and 0.16. 0.17 knows what the wallet flags are so it does understand the mandatory flag and refuses to load wallets with the blank flag set. |
|
Would it had made (or still make) sense to raise the wallet version number to prevent ignoring wallet flags? |
It makes sense that if you are going to set a mandatory flag, you also need to increase the minimum version to whatever bitcoin version started checking mandatory flags. |
|
Wallet feature flags were introduced in 0.17.0, and as @achow101 and the source comment points out, "wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown". The following, added in a8da482 and released in v0.17.0, should already prevent 0.16 nodes from opening a >=0.17.0 wallet: FEATURE_PRE_SPLIT_KEYPOOL = 169900,
FEATURE_LATEST = FEATURE_PRE_SPLIT_KEYPOOL;@achow101 I'm surprised you were able to open such a wallet in 0.16. Are you sure you compiled it right? I just tried using the By the way, let's make sure we don't get in the way of #13756 which introduces |
|
Oh, I made a mistake. Just tested it again and yes, 0.16 does not open wallets that have flags set, so there is no need to do another version bump. |
c0bfc2d to
ac4d021
Compare
Thank you, I really like this distinct terminology. |
ac4d021 to
2021dfa
Compare
|
Rebased |
ryanofsky
left a comment
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.
I really like the feature, but would NACK the PR in it's current form just because it so pointlessly confusing to review! The worst part is the renaming of IsHDEnabled to HasHDSeed followed by an addition of a new IsHDEnabled with a different meaning. So all the calls where the previous behavior isn't changing show up in the diff, while all the calls where the behavior is changing don't show up at all! I'd really suggest dropping the IsHDEnabled rename or doing a scripted diff commit, and then adding a new function like IsHDSupported or IsHDSafe for the new version-based check.
4d2b8b4 to
1cdb8d8
Compare
|
I've reworked I've also squashed down the commits as I don't think the original commit structure would pass tests. I changed how |
ryanofsky
left a comment
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.
Thanks for reworking and squashing. I think I understand the PR better now. I do have two questions below.
1cdb8d8 to
8061ea4
Compare
|
Tested ACK 8061ea4611696b22d5d5dcdd73c1e053ffecc09d |
|
Tested on OS X, reviewed and looks good but I don't feel qualified to ACK as I don't understand the intricacies of the wallet well enough. |
|
I'll try to give this another review in the next few days. |
ryanofsky
left a comment
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.
This is pretty good and I think it will work but I think it can be simplified more. Left suggestions below.
src/wallet/rpcwallet.cpp
Outdated
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 commit "[wallet] Support creating a blank wallet" (8061ea4611696b22d5d5dcdd73c1e053ffecc09d)
This is pretty convoluted. It would be more straightforward to avoid all the cancelling conditions and just write if (!CanSupportFeature(FEATURE_HD))
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 commit "[wallet] Support creating a blank wallet" (8061ea4611696b22d5d5dcdd73c1e053ffecc09d)
This will now allow calling sethdseed on a wallet with WALLET_FLAG_DISABLE_PRIVATE_KEYS set. That seems like a mistake because I'm not sure the resulting state would make sense, and at the very least GenerateNewSeed would assert false in this case.
Would suggest adding a check for WALLET_FLAG_DISABLE_PRIVATE_KEYS here.
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.
There's already a check for that flag above.
src/wallet/rpcwallet.cpp
Outdated
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 commit "[wallet] Support creating a blank wallet" (8061ea4611696b22d5d5dcdd73c1e053ffecc09d)
This will now allow calling sethdseed on a wallet with WALLET_FLAG_DISABLE_PRIVATE_KEYS set. That seems like a mistake because I'm not sure the resulting state would make sense, and at the very least GenerateNewSeed would assert false in this case.
Would suggest adding a check for WALLET_FLAG_DISABLE_PRIVATE_KEYS here.
8061ea4 to
49044a4
Compare
|
I have taken @ryanofsky's suggestions and reworked this a bit more. This should also help with #14075. I got rid of |
49044a4 to
8b5533e
Compare
ryanofsky
left a comment
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.
utACK 8b5533ee281ba114b8bb5c195f4a9b715b02a644. Thanks for being so responsive. I think this is in good shape, though I did leave some more suggestions.
src/wallet/rpcwallet.cpp
Outdated
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 commit "[wallet] Support creating a blank wallet" (8b5533ee281ba114b8bb5c195f4a9b715b02a644)
Curious what other people think but I think it would be great to remove WALLET_FLAG_DISABLE_PRIVATE_KEYS check above in light of this check.
One thing that makes flag code hard to understand is that you can grep and have to dig through 20 usages of a flag where checking it is redundant or has little effect, which makes it harder to identify the places where the flag is actually playing an important role
I think if WALLET_FLAG_DISABLE_PRIVATE_KEYS check above should be kept it should at least have a comment saying it's belt and suspenders or something like that.
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.
I've added a comment
src/wallet/rpcwallet.cpp
Outdated
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 commit "[wallet] Support creating a blank wallet" (8b5533ee281ba114b8bb5c195f4a9b715b02a644)
There's another WALLET_FLAG_DISABLE_PRIVATE_KEYS check above that could be removed or noted belt and suspenders.
src/wallet/wallet.cpp
Outdated
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 commit "[wallet] Support creating a blank wallet" (8b5533ee281ba114b8bb5c195f4a9b715b02a644)
Here and other three places where wallet code is calling CanGetAddresses(), I think it should be calling CanGenerateKeys() instead. CanGetAddresses() is definitely useful for the GUI, because the GUI has to continuously keep its display state up to date with state of the keypool, and this is inherently racy and approximate. But actual wallet code shouldn't be doing racy, redundant checks like this. There's no point to locking cs_wallet, checking the number of available keys in the keypool, releasing the lock, reacquiring the lock and then doing the same check again below in ReserveKey.
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.
The reason I have the CanGetAddresses check here is for future work where you can get a key from the keypool without the ability to generate addresses.
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.
Agree with the usefulness of CanGetAddresses for followup stuff. Longer term I also think it's a useful distinction in a descriptor based wallet, which may support a lot more (semi) watch-only (solvable, but not IsMine) things like being part of a multisig group.
Regarding the "racy" stuff, maybe it helps to add AssertLockHeld to CWallet CanGetAddresses and CanGenerateKeys? That way places that (indirectly) call both can get a lock once.
8b5533e to
707eaba
Compare
Sjors
left a comment
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.
utACK 707eaba, but please double check my "create a fresh seed" comment before merging.
I like the new CanGenerateKeys and CanGetAddresses approach, and the fact that the blank flag now really indicates the wallet is empty, rather than the more complicated condition we had before.
I checked again that v0.17.1 refuses to open a blank wallet, and that after sethdseed it does.
src/wallet/wallet.cpp
Outdated
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.
Agree with the usefulness of CanGetAddresses for followup stuff. Longer term I also think it's a useful distinction in a descriptor based wallet, which may support a lot more (semi) watch-only (solvable, but not IsMine) things like being part of a multisig group.
Regarding the "racy" stuff, maybe it helps to add AssertLockHeld to CWallet CanGetAddresses and CanGenerateKeys? That way places that (indirectly) call both can get a lock once.
src/wallet/wallet.h
Outdated
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.
IsHDEnabled() should be renamed to HasHDSeed() because that's actually what it checks (as opposed to CanSupportFeature(FEATURE_HD)). Can perhaps wait until a followup, since it's clear enough from the comments.
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.
I would prefer to leave it as-is for now. That can be changed in a followup.
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.
That's fine, but I'll keep stalking you :-)
src/wallet/wallet.cpp
Outdated
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.
I don't see how "create a fresh seed" happens here, because if there's no seed IsHDEnabled() returns false.
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.
Outdated comment. I've changed it back.
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.
Might be useful to add "If no HD seed is set, e.g. because it is a blank wallet, do not add one.", can be done in the same followup as renaming IsHDEnabled() (though that rename would make the comment unnecessary :-).
A blank wallet is a wallet that has no keys, script or watch only things. A new wallet flag indicating that it is blank will be set when the wallet is blank. Once it is no longer blank (a seed has been generated, keys or scripts imported, etc), the flag will be unset.
707eaba to
7687f78
Compare
|
re-utACK 7687f78 |
7687f78 [wallet] Support creating a blank wallet (Andrew Chow) Pull request description: Alternative (kind of) to #14938 This PR adds a `blank` parameter to the `createwallet` RPC to create a wallet that has no private keys initially. `sethdseed` can then be used to make a clean wallet with a custom seed. `encryptwallet` can also be used to make a wallet that is born encrypted. Instead of changing the version number as done in #14938, a wallet flag is used to indicate that the wallet should be blank. This flag is set at creation, and then unset when the wallet is no longer blank. A wallet becomes non-blank when a HD seed is set or anything is imported. The main change to create a blank wallet is primarily taken from #14938. Also with this, the term "blank wallet" is used instead of "empty wallet" to avoid confusion with wallets that have balance which would also be referred to as "empty". This is built on top of #15225 in order to fix GUI issues. Tree-SHA512: 824d685e11ac2259a26b5ece99c67a7bda94a570cd921472c464243ee356b7734595ad35cc439b34357135df041ed9cba951e6edac194935c3a55a1dc4fcbdea
Updated the address format in the new rpc_deriveaddresses.py regtest to Xaya's address versions. After bitcoin/bitcoin#15226, we have to explicitly set HDs seeds in some of the wallet unit tests, specifically for Xaya. That is the case because in Xaya, the initial / default wallet version already supports HD, and then the wallet refuses the generate keys without an HD seed set.
662d117 Add option to create an encrypted wallet (Andrew Chow) Pull request description: This PR adds a new `passphrase` argument to `createwallet` which will create a wallet that is encrypted with that passphrase. This is built on #15226 because it needs to first create an empty wallet, then encrypt the empty wallet and generate new keys that have only been stored in an encrypted state. ACKs for commit 662d11: laanwj: utACK 662d117 jnewbery: Looks great. utACK 662d117 Tree-SHA512: a53fc9a0f341eaec1614eb69abcf2d48eb4394bc89041ab69bfc05a63436ed37c65ad586c07fd37dc258ac7c7d5e4f7f93b4191407f5824bbf063b4c50894c4a
Alternative (kind of) to #14938
This PR adds a
blankparameter to thecreatewalletRPC to create a wallet that has no private keys initially.sethdseedcan then be used to make a clean wallet with a custom seed.encryptwalletcan also be used to make a wallet that is born encrypted.Instead of changing the version number as done in #14938, a wallet flag is used to indicate that the wallet should be blank. This flag is set at creation, and then unset when the wallet is no longer blank. A wallet becomes non-blank when a HD seed is set or anything is imported. The main change to create a blank wallet is primarily taken from #14938.
Also with this, the term "blank wallet" is used instead of "empty wallet" to avoid confusion with wallets that have balance which would also be referred to as "empty".
This is built on top of #15225 in order to fix GUI issues.