Skip to content

Commit 8f191ad

Browse files
committed
wallet: Migrate entire address book entries
1 parent 1472df6 commit 8f191ad

File tree

2 files changed

+70
-24
lines changed

2 files changed

+70
-24
lines changed

src/wallet/wallet.cpp

+12-24
Original file line numberDiff line numberDiff line change
@@ -3957,25 +3957,17 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
39573957
if (data.watchonly_wallet) {
39583958
LOCK(data.watchonly_wallet->cs_wallet);
39593959
if (data.watchonly_wallet->IsMine(addr_pair.first)) {
3960-
// Add to the watchonly. Preserve the labels, purpose, and change-ness
3961-
std::string label = addr_pair.second.GetLabel();
3962-
data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
3963-
if (!addr_pair.second.IsChange()) {
3964-
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
3965-
}
3960+
// Add to the watchonly. Copy the entire address book entry
3961+
data.watchonly_wallet->m_address_book[addr_pair.first] = addr_pair.second;
39663962
dests_to_delete.push_back(addr_pair.first);
39673963
continue;
39683964
}
39693965
}
39703966
if (data.solvable_wallet) {
39713967
LOCK(data.solvable_wallet->cs_wallet);
39723968
if (data.solvable_wallet->IsMine(addr_pair.first)) {
3973-
// Add to the solvable. Preserve the labels, purpose, and change-ness
3974-
std::string label = addr_pair.second.GetLabel();
3975-
data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
3976-
if (!addr_pair.second.IsChange()) {
3977-
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
3978-
}
3969+
// Add to the solvable. Copy the entire address book entry
3970+
data.solvable_wallet->m_address_book[addr_pair.first] = addr_pair.second;
39793971
dests_to_delete.push_back(addr_pair.first);
39803972
continue;
39813973
}
@@ -3995,21 +3987,13 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
39953987
// Labels for everything else ("send") should be cloned to all
39963988
if (data.watchonly_wallet) {
39973989
LOCK(data.watchonly_wallet->cs_wallet);
3998-
// Add to the watchonly. Preserve the labels, purpose, and change-ness
3999-
std::string label = addr_pair.second.GetLabel();
4000-
data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4001-
if (!addr_pair.second.IsChange()) {
4002-
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
4003-
}
3990+
// Add to the watchonly. Copy the entire address book entry
3991+
data.watchonly_wallet->m_address_book[addr_pair.first] = addr_pair.second;
40043992
}
40053993
if (data.solvable_wallet) {
40063994
LOCK(data.solvable_wallet->cs_wallet);
4007-
// Add to the solvable. Preserve the labels, purpose, and change-ness
4008-
std::string label = addr_pair.second.GetLabel();
4009-
data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4010-
if (!addr_pair.second.IsChange()) {
4011-
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
4012-
}
3995+
// Add to the solvable. Copy the entire address book entry
3996+
data.solvable_wallet->m_address_book[addr_pair.first] = addr_pair.second;
40133997
}
40143998
}
40153999
}
@@ -4024,6 +4008,10 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
40244008
// don't bother writing default values (unknown purpose)
40254009
if (addr_book_data.purpose) batch.WritePurpose(address, PurposeToString(*addr_book_data.purpose));
40264010
if (label) batch.WriteName(address, *label);
4011+
for (const auto& [id, request] : addr_book_data.receive_requests) {
4012+
batch.WriteAddressReceiveRequest(destination, id, request);
4013+
}
4014+
if (addr_book_data.previously_spent) batch.WriteAddressPreviouslySpent(destination, true);
40274015
}
40284016
};
40294017
if (data.watchonly_wallet) persist_address_book(*data.watchonly_wallet);

test/functional/wallet_migration.py

+58
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,63 @@ def test_conflict_txs(self):
770770

771771
wallet.unloadwallet()
772772

773+
def test_avoidreuse(self):
774+
self.log.info("Test that avoidreuse persists after migration")
775+
def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
776+
777+
wallet = self.create_legacy_wallet("avoidreuse")
778+
wallet.setwalletflag("avoid_reuse", True)
779+
780+
# Import a pubkey to the test wallet and send some funds to it
781+
reused_imported_addr = def_wallet.getnewaddress()
782+
wallet.importpubkey(def_wallet.getaddressinfo(reused_imported_addr)["pubkey"])
783+
txid = def_wallet.sendtoaddress(reused_imported_addr, 2)
784+
vout = find_vout_for_address(def_wallet, txid, reused_imported_addr)
785+
imported_utxo = {"txid": txid, "vout": vout}
786+
def_wallet.lockunspent(False, [imported_utxo])
787+
788+
# Send funds to the test wallet
789+
reused_addr = wallet.getnewaddress()
790+
def_wallet.sendtoaddress(reused_addr, 2)
791+
792+
self.generate(self.nodes[0], 1)
793+
794+
# Send funds from the test wallet with both its own and the imported
795+
wallet.sendall([def_wallet.getnewaddress()])
796+
def_wallet.sendall(recipients=[def_wallet.getnewaddress()], inputs=[imported_utxo])
797+
self.generate(self.nodes[0], 1)
798+
balances = wallet.getbalances()
799+
assert_equal(balances["mine"]["trusted"], 0)
800+
assert_equal(balances["watchonly"]["trusted"], 0)
801+
802+
# Reuse the addresses
803+
def_wallet.sendtoaddress(reused_addr, 1)
804+
def_wallet.sendtoaddress(reused_imported_addr, 1)
805+
self.generate(self.nodes[0], 1)
806+
balances = wallet.getbalances()
807+
assert_equal(balances["mine"]["used"], 1)
808+
# Reused watchonly will not show up in balances
809+
assert_equal(balances["watchonly"]["trusted"], 0)
810+
assert_equal(balances["watchonly"]["untrusted_pending"], 0)
811+
assert_equal(balances["watchonly"]["immature"], 0)
812+
813+
utxos = wallet.listunspent()
814+
assert_equal(len(utxos), 2)
815+
for utxo in utxos:
816+
assert_equal(utxo["reused"], True)
817+
818+
# Migrate
819+
migrate_res = wallet.migratewallet()
820+
watchonly_wallet = self.nodes[0].get_wallet_rpc(migrate_res["watchonly_name"])
821+
822+
# One utxo in each wallet, marked used
823+
utxos = wallet.listunspent()
824+
assert_equal(len(utxos), 1)
825+
assert_equal(utxos[0]["reused"], True)
826+
watchonly_utxos = watchonly_wallet.listunspent()
827+
assert_equal(len(watchonly_utxos), 1)
828+
assert_equal(watchonly_utxos[0]["reused"], True)
829+
773830
def run_test(self):
774831
self.generate(self.nodes[0], 101)
775832

@@ -787,6 +844,7 @@ def run_test(self):
787844
self.test_addressbook()
788845
self.test_migrate_raw_p2sh()
789846
self.test_conflict_txs()
847+
self.test_avoidreuse()
790848

791849
if __name__ == '__main__':
792850
WalletMigrationTest().main()

0 commit comments

Comments
 (0)