Skip to content

Commit

Permalink
wallet: Migrate entire address book entries
Browse files Browse the repository at this point in the history
  • Loading branch information
achow101 committed Oct 11, 2023
1 parent 744157e commit 4fcd3ef
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 24 deletions.
36 changes: 12 additions & 24 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3957,25 +3957,17 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
if (data.watchonly_wallet) {
LOCK(data.watchonly_wallet->cs_wallet);
if (data.watchonly_wallet->IsMine(addr_pair.first)) {
// Add to the watchonly. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
// Add to the watchonly. Copy the entire address book entry
data.watchonly_wallet->m_address_book[addr_pair.first] = addr_pair.second;
dests_to_delete.push_back(addr_pair.first);
continue;
}
}
if (data.solvable_wallet) {
LOCK(data.solvable_wallet->cs_wallet);
if (data.solvable_wallet->IsMine(addr_pair.first)) {
// Add to the solvable. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
// Add to the solvable. Copy the entire address book entry
data.solvable_wallet->m_address_book[addr_pair.first] = addr_pair.second;
dests_to_delete.push_back(addr_pair.first);
continue;
}
Expand All @@ -3995,21 +3987,13 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
// Labels for everything else ("send") should be cloned to all
if (data.watchonly_wallet) {
LOCK(data.watchonly_wallet->cs_wallet);
// Add to the watchonly. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
// Add to the watchonly. Copy the entire address book entry
data.watchonly_wallet->m_address_book[addr_pair.first] = addr_pair.second;
}
if (data.solvable_wallet) {
LOCK(data.solvable_wallet->cs_wallet);
// Add to the solvable. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
// Add to the solvable. Copy the entire address book entry
data.solvable_wallet->m_address_book[addr_pair.first] = addr_pair.second;
}
}
}
Expand All @@ -4024,6 +4008,10 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
// don't bother writing default values (unknown purpose)
if (addr_book_data.purpose) batch.WritePurpose(address, PurposeToString(*addr_book_data.purpose));
if (label) batch.WriteName(address, *label);
for (const auto& [id, request] : addr_book_data.receive_requests) {
batch.WriteAddressReceiveRequest(destination, id, request);
}
if (addr_book_data.previously_spent) batch.WriteAddressPreviouslySpent(destination, true);
}
};
if (data.watchonly_wallet) persist_address_book(*data.watchonly_wallet);
Expand Down
58 changes: 58 additions & 0 deletions test/functional/wallet_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,63 @@ def test_hybrid_pubkey(self):

wallet.unloadwallet()

def test_avoidreuse(self):
self.log.info("Test that avoidreuse persists after migration")
def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)

wallet = self.create_legacy_wallet("avoidreuse")
wallet.setwalletflag("avoid_reuse", True)

# Import a pubkey to the test wallet and send some funds to it
reused_imported_addr = def_wallet.getnewaddress()
wallet.importpubkey(def_wallet.getaddressinfo(reused_imported_addr)["pubkey"])
txid = def_wallet.sendtoaddress(reused_imported_addr, 2)
vout = find_vout_for_address(def_wallet, txid, reused_imported_addr)
imported_utxo = {"txid": txid, "vout": vout}
def_wallet.lockunspent(False, [imported_utxo])

# Send funds to the test wallet
reused_addr = wallet.getnewaddress()
def_wallet.sendtoaddress(reused_addr, 2)

self.generate(self.nodes[0], 1)

# Send funds from the test wallet with both its own and the imported
wallet.sendall([def_wallet.getnewaddress()])
def_wallet.sendall(recipients=[def_wallet.getnewaddress()], inputs=[imported_utxo])
self.generate(self.nodes[0], 1)
balances = wallet.getbalances()
assert_equal(balances["mine"]["trusted"], 0)
assert_equal(balances["watchonly"]["trusted"], 0)

# Reuse the addresses
def_wallet.sendtoaddress(reused_addr, 1)
def_wallet.sendtoaddress(reused_imported_addr, 1)
self.generate(self.nodes[0], 1)
balances = wallet.getbalances()
assert_equal(balances["mine"]["used"], 1)
# Reused watchonly will not show up in balances
assert_equal(balances["watchonly"]["trusted"], 0)
assert_equal(balances["watchonly"]["untrusted_pending"], 0)
assert_equal(balances["watchonly"]["immature"], 0)

utxos = wallet.listunspent()
assert_equal(len(utxos), 2)
for utxo in utxos:
assert_equal(utxo["reused"], True)

# Migrate
migrate_res = wallet.migratewallet()
watchonly_wallet = self.nodes[0].get_wallet_rpc(migrate_res["watchonly_name"])

# One utxo in each wallet, marked used
utxos = wallet.listunspent()
assert_equal(len(utxos), 1)
assert_equal(utxos[0]["reused"], True)
watchonly_utxos = watchonly_wallet.listunspent()
assert_equal(len(watchonly_utxos), 1)
assert_equal(watchonly_utxos[0]["reused"], True)

def run_test(self):
self.generate(self.nodes[0], 101)

Expand All @@ -845,6 +902,7 @@ def run_test(self):
self.test_migrate_raw_p2sh()
self.test_conflict_txs()
self.test_hybrid_pubkey()
self.test_avoidreuse()

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

0 comments on commit 4fcd3ef

Please sign in to comment.