-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Support creating an empty wallet #14938
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
dddff68 to
2c60129
Compare
|
Some context:
|
6d603dd to
9822ff6
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. |
promag
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.
Concept ACK.
|
Concept ACK. |
|
Concept ACK @jonasschnelli is this in line with your idea of supporting hardware wallets? |
|
It's definitely in line with my idea of adding hardware wallets :-) See also #14145. |
|
I'm not opposed against this,... but this seems not to be in line with hardware wallet support (yet). Because But once this is turned into "watch-only-HD"/ public-key-derivation, then I guess this is useful. The question then would be, if we don't want to directly add an xpub argument to the |
|
Calling I would expect either that we can't encrypt an empty wallet (bummer, because then we can't have a wallet encrypted from the very beginning), or that it would encrypt and have a newly generated seed (which is what I think you were trying to do). Edit: achow101@d3b5d7b fixes this issue. |
9822ff6 to
a3755ca
Compare
|
@achow101 thanks, I see you included that commit in #15006 Addressed @promag's, @practicalswift 's and @achow101's comments. Rebased because Travis was going nuts. |
efbfc9e to
0cc35e0
Compare
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.
@jnewbery this test fails with --usecli if I use a boolean True rather than a string 'true'. Is that by design? Two of the Travis machines don't seem to like this syntax either.
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.
Looks like this is a variation of the issue fixed here: a3fa4d6 but for named arguments. Fix it with something like:
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 031a8824b..8225992c2 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -434,7 +434,7 @@ class TestNodeCLI():
def send_cli(self, command=None, *args, **kwargs):
"""Run bitcoin-cli command. Deserializes returned string as python object."""
pos_args = [str(arg).lower() if type(arg) is bool else str(arg) for arg in args]
- named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()]
+ named_args = [str(key) + "=" + (str(value).lower() if type(value) is bool else str(value)) for (key, value) in kwargs.items()]
assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call"
p_args = [self.binary, "-datadir=" + self.datadir] + self.options
if named_args:
|
Concept ACK. Had a very quick skim and changes look sensible. Will review once Travis is happy. |
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.
Why not stay with FEATURE_LATEST here? It is currently equal to FEATURE_PRE_SPLIT_KEYPOOL, and presumably we will want to stick with current feature support when we make the next breaking change.
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.
@Empact in an earlier version I added a new feature version for this, but then I realized it wasn't necessary. Forgot to remove this bit. Fixed. On second thought I'm worried that previous versions would treat this as a non-HD wallet and upgrade it, which may not be what the user intended. So it seems safer to add a new version number.
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 think instead of using a version number you should use a wallet flag that is required. The flag can be unset once the wallet is no longer empty. This would remove the need for a new version number while still preventing older software from opening the wallet.
0cc35e0 to
65f7276
Compare
65f7276 to
1bc6a02
Compare
1bc6a02 to
8ce17c0
Compare
|
Travis is happy now. Added I added a new wallet version |
|
I don't think it is necessary to set different version numbers depending on whether the wallet can be empty. This is effectively reintroducing the optional version stuff that we had done for HD wallets and HD chain split, and reconciling those was a major pain. I don't see why it is necessary to do that again. |
|
What do you mean by "optional version stuff"? The alternative seems to be to disallow <= v0.17 nodes from opening a v0.18 wallet, even though only a minitory of users need the empty wallet feature. |
The original HD wallet stuff was optional and the option was determined by the wallet version number. Non-HD wallets had a lower version number than HD wallets. So an optional feature was determined by the version number. But later when a change to the wallet affected both non-HD and HD wallets and required a version number bump, this optional feature thing switched via the version number had to go away, and making it go away was a pain. In general, I don't think that we shouldn't have optional features be indicated by the version number. Since we have wallet flags now, I think that instead optional features should be indicated through the flags, and if a flag is set that we don't know about, we should throw an error. If you set a flag in the upper 32 bits, an error will be thrown if the flag is set but the flag is unknown, so I think you should use a flag there instead of a version number. The flag for disable private keys does the same thing.
That certainly wouldn't be ideal, but I don't think that is really that big of a concern. I think it is far more likely for someone who upgraded to 0.18 from 0.17 to then downgrade to 0.17 than for someone who starts with 0.18 (and thus makes a new wallet) to then downgrade to 0.17. |
| return false; | ||
|
|
||
| // If wallet supports HD but no seed is present, do not top up keypool | ||
| if(IsHDEnabled() && !HasHDSeed()) return true; |
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.
maybe roll this logic (which is repeated below) into a function IsEmpty()?
Edit: hmm I guess empty is a bad name here as it could also imply that the wallet has no transactions, or no funds…
|
Should this option be exposed in the GUI (after #13100)? |
|
@promag I think it should |
|
@jonasschnelli an empty wallet does not have an HD seed, so there is no way to refill the keypool. Calling I'm surprised the GUI doesn't handle this correctly, since the keypool could already run out before this change. Normally it just greys out the new address button. I'll try to reproduce. |
|
@achow101 wrote inline:
I'm happy with either option. Mandatory flags explicitly say what a wallet can't do, which is arguably better than inferring capabilities from version numbers. Any other takes? |
Right—apparently the GUI doesn't do correct error handling here, it should handle the case where it's impossible to generate an address. |
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 8ce17c0, but I agree with @achow101 in preferring a new feature flag to a new version number here.
In this case, since it is unlikely there'd ever be a new version of the wallet which dropped support for unset HD seeds, there's little practical difference between using a new flag or a new version. I prefer flags anyway just for sanity when reading code, because flags make it possible to reason about one feature at a time without having to think about the history of the project. The counterargument in favor of preferring versions to flags is that using flags leads to a combinatorial explosion of configurations that can't all be tested and make the project less stable. I think this argument is spurious because you can always disallow combinations of flags you don't want to test, without the need to confuse future maintainers of the code forever with version number comparisons.
|
|
||
| // Top up the keypool | ||
| if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !walletInstance->TopUpKeyPool()) { | ||
| if (!create_empty && !walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !walletInstance->TopUpKeyPool()) { |
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 do you need to check create_empty here if TopUpKeyPool already returns true when there's no seed? I think you should add a code comment here if checking create_empty is necessary for some reason, and probably drop it otherwise to simplify this code and be consistent with other TopUpKeyPool calls.
This error is because the grey out condition is that private keys are disable. |
|
Closing in favour of #15226. |
…ate changing 2bc4c3e Notify the GUI that the keypool has changed to set the receive button (Andrew Chow) 14bcdbe Check for more than private keys disabled to show receive button (Andrew Chow) Pull request description: Currently the Receive button in the GUI is displayed enabled or disabled by the initial state of the wallet when the wallet is first loaded. The button is only enabled or disabled depending on whether the disable private keys flag is set when the wallet is loaded. However, future changes to the wallet means that this initial state and check may no longer be accurate. #14938 introduces empty wallets which do not have private keys. An empty wallet that is loaded should have the Receive button disabled, and then it should become enabled once `sethdseed` is used so that a keypool can be generated and new keys generated. Likewise, with #14075, a wallet can be loaded with no keypool initially, so the button should be disabled. Later, public keys can be imported into the keypool, at which time the button should become enabled. When the keypool runs out again (no new keys are generated as the keypool only consists of imports), the button should become disabled. This PR makes it so that the button becomes enabled and disabled as the keypool state changes. The check for whether to enable or disable the receive button has changed to checking whether it is possible to get new keys. It now checks for whether the wallet has an HD seed and, if not, whether the private keys are disabled. When an action happens which would make it possible for a new address to be retrieved or make it possible for a no more addresses to be retrieved, a signal is emitted which has the GUI recheck the conditions for the Receive button. These actions are setting a new HD seed, topping up the keypool, retrieving a key from the keypool, and returning a key to the keypool. Tree-SHA512: eff15a5337f4c64ecd7169414fb47053c04f6a0f0130341b6dd9799ac4d79f451e25284701c668971fca33f0909d5352a474a2c12349375bedfdb59b63077d50
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
…pool state changing 2bc4c3e Notify the GUI that the keypool has changed to set the receive button (Andrew Chow) 14bcdbe Check for more than private keys disabled to show receive button (Andrew Chow) Pull request description: Currently the Receive button in the GUI is displayed enabled or disabled by the initial state of the wallet when the wallet is first loaded. The button is only enabled or disabled depending on whether the disable private keys flag is set when the wallet is loaded. However, future changes to the wallet means that this initial state and check may no longer be accurate. bitcoin#14938 introduces empty wallets which do not have private keys. An empty wallet that is loaded should have the Receive button disabled, and then it should become enabled once `sethdseed` is used so that a keypool can be generated and new keys generated. Likewise, with bitcoin#14075, a wallet can be loaded with no keypool initially, so the button should be disabled. Later, public keys can be imported into the keypool, at which time the button should become enabled. When the keypool runs out again (no new keys are generated as the keypool only consists of imports), the button should become disabled. This PR makes it so that the button becomes enabled and disabled as the keypool state changes. The check for whether to enable or disable the receive button has changed to checking whether it is possible to get new keys. It now checks for whether the wallet has an HD seed and, if not, whether the private keys are disabled. When an action happens which would make it possible for a new address to be retrieved or make it possible for a no more addresses to be retrieved, a signal is emitted which has the GUI recheck the conditions for the Receive button. These actions are setting a new HD seed, topping up the keypool, retrieving a key from the keypool, and returning a key to the keypool. Tree-SHA512: eff15a5337f4c64ecd7169414fb47053c04f6a0f0130341b6dd9799ac4d79f451e25284701c668971fca33f0909d5352a474a2c12349375bedfdb59b63077d50
…pool state changing 2bc4c3e Notify the GUI that the keypool has changed to set the receive button (Andrew Chow) 14bcdbe Check for more than private keys disabled to show receive button (Andrew Chow) Pull request description: Currently the Receive button in the GUI is displayed enabled or disabled by the initial state of the wallet when the wallet is first loaded. The button is only enabled or disabled depending on whether the disable private keys flag is set when the wallet is loaded. However, future changes to the wallet means that this initial state and check may no longer be accurate. bitcoin#14938 introduces empty wallets which do not have private keys. An empty wallet that is loaded should have the Receive button disabled, and then it should become enabled once `sethdseed` is used so that a keypool can be generated and new keys generated. Likewise, with bitcoin#14075, a wallet can be loaded with no keypool initially, so the button should be disabled. Later, public keys can be imported into the keypool, at which time the button should become enabled. When the keypool runs out again (no new keys are generated as the keypool only consists of imports), the button should become disabled. This PR makes it so that the button becomes enabled and disabled as the keypool state changes. The check for whether to enable or disable the receive button has changed to checking whether it is possible to get new keys. It now checks for whether the wallet has an HD seed and, if not, whether the private keys are disabled. When an action happens which would make it possible for a new address to be retrieved or make it possible for a no more addresses to be retrieved, a signal is emitted which has the GUI recheck the conditions for the Receive button. These actions are setting a new HD seed, topping up the keypool, retrieving a key from the keypool, and returning a key to the keypool. Tree-SHA512: eff15a5337f4c64ecd7169414fb47053c04f6a0f0130341b6dd9799ac4d79f451e25284701c668971fca33f0909d5352a474a2c12349375bedfdb59b63077d50

Add as new argument (
empty) tocreatewalletto create an empty wallet.This can be followed by
sethdseedto create a clean wallet with a custom seed.Followup PRs can make this significantly more useful, e.g.
createwalletTopUpKeyPool()should look for imported keysTopUpKeyPool()should look for public keys (ifWALLET_FLAG_DISABLE_PRIVATE_KEYSis set)