Repository: bitcoin/bitcoin
File: test/functional/wallet_backwards_compatibility.py (Python)

Code before:
            self.log.warning("sqlite3 module not available, skipping lack of keymeta records check")

    def run_test(self):
        node_miner = self.nodes[0]
        node_master = self.nodes[1]
        node_v21 = self.nodes[self.num_nodes - 2]
        node_v20 = self.nodes[self.num_nodes - 1] # bdb only

        legacy_nodes = self.nodes[2:] # Nodes that support legacy wallets
        descriptors_nodes = self.nodes[2:-1] # Nodes that support descriptor wallets

        self.generatetoaddress(node_miner, COINBASE_MATURITY + 1, node_miner.getnewaddress())

        # Sanity check the test framework:
        assert_equal(node_v20.getblockchaininfo()["blocks"], COINBASE_MATURITY + 1)

        self.log.info("Test wallet backwards compatibility...")
        # Create a number of wallets and open them in older versions:

        # w1: regular wallet, created on master: update this test when default
        #     wallets can no longer be opened by older versions.
        node_master.createwallet(wallet_name="w1")
        wallet = node_master.get_wallet_rpc("w1")
        info = wallet.getwalletinfo()
        assert info['private_keys_enabled']
        assert info['keypoolsize'] > 0
        # Create a confirmed transaction, receiving coins
        address = wallet.getnewaddress()
        node_miner.sendtoaddress(address, 10)
        self.sync_mempools()
        self.generate(node_miner, 1)
        # Create a conflicting transaction using RBF
        return_address = node_miner.getnewaddress()
        tx1_id = node_master.sendtoaddress(return_address, 1)
        tx2_id = node_master.bumpfee(tx1_id)["txid"]
        # Confirm the transaction
        self.sync_mempools()
        self.generate(node_miner, 1)
        # Create another conflicting transaction using RBF
        tx3_id = node_master.sendtoaddress(return_address, 1)
        tx4_id = node_master.bumpfee(tx3_id)["txid"]
        self.sync_mempools()
        # Abandon transaction, but don't confirm
        node_master.abandontransaction(tx3_id)

        # w2: wallet with private keys disabled, created on master: update this
        #     test when default wallets private keys disabled can no longer be
        #     opened by older versions.
        node_master.createwallet(wallet_name="w2", disable_private_keys=True)
        wallet = node_master.get_wallet_rpc("w2")
        info = wallet.getwalletinfo()

Review comment (bug):
I think something like this (or within a function called `assert_restart_raises_init_warning`):
```suggestion
        # Restart latest node and verify that the legacy wallet load is skipped with a warning during init.
        with node_master.assert_debug_log([f"Failed to open database path '{wallet_path}'. The wallet appears to be a Legacy wallet, please use the wallet migration tool (migratewallet RPC or the GUI option)."]):
            self.restart_node(node_master.index, extra_args=[])
```

Code after:
        except ImportError:
            self.log.warning("sqlite3 module not available, skipping lack of keymeta records check")

    def test_ignore_legacy_during_startup(self, legacy_nodes, node_master):
        self.log.info("Test that legacy wallets are ignored during startup on v29+")

        legacy_node = legacy_nodes[0]
        wallet_name = f"legacy_up_{legacy_node.version}"
        legacy_node.loadwallet(wallet_name)
        legacy_wallet = legacy_node.get_wallet_rpc(wallet_name)

        # Move legacy wallet to latest node
        wallet_path = node_master.wallets_path / wallet_name
        wallet_path.mkdir()
        legacy_wallet.backupwallet(wallet_path / "wallet.dat")
        legacy_wallet.unloadwallet()

        # Write wallet so it is automatically loaded during init
        settings_path = node_master.chain_path / "settings.json"
        with settings_path.open("w") as fp:
            json.dump({"wallet": [wallet_name]}, fp)

        # Restart latest node and verify that the legacy wallet load is skipped without exiting early during init.
        self.restart_node(node_master.index, extra_args=[])
        # Ensure we receive the warning message and clear the stderr pipe.
        node_master.stderr.seek(0)
        warning_msg = node_master.stderr.read().decode('utf-8').strip()
        assert "The wallet appears to be a Legacy wallet, please use the wallet migration tool (migratewallet RPC or the GUI option)" in warning_msg
        node_master.stderr.truncate(0), node_master.stderr.seek(0) # reset buffer

        # Verify the node is still running (no shutdown occurred during startup)
        node_master.getblockcount()
        # Reset settings for any subsequent test
        os.remove(settings_path)

    def run_test(self):
        node_miner = self.nodes[0]
        node_master = self.nodes[1]
        node_v21 = self.nodes[self.num_nodes - 2]
        node_v20 = self.nodes[self.num_nodes - 1] # bdb only

        legacy_nodes = self.nodes[2:] # Nodes that support legacy wallets
        descriptors_nodes = self.nodes[2:-1] # Nodes that support descriptor wallets

        self.generatetoaddress(node_miner, COINBASE_MATURITY + 1, node_miner.getnewaddress())

        # Sanity check the test framework:
        assert_equal(node_v20.getblockchaininfo()["blocks"], COINBASE_MATURITY + 1)

        self.log.info("Test wallet backwards compatibility...")
        # Create a number of wallets and open them in older versions: