From d5f4ae7fac0bceb0c9ad939b9a4fbdb85da0bf95 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Wed, 28 Dec 2022 13:38:37 +0100 Subject: [PATCH 1/2] wallet: fully migrate address book entries for watchonly/solvable wallets Currently `migratewallet` migrates the address book (i.e. labels and purposes) for watchonly and solvable wallets only in RAM, but doesn't persist them on disk. Fix this by adding another loop for both of the special wallet types after which writes the corresponding NAME and PURPOSE entries to the database in a single batch. --- src/wallet/wallet.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d8d6c56cd51..2a5311650d3 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4002,6 +4002,23 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error) } } } + + // Persist added address book entries (labels, purpose) for watchonly and solvable wallets + auto persist_address_book = [](const CWallet& wallet) { + LOCK(wallet.cs_wallet); + WalletBatch batch{wallet.GetDatabase()}; + for (const auto& [destination, addr_book_data] : wallet.m_address_book) { + auto address{EncodeDestination(destination)}; + auto purpose{addr_book_data.purpose}; + auto label{addr_book_data.GetLabel()}; + // don't bother writing default values (unknown purpose, empty label) + if (purpose != "unknown") batch.WritePurpose(address, purpose); + if (!label.empty()) batch.WriteName(address, label); + } + }; + if (data.watchonly_wallet) persist_address_book(*data.watchonly_wallet); + if (data.solvable_wallet) persist_address_book(*data.solvable_wallet); + // Remove the things to delete if (dests_to_delete.size() > 0) { for (const auto& dest : dests_to_delete) { From 730e14a317ae45fe871c8d6f44a51936756bbbea Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Wed, 28 Dec 2022 13:41:49 +0100 Subject: [PATCH 2/2] test: wallet: check that labels are migrated to watchonly wallet --- test/functional/wallet_migration.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py index 93bd5b481a6..688ac986171 100755 --- a/test/functional/wallet_migration.py +++ b/test/functional/wallet_migration.py @@ -258,7 +258,7 @@ class WalletMigrationTest(BitcoinTestFramework): self.log.info("Test migration of a wallet with watchonly imports") imports0 = self.create_legacy_wallet("imports0") - # Exteranl address label + # External address label imports0.setlabel(default.getnewaddress(), "external") # Normal non-watchonly tx @@ -311,6 +311,13 @@ class WalletMigrationTest(BitcoinTestFramework): assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", watchonly.gettransaction, received_txid) assert_equal(len(watchonly.listtransactions(include_watchonly=True)), 3) + # Check that labels were migrated and persisted to watchonly wallet + self.nodes[0].unloadwallet("imports0_watchonly") + self.nodes[0].loadwallet("imports0_watchonly") + labels = watchonly.listlabels() + assert "external" in labels + assert "imported" in labels + def test_no_privkeys(self): default = self.nodes[0].get_wallet_rpc(self.default_wallet_name)