Skip to content

Commit 4fcd3ef

Browse files
committed
wallet: Migrate entire address book entries
1 parent 744157e commit 4fcd3ef

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
@@ -827,6 +827,63 @@ def test_hybrid_pubkey(self):
827827

828828
wallet.unloadwallet()
829829

830+
def test_avoidreuse(self):
831+
self.log.info("Test that avoidreuse persists after migration")
832+
def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
833+
834+
wallet = self.create_legacy_wallet("avoidreuse")
835+
wallet.setwalletflag("avoid_reuse", True)
836+
837+
# Import a pubkey to the test wallet and send some funds to it
838+
reused_imported_addr = def_wallet.getnewaddress()
839+
wallet.importpubkey(def_wallet.getaddressinfo(reused_imported_addr)["pubkey"])
840+
txid = def_wallet.sendtoaddress(reused_imported_addr, 2)
841+
vout = find_vout_for_address(def_wallet, txid, reused_imported_addr)
842+
imported_utxo = {"txid": txid, "vout": vout}
843+
def_wallet.lockunspent(False, [imported_utxo])
844+
845+
# Send funds to the test wallet
846+
reused_addr = wallet.getnewaddress()
847+
def_wallet.sendtoaddress(reused_addr, 2)
848+
849+
self.generate(self.nodes[0], 1)
850+
851+
# Send funds from the test wallet with both its own and the imported
852+
wallet.sendall([def_wallet.getnewaddress()])
853+
def_wallet.sendall(recipients=[def_wallet.getnewaddress()], inputs=[imported_utxo])
854+
self.generate(self.nodes[0], 1)
855+
balances = wallet.getbalances()
856+
assert_equal(balances["mine"]["trusted"], 0)
857+
assert_equal(balances["watchonly"]["trusted"], 0)
858+
859+
# Reuse the addresses
860+
def_wallet.sendtoaddress(reused_addr, 1)
861+
def_wallet.sendtoaddress(reused_imported_addr, 1)
862+
self.generate(self.nodes[0], 1)
863+
balances = wallet.getbalances()
864+
assert_equal(balances["mine"]["used"], 1)
865+
# Reused watchonly will not show up in balances
866+
assert_equal(balances["watchonly"]["trusted"], 0)
867+
assert_equal(balances["watchonly"]["untrusted_pending"], 0)
868+
assert_equal(balances["watchonly"]["immature"], 0)
869+
870+
utxos = wallet.listunspent()
871+
assert_equal(len(utxos), 2)
872+
for utxo in utxos:
873+
assert_equal(utxo["reused"], True)
874+
875+
# Migrate
876+
migrate_res = wallet.migratewallet()
877+
watchonly_wallet = self.nodes[0].get_wallet_rpc(migrate_res["watchonly_name"])
878+
879+
# One utxo in each wallet, marked used
880+
utxos = wallet.listunspent()
881+
assert_equal(len(utxos), 1)
882+
assert_equal(utxos[0]["reused"], True)
883+
watchonly_utxos = watchonly_wallet.listunspent()
884+
assert_equal(len(watchonly_utxos), 1)
885+
assert_equal(watchonly_utxos[0]["reused"], True)
886+
830887
def run_test(self):
831888
self.generate(self.nodes[0], 101)
832889

@@ -845,6 +902,7 @@ def run_test(self):
845902
self.test_migrate_raw_p2sh()
846903
self.test_conflict_txs()
847904
self.test_hybrid_pubkey()
905+
self.test_avoidreuse()
848906

849907
if __name__ == '__main__':
850908
WalletMigrationTest().main()

0 commit comments

Comments
 (0)