Skip to content

Commit af91cfa

Browse files
committed
wallet: Migrate entire address book entries
1 parent 51f640f commit af91cfa

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
@@ -3970,25 +3970,17 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
39703970
if (data.watchonly_wallet) {
39713971
LOCK(data.watchonly_wallet->cs_wallet);
39723972
if (data.watchonly_wallet->IsMine(addr_pair.first)) {
3973-
// Add to the watchonly. Preserve the labels, purpose, and change-ness
3974-
std::string label = addr_pair.second.GetLabel();
3975-
data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
3976-
if (!addr_pair.second.IsChange()) {
3977-
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
3978-
}
3973+
// Add to the watchonly. Copy the entire address book entry
3974+
data.watchonly_wallet->m_address_book[addr_pair.first] = addr_pair.second;
39793975
dests_to_delete.push_back(addr_pair.first);
39803976
continue;
39813977
}
39823978
}
39833979
if (data.solvable_wallet) {
39843980
LOCK(data.solvable_wallet->cs_wallet);
39853981
if (data.solvable_wallet->IsMine(addr_pair.first)) {
3986-
// Add to the solvable. Preserve the labels, purpose, and change-ness
3987-
std::string label = addr_pair.second.GetLabel();
3988-
data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
3989-
if (!addr_pair.second.IsChange()) {
3990-
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
3991-
}
3982+
// Add to the solvable. Copy the entire address book entry
3983+
data.solvable_wallet->m_address_book[addr_pair.first] = addr_pair.second;
39923984
dests_to_delete.push_back(addr_pair.first);
39933985
continue;
39943986
}
@@ -4008,21 +4000,13 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
40084000
// Labels for everything else ("send") should be cloned to all
40094001
if (data.watchonly_wallet) {
40104002
LOCK(data.watchonly_wallet->cs_wallet);
4011-
// Add to the watchonly. Preserve the labels, purpose, and change-ness
4012-
std::string label = addr_pair.second.GetLabel();
4013-
data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4014-
if (!addr_pair.second.IsChange()) {
4015-
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
4016-
}
4003+
// Add to the watchonly. Copy the entire address book entry
4004+
data.watchonly_wallet->m_address_book[addr_pair.first] = addr_pair.second;
40174005
}
40184006
if (data.solvable_wallet) {
40194007
LOCK(data.solvable_wallet->cs_wallet);
4020-
// Add to the solvable. Preserve the labels, purpose, and change-ness
4021-
std::string label = addr_pair.second.GetLabel();
4022-
data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
4023-
if (!addr_pair.second.IsChange()) {
4024-
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
4025-
}
4008+
// Add to the solvable. Copy the entire address book entry
4009+
data.solvable_wallet->m_address_book[addr_pair.first] = addr_pair.second;
40264010
}
40274011
}
40284012
}
@@ -4037,6 +4021,10 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
40374021
// don't bother writing default values (unknown purpose)
40384022
if (addr_book_data.purpose) batch.WritePurpose(address, PurposeToString(*addr_book_data.purpose));
40394023
if (label) batch.WriteName(address, *label);
4024+
for (const auto& [id, request] : addr_book_data.receive_requests) {
4025+
batch.WriteAddressReceiveRequest(destination, id, request);
4026+
}
4027+
if (addr_book_data.previously_spent) batch.WriteAddressPreviouslySpent(destination, true);
40404028
}
40414029
};
40424030
if (data.watchonly_wallet) persist_address_book(*data.watchonly_wallet);

test/functional/wallet_migration.py

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

782782
wallet.unloadwallet()
783783

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

@@ -798,6 +855,7 @@ def run_test(self):
798855
self.test_addressbook()
799856
self.test_migrate_raw_p2sh()
800857
self.test_conflict_txs()
858+
self.test_avoidreuse()
801859

802860
if __name__ == '__main__':
803861
WalletMigrationTest().main()

0 commit comments

Comments
 (0)