tests: Check that the last hardened cache upgrade occurs

When loading an older wallet without the last hardened cache, an
automatic upgrade should be performed. Check this in
wallet_backwards_compatibility.py

When migrating a wallet, the migrated wallet should always have the last
hardened cache, so verify in wallet_migration.py
This commit is contained in:
Ava Chow committed 2025-07-31 10:29:32 -07:00
1 parent 00604296e1
commit 8a08eef645
3 files changed
+66 -14

No files matched your search

@@ -21,9 +21,11 @@ import shutil
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.descriptors import descsum_create
from test_framework.messages import ser_string
from test_framework.util import (
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
)
@@ -149,18 +151,13 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
assert_equal(bad_deriv_wallet_master.getaddressinfo(bad_path_addr)["hdkeypath"], good_deriv_path)
bad_deriv_wallet_master.unloadwallet()
# If we have sqlite3, verify that there are no keymeta records
try:
import sqlite3
wallet_db = node_master.wallets_path / wallet_name / "wallet.dat"
conn = sqlite3.connect(wallet_db)
with conn:
# Retrieve all records that have the "keymeta" prefix. The remaining key data varies for each record.
keymeta_rec = conn.execute("SELECT value FROM main where key >= x'076b65796d657461' AND key < x'076b65796d657462'").fetchone()
assert_equal(keymeta_rec, None)
conn.close()
except ImportError:
self.log.warning("sqlite3 module not available, skipping lack of keymeta records check")
def check_keymeta(conn):
# Retrieve all records that have the "keymeta" prefix. The remaining key data varies for each record.
keymeta_rec = conn.execute(f"SELECT value FROM main where key >= x'{ser_string(b'keymeta').hex()}' AND key < x'{ser_string(b'keymetb').hex()}'").fetchone()
assert_equal(keymeta_rec, None)
wallet_db = node_master.wallets_path / wallet_name / "wallet.dat"
self.inspect_sqlite_db(wallet_db, check_keymeta)
def test_ignore_legacy_during_startup(self, legacy_nodes, node_master):
self.log.info("Test that legacy wallets are ignored during startup on v29+")
@@ -342,6 +339,13 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
# Remove the wallet from old node
wallet_prev.unloadwallet()
# Open backup with sqlite and get flags
def get_flags(conn):
flags_rec = conn.execute(f"SELECT value FROM main WHERE key = x'{ser_string(b'flags').hex()}'").fetchone()
return int.from_bytes(flags_rec[0], byteorder="little")
old_flags = self.inspect_sqlite_db(backup_path, get_flags)
# Restore the wallet to master
load_res = node_master.restorewallet(wallet_name, backup_path)
@@ -378,6 +382,21 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
wallet.unloadwallet()
# Open the wallet with sqlite and inspect the flags and records
def check_upgraded_records(conn, old_flags):
flags_rec = conn.execute(f"SELECT value FROM main WHERE key = x'{ser_string(b'flags').hex()}'").fetchone()
new_flags = int.from_bytes(flags_rec[0], byteorder="little")
diff_flags = new_flags & ~old_flags
# Check for last hardened xpubs if the flag is newly set
if diff_flags & (1 << 2):
self.log.debug("Checking descriptor cache was upgraded")
# Fetch all records with the walletdescriptorlhcache prefix
lh_cache_recs = conn.execute(f"SELECT value FROM main where key >= x'{ser_string(b'walletdescriptorlhcache').hex()}' AND key < x'{ser_string(b'walletdescriptorlhcachf').hex()}'").fetchall()
assert_greater_than(len(lh_cache_recs), 0)
self.inspect_sqlite_db(down_backup_path, check_upgraded_records, old_flags)
# Check that no automatic upgrade broke downgrading the wallet
target_dir = node.wallets_path / down_wallet_name
os.makedirs(target_dir, exist_ok=True)