-
Notifications
You must be signed in to change notification settings - Fork 37.7k
wallet: Derive inactive HD chains in additional places #23304
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
wallet: Derive inactive HD chains in additional places #23304
Conversation
a5d8957
to
e9f203f
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. |
e9f203f
to
ee93c29
Compare
Ready for review, supersedes #23277 |
Concept ACK, thanks for adding a test! |
Resolves segfault on legacy wallet Log warning when meta.key_origin.path is below expected size
When topping up an inactive HD chain, either key_origin will be available and we can use the path given there, or we need to figure out the path from the string hdKeypath.
When build CHDChains out of CKeyMetadata, the chain counters are actually 1 based, not 0 based, so 1 must be added to each index.
Rebased for hidden merge conflict. |
ee93c29
to
38c949a
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.
some formatting suggestions (can also just run clang-diff-format.py)
38c949a
to
f835693
Compare
Refactors TopUp so that it also tops up inactive chains. The bulk of TopUp is moved to TopUpChain. CHDChain also has 2 new in memory variables to track its highest used indexes. This is used only for inactive hd chains so that they can be topped up later in the same session (e.g. if the wallet is encrypted and not unlocked at the time of MarkUnusedAddresses).
f835693
to
f3b02bd
Compare
} else { | ||
nTargetSize = std::max(gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE), int64_t{0}); | ||
} | ||
int64_t target = std::max((int64_t) nTargetSize, int64_t{1}); |
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.
avoid c-style casts
int64_t target = std::max((int64_t) nTargetSize, int64_t{1}); | |
int64_t target = std::max(int64_t(nTargetSize), int64_t{1}); |
missingExternal = std::max(target - (int64_t)setExternalKeyPool.size(), int64_t{0}); | ||
missingInternal = std::max(target - (int64_t)setInternalKeyPool.size(), int64_t{0}); |
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.
missingExternal = std::max(target - (int64_t)setExternalKeyPool.size(), int64_t{0}); | |
missingInternal = std::max(target - (int64_t)setInternalKeyPool.size(), int64_t{0}); | |
missingExternal = std::max(target - int64_t(setExternalKeyPool.size()), int64_t{0}); | |
missingInternal = std::max(target - int64_t(setInternalKeyPool.size()), int64_t{0}); |
Do we want this for 23.0? It fixes a segfault that a number of people have run into. |
28d3370
to
87e090a
Compare
test cases are added for inactive HD chains: a basic case, a case where the wallet is encrypted, and a case for the 21605 segfault.
87e090a
to
c4d76c6
Compare
Yes, definitely. It would be really good to have a tested ACK from someone experiencing the segfault problem. |
Code review ACK c4d76c6 |
@GITErnesO @IvRRimum are you able to test this change? |
I have 7 empty wallets that throw this error. I gave one of the wallets that throw this error to achow101 so my guess is that he checked that now it works OK. If I can get and RC or an internal version I will check all the 7 wallets. |
…places c4d76c6 tests: Tests for inactive HD chains (Andrew Chow) 8077862 wallet: Refactor TopUp to be able to top up inactive chains too (Andrew Chow) 70134eb wallet: Properly set hd chain counters when loading (Andrew Chow) 961b9e4 wallet: Parse hdKeypath if key_origin is not available (Andrew Chow) 0652ee7 Add size check on meta.key_origin.path (Rob Fielding) Pull request description: Currently inactive HD chains are only derived from at the time a key in that chain is found to have been used. However, at that time, the wallet may not be able to derive keys (e.g. it is locked). Currently we would just move on and not derive any new keys, however this could result in missing funds. This PR resolves this problem by adding memory only variables to `CHDChain` which track the highest known index. `TopUp` is modified to always try to top up the inactive HD chains, and this process will use the new variables to determine how much to top up. In this way, after an encrypted wallet is unlocked, the inactive HD chains will be topped up and hopefully funds will not be missed. Note that because these variables are not persisted to disk (because `CHDChain`s for inactive HD chains are not written to disk), if an encrypted wallet is not unlocked in the same session as a key from an inactive chain is found to be used, then it will not be topped up later unless more keys are found. Additionally, wallets which do not have upgraded key metadata will not derive any keys from inactive HD chains. This is resolved by using the derivation path string in `CKeyMetadata.hdKeypath` to determine what indexes to derive. ACKs for top commit: laanwj: Code review ACK c4d76c6 Tree-SHA512: b2b572ad7f1b1b2847edece09f7583543d63997e18ae32764e5a27ad608dd64b9bdb2d84ea27137894e986a8e82f047a3dba9c8015b74f5f179961911f0c4095
Currently inactive HD chains are only derived from at the time a key in that chain is found to have been used. However, at that time, the wallet may not be able to derive keys (e.g. it is locked). Currently we would just move on and not derive any new keys, however this could result in missing funds.
This PR resolves this problem by adding memory only variables to
CHDChain
which track the highest known index.TopUp
is modified to always try to top up the inactive HD chains, and this process will use the new variables to determine how much to top up. In this way, after an encrypted wallet is unlocked, the inactive HD chains will be topped up and hopefully funds will not be missed.Note that because these variables are not persisted to disk (because
CHDChain
s for inactive HD chains are not written to disk), if an encrypted wallet is not unlocked in the same session as a key from an inactive chain is found to be used, then it will not be topped up later unless more keys are found.Additionally, wallets which do not have upgraded key metadata will not derive any keys from inactive HD chains. This is resolved by using the derivation path string in
CKeyMetadata.hdKeypath
to determine what indexes to derive.