wallet, migration: Fix empty wallet crash #32149

pull pablomartin4btc wants to merge 2 commits into bitcoin:master from pablomartin4btc:wallet-migration-empty-wallet-crash-fix changing 5 files +51 −20
  1. pablomartin4btc commented at 2:32 am on March 27, 2025: member

    Same as with a blank wallet (#28976), wallets with no legacy records (i.e. empty, non-blank, watch-only wallet) do not require to be migrated.

    Steps to reproduce the issue:

    1.- createwallet "empty_wo_noblank_legacy_wallet" true false "" false false 2.- migratewallet

    0wallet/wallet.cpp:4071 GetDescriptorsForLegacy: Assertion `legacy_spkm' failed.
    1Aborted (core dumped)
    
  2. DrahtBot commented at 2:32 am on March 27, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32149.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK furszy, BrandonOdiwuor, davidgumberg, fjahr, achow101
    Concept ACK rkrux
    Stale ACK w0xlt

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #31423 (wallet: migration, don’t create spendable wallet from a watch-only legacy wallet by furszy)
    • #30343 (wallet, logging: Replace WalletLogPrintf() with LogInfo() by ryanofsky)
    • #29124 (wallet: Automatically repair corrupted metadata with doubled derivation path by achow101)

    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.

  3. laanwj added the label Wallet on Mar 27, 2025
  4. in src/wallet/wallet.cpp:4545 in 9962614b90 outdated
    4541+            empty_wallet = !HasLegacyRecords(local_wallet.get(), *db_batch);
    4542+        }
    4543+
    4544         // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    4545-        success = local_wallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
    4546+        success = empty_wallet || local_wallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
    


    furszy commented at 2:05 pm on March 27, 2025:

    In 9962614b9060:

    I changed my mind here. The blank flag check seems redundant and could even be harmful if it isn’t unset after key import or creation for some reason. This could just be a:

    0success = empty_wallet;
    

    pablomartin4btc commented at 2:28 pm on March 27, 2025:
    Ok, I’ll check, I’ve tested already that when you import an address the flag gets unset.
  5. in test/functional/wallet_migration.py:450 in 9962614b90 outdated
    444@@ -445,6 +445,39 @@ def test_no_privkeys(self):
    445         # After migrating, the "keypool" is empty
    446         assert_raises_rpc_error(-4, "Error: This wallet has no available keys", watchonly1.getnewaddress)
    447 
    448+        # Migrating a watch-only blank empty wallet (with no pubkeys)
    449+        self.log.info("Test migration of a pure watchonly blank empty wallet (with no pubkeys)")
    450+        watchonly2 = self.create_legacy_wallet("watchonly2", disable_private_keys=True, blank=True)
    


    furszy commented at 2:07 pm on March 27, 2025:
    the blank=True flag is not needed when you disable private keys.

    pablomartin4btc commented at 2:30 pm on March 27, 2025:
    But wanted to make it explicit that as the wallet is empty, not imported address, the flag will remain the same after migration.
  6. in test/functional/wallet_migration.py:455 in 9962614b90 outdated
    450+        watchonly2 = self.create_legacy_wallet("watchonly2", disable_private_keys=True, blank=True)
    451+        # Before migrating
    452+        info = watchonly2.getwalletinfo()
    453+        assert_equal(info["descriptors"], False)
    454+        assert_equal(info["private_keys_enabled"], False)
    455+        assert_equal(info["blank"], True)
    


    furszy commented at 2:12 pm on March 27, 2025:

    In https://github.com/bitcoin/bitcoin/commit/9962614b9060e9713042de91dc04ff5ea6604ae1:

    The first check is redundant —create_legacy_wallet() already performs it. The other two checks are unnecessary. You want to verify migration here, not whether createwallet() works as expected, that’s something different.


    pablomartin4btc commented at 2:30 pm on March 27, 2025:
    Ok, I’ll remove it.
  7. in test/functional/wallet_migration.py:460 in 9962614b90 outdated
    455+        assert_equal(info["blank"], True)
    456+
    457+        _, watchonly2 = self.migrate_and_get_rpc("watchonly2")
    458+        # After migrating
    459+        info = watchonly2.getwalletinfo()
    460+        assert_equal(info["descriptors"], True)
    


    furszy commented at 2:13 pm on March 27, 2025:

    In https://github.com/bitcoin/bitcoin/commit/9962614b9060e9713042de91dc04ff5ea6604ae1:

    this check is redundant, migrate_and_get_rpc() already checks it.


    pablomartin4btc commented at 2:57 pm on March 27, 2025:
    I can see I got confused with other tests that validate it but I see they call migratewallet instead (and then get_wallet_rpc - I can do a follow-up to clean it up later). Same for assert_is_sqlite, I’ll remove it, since migrate_and_get_rpc() already calls it within. Thanks!
  8. in test/functional/wallet_migration.py:462 in 9962614b90 outdated
    457+        _, watchonly2 = self.migrate_and_get_rpc("watchonly2")
    458+        # After migrating
    459+        info = watchonly2.getwalletinfo()
    460+        assert_equal(info["descriptors"], True)
    461+        assert_equal(info["private_keys_enabled"], False)
    462+        assert_equal(info["blank"], True)
    


    furszy commented at 2:18 pm on March 27, 2025:

    In https://github.com/bitcoin/bitcoin/commit/9962614b9060e9713042de91dc04ff5ea6604ae1:

    This is actually asserting the wrong behavior. The migrated wallet should have private keys disabled, just like the legacy wallet.


    pablomartin4btc commented at 2:37 pm on March 27, 2025:

    The migrated wallet should have private keys disabled

    Yes, it’s doing that (private_keys_enabled = False), otherwise it would be failing.


    furszy commented at 2:44 pm on March 27, 2025:
    ha, I read it in the other way around.. “private_keys_disabled”.. all good. Can solve this comment.
  9. in test/functional/wallet_migration.py:456 in 9962614b90 outdated
    475+        info = watchonly3.getwalletinfo()
    476+        assert_equal(info["descriptors"], True)
    477+        assert_equal(info["private_keys_enabled"], False)
    478+        assert_equal(info["blank"], False)
    479+        self.assert_is_sqlite("watchonly3")
    480+
    


    furszy commented at 2:50 pm on March 27, 2025:

    Could probably re-write this test in just a few lines:

    0self.log.info("Test migration of a watch-only empty wallet")
    1for is_blank in [True, False]:
    2    self.create_legacy_wallet("watchonly_empty", disable_private_keys=True, blank=is_blank)
    3    _, watchonly_empty = self.migrate_and_get_rpc("watchonly_empty")
    4    info = watchonly_empty.getwalletinfo()
    5    assert_equal(info["private_keys_enabled"], False)
    6    assert_equal(info["blank"], is_blank)
    

    pablomartin4btc commented at 2:58 pm on March 27, 2025:
    Yup, much better! Cheers!
  10. furszy commented at 2:51 pm on March 27, 2025: member
    added another suggestion
  11. pablomartin4btc force-pushed on Mar 27, 2025
  12. DrahtBot added the label CI failed on Mar 27, 2025
  13. pablomartin4btc force-pushed on Mar 27, 2025
  14. pablomartin4btc commented at 4:55 pm on March 27, 2025: member

    Updates:

  15. DrahtBot removed the label CI failed on Mar 27, 2025
  16. in src/wallet/test/walletdb_tests.cpp:52 in 61f0d7908c outdated
    47@@ -48,10 +48,13 @@ BOOST_AUTO_TEST_CASE(walletdb_read_write_deadlock)
    48         LOCK(wallet->cs_wallet);
    49         auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan();
    50         BOOST_CHECK(legacy_spkm->SetupGeneration(true));
    51+        const auto& db_batch = wallet->GetDatabase().MakeBatch();
    52+        BOOST_CHECK(HasLegacyRecords(wallet.get(), *db_batch));
    


    furszy commented at 1:00 pm on March 28, 2025:

    This leaves the db batch object alive and could conflict with the Flush() and DeleteRecords() internals, as both access the db.

    Better to limit the scope of the db batch object only to this function call.

  17. pablomartin4btc force-pushed on Mar 28, 2025
  18. pablomartin4btc commented at 4:28 pm on March 28, 2025: member

    Updates:

  19. in src/wallet/test/walletdb_tests.cpp:64 in ff7f9bb0b8 outdated
    58-        // Now delete all records, which performs a read write operation.
    59-        BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords());
    60+            // Now delete all records, which performs a read write operation.
    61+            BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords());
    62+            BOOST_CHECK(!HasLegacyRecords(wallet.get(), *db_batch));
    63+        }
    


    furszy commented at 10:10 pm on March 28, 2025:
    You didn’t change the behavior on the latest push. The db_batch object is alive while Flush() and DeleteRecords() are called. My suggestion was to scope each single HasLegacyRecords() call so it does not interfere with the other calls who also access db.

    pablomartin4btc commented at 11:12 am on March 29, 2025:
    Yup, fixed it, thanks!
  20. pablomartin4btc force-pushed on Mar 29, 2025
  21. pablomartin4btc force-pushed on Mar 29, 2025
  22. pablomartin4btc commented at 11:38 am on March 29, 2025: member

    Updates:

  23. in src/wallet/wallet.cpp:4545 in ef994480ea outdated
    4541+            empty_wallet = !HasLegacyRecords(local_wallet.get(), *db_batch);
    4542+        }
    4543+
    4544         // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    4545-        success = local_wallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
    4546+        success = empty_wallet;
    


    fjahr commented at 3:56 pm on March 30, 2025:

    Seems like this can be simplified (with maybe an additional comment that an empty wallet means automatic success)

    0        {
    1            // Keep the batch alive only for this call
    2            const auto& db_batch = local_wallet->GetDatabase().MakeBatch();
    3            success = !HasLegacyRecords(local_wallet.get(), *db_batch);
    4        }
    5
    6        // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    

    pablomartin4btc commented at 10:06 am on March 31, 2025:
    Yeah, I’ll tweak it a bit. Thanks!
  24. in src/wallet/wallet.cpp:4539 in ef994480ea outdated
    4533@@ -4534,8 +4534,15 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
    4534         // First change to using SQLite
    4535         if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
    4536 
    4537+        bool empty_wallet{false};
    4538+        {
    4539+            // Keep the batch alive only for this call
    


    fjahr commented at 3:59 pm on March 30, 2025:
    nit: I find this comment a bit redundant, especially in the tests. If you rename db_batch to temp_batch IMO it could be removed.

    pablomartin4btc commented at 10:05 am on March 31, 2025:
    Thanks! I’ll overload HasLegacyRecords so it’d make it even cleaner I think.
  25. in src/wallet/walletdb.h:337 in ef994480ea outdated
    332@@ -333,6 +333,9 @@ bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::stri
    333 bool LoadCryptedKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr);
    334 bool LoadEncryptionKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr);
    335 bool LoadHDChain(CWallet* pwallet, DataStream& ssValue, std::string& strErr);
    336+
    337+//! Returns true if there is any DBKeys::LEGACY_TYPES record in the wallet db
    


    fjahr commented at 3:59 pm on March 30, 2025:

    nit

    0//! Returns true if there are any DBKeys::LEGACY_TYPES records in the wallet db
    
  26. fjahr commented at 4:01 pm on March 30, 2025: contributor
    Concept ACK
  27. pablomartin4btc force-pushed on Mar 31, 2025
  28. pablomartin4btc commented at 10:28 am on March 31, 2025: member

    Updates:

    • Addressed @fjahr’s feedback.
  29. pablomartin4btc force-pushed on Mar 31, 2025
  30. fjahr commented at 1:36 pm on March 31, 2025: contributor

    tACK d4cb6d048b0222cf51c8a56fa56f97dd5d2c9add

    Changes look good to me and I confirmed that the new test fails on master.

  31. in src/wallet/wallet.cpp:4538 in d4cb6d048b outdated
    4534@@ -4535,7 +4535,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
    4535         if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
    4536 
    4537         // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    4538-        success = local_wallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
    4539+        success = !HasLegacyRecords(local_wallet.get());;
    


    furszy commented at 2:03 pm on March 31, 2025:
    extra ; at the end.

    pablomartin4btc commented at 2:09 pm on March 31, 2025:
    argh! Thanks!
  32. pablomartin4btc force-pushed on Mar 31, 2025
  33. pablomartin4btc commented at 2:12 pm on March 31, 2025: member
    Fixed a typo.
  34. furszy commented at 2:13 pm on March 31, 2025: member
    Code review ACK eb4333c8aa4a8f1a66ecbe5c48dbe15467332864
  35. DrahtBot requested review from fjahr on Mar 31, 2025
  36. fjahr commented at 2:21 pm on March 31, 2025: contributor
    re-ACK eb4333c8aa4a8f1a66ecbe5c48dbe15467332864
  37. in src/wallet/walletdb.cpp:560 in 0d0a7fc7ea outdated
    555+
    556+        prefix << type;
    557+        std::unique_ptr<DatabaseCursor> cursor = batch.GetNewPrefixCursor(prefix);
    558+        if (!cursor) {
    559+            // Could only happen on a closed db, which means there is an error in the code flow.
    560+            pwallet->WalletLogPrintf("Error getting database cursor for '%s' records", type);
    


    davidgumberg commented at 6:09 pm on April 1, 2025:
    Just a question: Why log the same message that gets thrown?

    furszy commented at 7:14 pm on April 1, 2025:
    Because the caller is not logging it and didn’t want to change the existing behavior in the refactoring commit, the pwallet argument could have otherwise been removed.
  38. in src/wallet/test/walletdb_tests.cpp:49 in 0d0a7fc7ea outdated
    47@@ -48,10 +48,12 @@ BOOST_AUTO_TEST_CASE(walletdb_read_write_deadlock)
    48         LOCK(wallet->cs_wallet);
    49         auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan();
    


    davidgumberg commented at 6:29 pm on April 1, 2025:

    nit, if you retouch:

    0        auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan();
    1        BOOST_CHECK(!HasLegacyRecords(wallet.get()));
    
  39. in src/wallet/walletdb.cpp:565 in 0d0a7fc7ea outdated
    560+            pwallet->WalletLogPrintf("Error getting database cursor for '%s' records", type);
    561+            throw std::runtime_error(strprintf("Error getting database cursor for '%s' records", type));
    562+        }
    563+
    564+        DatabaseCursor::Status status = cursor->Next(key, value);
    565+        if (status != DatabaseCursor::Status::DONE) {
    


    davidgumberg commented at 6:34 pm on April 1, 2025:

    maybe this should be:

    0        if (status == DatabaseCursor::Status::MORE)
    

    as is done in WalletBatch::IsEncrypted(). That would more correctly handle Status::FAIL which I presume is extremely unlikely here.

    Edit: And out of scope of this refactor commit, feel free to disregard, just an observation.


    furszy commented at 7:22 pm on April 1, 2025:
    If it fails, we should abort the process. Probably by throwing an exception. But I would leave that for another PR to avoid mixing it with this crash fix.
  40. davidgumberg commented at 0:05 am on April 2, 2025: contributor

    ACK eb4333c8aa4a8f1a66ecbe5c48dbe15467332864

    Tested that this fixes the issue in the PR description and also fixes another issue, #32112 (see #32112 (comment)). Reviewed and manually verified that the test case added here in test/functional/wallet_migration.py catches the issue in master. This refactor also improves readability of LoadLegacyWalletRecords().

  41. in src/wallet/wallet.cpp:4537 in eb4333c8aa outdated
    4534@@ -4535,7 +4535,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
    4535         if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
    4536 
    4537         // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    


    rkrux commented at 12:15 pm on April 2, 2025:

    The comment can be updated now to account for empty wallets as well.

    0-        // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    1+        // Do the migration of keys and scripts for non-blank and non-empty wallets, and cleanup if it fails
    

    pablomartin4btc commented at 1:56 pm on April 2, 2025:
    I’d just keep “for non-empty wallets” instead, as we did remove the flag check as well in a previous iteration.
  42. in src/wallet/wallet.cpp:4539 in eb4333c8aa outdated
    4534@@ -4535,7 +4535,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
    4535         if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
    4536 
    4537         // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    4538-        success = local_wallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
    4539+        success = !HasLegacyRecords(local_wallet.get());
    4540         if (!success) {
    


    rkrux commented at 12:35 pm on April 2, 2025:

    This has become a double negation now that makes it tougher to read imo. We can get rid of setting the success variable here and directly add in the if condition. Moreover, setting success here seems quite unusual to me, just like it was in the previous code as well. I believe it can be directly updated in the if condition.

    I notice that the migration is done only if success is false and then updated. But if success evaluates to true at this line, the migration is skipped and success remains true. To handle this, success can be initially set to true. Also, I believe this is an opportunity to narrow the scope of success here because it’s not used in the previous if block at all.

    So, the overall diff is below, which is more than originally intended but I believe it makes this code block more readable. All the unit tests and the migration functional tests pass.

     0     res.backup_path = backup_path;
     1 
     2-    bool success = false;
     3-
     4     // Unlock the wallet if needed
     5     if (local_wallet->IsLocked() && !local_wallet->Unlock(passphrase)) {
     6         if (was_loaded) {
     7@@ -4529,14 +4527,14 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
     8         }
     9     }
    10 
    11+    bool success = true;
    12     {
    13         LOCK(local_wallet->cs_wallet);
    14         // First change to using SQLite
    15         if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
    16 
    17         // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    18-        success = !HasLegacyRecords(local_wallet.get());
    19-        if (!success) {
    20+        if (HasLegacyRecords(local_wallet.get())) {
    21             success = DoMigration(*local_wallet, context, error, res);
    22         } else {
    23             // Make sure that descriptors flag is actually set
    

    pablomartin4btc commented at 2:18 pm on April 2, 2025:
    Ok, I’ll take your suggestion, thanks!
  43. rkrux changes_requested
  44. rkrux commented at 12:46 pm on April 2, 2025: contributor

    Concept ACK eb4333c8aa4a8f1a66ecbe5c48dbe15467332864

    Suggested changes based on readability.

  45. in src/wallet/walletdb.cpp:561 in 0d0a7fc7ea outdated
    556+        prefix << type;
    557+        std::unique_ptr<DatabaseCursor> cursor = batch.GetNewPrefixCursor(prefix);
    558+        if (!cursor) {
    559+            // Could only happen on a closed db, which means there is an error in the code flow.
    560+            pwallet->WalletLogPrintf("Error getting database cursor for '%s' records", type);
    561+            throw std::runtime_error(strprintf("Error getting database cursor for '%s' records", type));
    


    rkrux commented at 1:29 pm on April 2, 2025:

    Throwing a runtime error here now instead of returning DBErrors::CORRUPT that the older code was doing makes sense to me. In case of loading wallet, this will be caught later, ultimately evaluating to the same DBError: https://github.com/bitcoin/bitcoin/blob/cfa7f70f6c99680851ab0c0df27baf9f7508747b/src/wallet/walletdb.cpp#L1219-L1223

    And in case of migrating wallet flow, this will not be caught but bubble up all the way to the RPC response, which seems ok to me.

  46. in src/wallet/walletdb.cpp:549 in eb4333c8aa outdated
    544+{
    545+    const auto& batch = pwallet->GetDatabase().MakeBatch();
    546+    return HasLegacyRecords(pwallet, *batch);
    547+}
    548+
    549+bool HasLegacyRecords(CWallet* pwallet, DatabaseBatch& batch)
    


    maflcko commented at 2:29 pm on April 2, 2025:
    0bool HasLegacyRecords(CWallet& wallet)
    1{
    2    const auto& batch = wallet.GetDatabase().MakeBatch();
    3    return HasLegacyRecords(wallet, *batch);
    4}
    5
    6bool HasLegacyRecords(CWallet& wallet, DatabaseBatch& batch)
    

    nit (feel free to ignore): If a function does not accept or handle a nullptr as an arg, it is better to just use a reference, which can not be null. This is self-documenting and also makes it clear to the caller that passing a nullptr would lead to UB.


    pablomartin4btc commented at 3:36 pm on April 2, 2025:
    I´ll take it, thanks!
  47. pablomartin4btc force-pushed on Apr 2, 2025
  48. pablomartin4btc commented at 4:11 pm on April 2, 2025: member

    Updates:

  49. pablomartin4btc force-pushed on Apr 2, 2025
  50. pablomartin4btc force-pushed on Apr 2, 2025
  51. pablomartin4btc commented at 4:49 pm on April 2, 2025: member
    Sorry for the mess, I thought there was a failure (individual commits) due to missing rebase but I checked it was unrelated so reverted it back.
  52. in src/wallet/wallet.cpp:4538 in aa7ec12d08 outdated
    4533@@ -4534,9 +4534,8 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
    4534         // First change to using SQLite
    4535         if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
    4536 
    4537-        // Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
    4538-        success = local_wallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
    4539-        if (!success) {
    4540+        // Do the migration of keys and scripts for non-empty wallets, and cleanup if it fails
    4541+        if (HasLegacyRecords(*local_wallet.get())) {
    


    maflcko commented at 5:58 pm on April 2, 2025:

    nit: no need for the get() now.

    0        if (HasLegacyRecords(*local_wallet)) {
    

    (If you want to fix the test-each-commit CI, a rebase should do it, or the failure can be ignored for now)


    pablomartin4btc commented at 8:22 pm on April 2, 2025:

    Ok I saw other places where * and get() it’s being used, I can do a follow-up and fix them all in 1 go.

    For the CI, I’d leave it as is, easier for current reviewers.


    maflcko commented at 8:37 pm on April 2, 2025:
    If you want to do them in one go, just using https://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-smartptr-get.html should be enough.

    furszy commented at 11:48 pm on April 2, 2025:
    It would be nice to fix the ones introduced by this PR here. We are already reviewing those lines.
  53. w0xlt commented at 8:46 pm on April 2, 2025: contributor
  54. DrahtBot requested review from furszy on Apr 2, 2025
  55. DrahtBot requested review from rkrux on Apr 2, 2025
  56. DrahtBot requested review from davidgumberg on Apr 2, 2025
  57. pablomartin4btc force-pushed on Apr 3, 2025
  58. pablomartin4btc commented at 10:49 am on April 3, 2025: member

    Updates:

  59. wallet, refactor: Decouple into HasLegacyRecords()
    The new helper will be used to fix a crash in the
    wallet migration process (watch-only, non-blank,
    private keys disabled, empty wallet - no scripts
    or addresses imported).
    
    Co-authored-by: Matias Furszyfer <mfurszy@protonmail.com>
    42c13141b5
  60. pablomartin4btc force-pushed on Apr 3, 2025
  61. pablomartin4btc commented at 10:57 am on April 3, 2025: member
    Rebased to fix test-each-commit CI failure.
  62. furszy commented at 3:02 pm on April 3, 2025: member
    the second commit has a typo in its title
  63. pablomartin4btc force-pushed on Apr 3, 2025
  64. pablomartin4btc commented at 3:17 pm on April 3, 2025: member

    the second commit has a typo in its title

    Fixed.

  65. in src/wallet/wallet.cpp:4514 in 099ae95122 outdated
    4510@@ -4511,7 +4511,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(std::shared_ptr<CWallet>
    4511     }
    4512     res.backup_path = backup_path;
    4513 
    4514-    bool success = false;
    4515+    bool success{true};
    


    furszy commented at 5:45 pm on April 3, 2025:

    I’m not sure about this change; it could be a source of bugs if we ever add something within the procedure without updating this value.

    Yet, if others are happy with it, it is fine for me.


    pablomartin4btc commented at 10:43 pm on April 3, 2025:
    Yeah, I think so too. We could revert it back to initialize it with false and set it to true in the else clause where we do local_wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);? (or success = Assert(local_wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));)

    rkrux commented at 2:04 pm on April 4, 2025:
    This previous suggestion #32149 (review) also contained narrowing the scope of the success variable that imho should make it less likely to miss updating this variable.

    pablomartin4btc commented at 4:42 pm on April 4, 2025:

    Another alternative could be moving the initialisation of success close to the conditional as it’s done in CWallet::MarkReplaced:

    https://github.com/bitcoin/bitcoin/blob/65dcbec75661d1652beb927f03b1feab4fab932e/src/wallet/wallet.cpp#L1012-L1016


    furszy commented at 7:01 pm on April 4, 2025:

    For simplicity, we could just:

    0// Do the migration of keys and scripts for non-empty wallets, and cleanup if it fails
    1if (HasLegacyRecords()) {
    2    success = DoMigration(*local_wallet, context, error, res);
    3} else {
    4    // Make sure that descriptors flag is actually set
    5    local_wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
    6    success = true;
    7}
    

    Leaving the success=false initialization.

  66. wallet, migration: Fix crash on empty wallet
    Same as with a blank wallet, wallets with no legacy
    records (i.e. empty, non-blank, watch-only wallet)
    do not require to be migrated.
    0f602c5693
  67. pablomartin4btc force-pushed on Apr 4, 2025
  68. furszy commented at 10:46 pm on April 4, 2025: member
    ACK 0f602c5693ef5d0c63b1e5b7dc0990dced3655d6
  69. maflcko closed this on Apr 7, 2025

  70. maflcko reopened this on Apr 7, 2025

  71. BrandonOdiwuor commented at 6:39 am on April 8, 2025: contributor
    Code Review ACK 0f602c5693ef5d0c63b1e5b7dc0990dced3655d6
  72. davidgumberg commented at 9:37 pm on April 8, 2025: contributor
  73. fjahr commented at 2:47 pm on April 9, 2025: contributor
    re-ACK 0f602c5693ef5d0c63b1e5b7dc0990dced3655d6
  74. achow101 commented at 0:14 am on April 10, 2025: member
    ACK 0f602c5693ef5d0c63b1e5b7dc0990dced3655d6
  75. achow101 merged this on Apr 10, 2025
  76. achow101 closed this on Apr 10, 2025

  77. fanquake commented at 10:45 am on April 15, 2025: member
    Looks like this broke the wallet migration benchmark: #32277.
  78. fjahr commented at 10:53 am on April 15, 2025: contributor

    Looks like this broke the wallet migration benchmark: #32149.

    That’s this PR, you meant to link to this I guess: #32277

  79. pablomartin4btc commented at 11:31 am on April 15, 2025: member
    checking…

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-04-29 09:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me