-
Notifications
You must be signed in to change notification settings - Fork 37.7k
wallet: Migrate legacy wallets to descriptor wallets without requiring BDB #26596
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
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. 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. |
9d6ce8a
to
03fdbaf
Compare
I think it would be easier to review if you made a separate PR for I'm pleasantly surprised at how small the implementation is. |
03fdbaf
to
bb4ea93
Compare
I don't see how reimplementing BDB is better than just continuing to use BDB. |
bb4ea93
to
a8060af
Compare
The reimplementation is quite compact because it is for only reading BDB files, only the features that we use, and none of the actual DB system stuff. BDB itself contains a ton of code, a lot of which we don't use. Maintaining it as a dependency will eventually be more burdensome - we already need to patch it in order to compile in the depends system. This reimplementation does not carry those issues - it implements a format that isn't going to change, and it only depends on things that are already being used elsewhere in the codebase. |
I've opeend #26606 for just |
a8060af
to
b29c0bf
Compare
b29c0bf
to
cfc73d1
Compare
cfc73d1
to
1af95bf
Compare
1af95bf
to
928b022
Compare
5cf595a
to
e94b4e6
Compare
Moved to #30328
I think it needs to be in the next release as it is a critical part of migration. I would prefer to have it in a release that people can use before deleting the legacy wallet.
Updated
Fixed
No, we should not be migrating a wallet if we cannot decrypt the keys. |
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.
Strange CI https://github.com/bitcoin/bitcoin/actions/runs/9649050504/job/26611651920?pr=26596 error.. it doesn't seem to be related. The "salvage" command opens the wallet in DatabaseFormat::BERKELEY
format.
When we reopen the wallet to do the migration, instead of opening using BDB, open it using the BerkeleyRO implementation.
e94b4e6
to
9700c21
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.
git range-diff master a8f8a2d 9700c217
Agree with @furszy on reordering the commits to make it possible to retain the 3 asserts in MigrateToDescriptor()
.
In order to load the necessary data for migrating a legacy wallet without the full LegacyScriptPubKeyMan, move the data storage and loading components to LegacyDataSPKM. LegacyScriptPubKeyMan now subclasses that.
IsMine is necessary for migration. It should be inlined with migration when the legacy wallet is removed.
In SetupLegacyScriptPubKeyMan, a base LegacyDataSPKM will be created if the database has the format "bdb_ro" (i.e. the wallet was opened only for migration purposes). All of the loading functions are now called with a LegacyDataSPKM object instead of LegacyScriptPubKeyMan.
The migration process reloads the wallet after all failures. This commit tests the behavior by trying to obtain a new address after a decryption failure during migration.
9700c21
to
8ce3739
Compare
Reordered the commits and preserved the |
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 8ce3739
git range-diff 9700c217~5..9700c217 8ce3739~5..8ce3739
- not the easiest read, also used GH compare.
Passed make check
& test/functional/test_runner.py
including p2p_handshake.py
which failed on CI.
Only one non-critical reservation: #26596 (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.
Code-review ACK 8ce3739
LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const | ||
{ | ||
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { | ||
return nullptr; | ||
} | ||
auto it = m_internal_spk_managers.find(OutputType::LEGACY); | ||
if (it == m_internal_spk_managers.end()) return nullptr; | ||
return dynamic_cast<LegacyDataSPKM*>(it->second); | ||
} |
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.
nit: was about to suggest to deduplicate shared code between this method and ::GetLegacyScriptPubKeyMan
above, but since the latter is removed soon anyway (in PR #28710, commit 5652a9c#diff-1f2db0e4d5c12d109c7f0962333c245b49b696cb39ff432da048e9d6c08944d8), it's probably not worth it.
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.
If you re-touch it again. Could:
LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const
{
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { return nullptr; }
return dynamic_cast<LegacyDataSPKM*>(GetScriptPubKeyMan(OutputType::LEGACY, /*internal=*/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.
Code review ACK 8ce3739
LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const | ||
{ | ||
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { | ||
return nullptr; | ||
} | ||
auto it = m_internal_spk_managers.find(OutputType::LEGACY); | ||
if (it == m_internal_spk_managers.end()) return nullptr; | ||
return dynamic_cast<LegacyDataSPKM*>(it->second); | ||
} |
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.
If you re-touch it again. Could:
LegacyDataSPKM* CWallet::GetLegacyDataSPKM() const
{
if (IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { return nullptr; }
return dynamic_cast<LegacyDataSPKM*>(GetScriptPubKeyMan(OutputType::LEGACY, /*internal=*/true));
}
void LegacyScriptPubKeyMan::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata& meta) | ||
{ | ||
LOCK(cs_KeyStore); | ||
LegacyDataSPKM::LoadKeyMetadata(keyID, meta); | ||
UpdateTimeFirstKey(meta.nCreateTime); | ||
mapKeyMetadata[keyID] = meta; | ||
} |
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 7461d0c:
At this point, just a non-blocking nit but you are locking cs_KeyStore
twice. One here, and another one inside LegacyDataSPKM::LoadKeyMetadata
.
Same for LoadScriptMetadata
.
bool LegacyDataSPKM::AddKeyPubKeyInner(const CKey& key, const CPubKey& pubkey) | ||
{ | ||
LOCK(cs_KeyStore); | ||
return FillableSigningProvider::AddKeyPubKey(key, pubkey); |
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 7461d0c:
FillableSigningProvider::AddKeyPubKey
already locks cs_Keystore
internally.
#26606 introduced
BerkeleyRODatabase
which is an independent parser for BDB files. This PR uses this in legacy wallet migration so that migration will continue to work once the legacy wallet and BDB are removed.LegacyDataSPKM
is introduced to have the minimum data and functions necessary for a legacy wallet to be loaded for migration.