dash/test/functional/feature_backwards_compatibility.py
MarcoFalke 65226da849
Merge bitcoin/bitcoin#22229: test: consolidate to f-strings (part 1)
68faa87881f5334b2528db4adc72ec19d94316a3 test: use f-strings in mining_*.py tests (fanquake)
c2a5d560df2824df5731100c2584e8ad7a3d7bc2 test: use f-strings in interface_*.py tests (fanquake)
86d958262dff43002820d58ccb8958e2dbfb9d5b test: use f-strings in feature_proxy.py (fanquake)
31bdb33dcb8345df1bb94b28e811252a918d7dcb test: use f-strings in feature_segwit.py (fanquake)
b166d54c3cbb0c028210cee977b3dcde5ac5474f test: use f-strings in feature_versionbits_warning.py (fanquake)
cf6d66bf941d946600047d712c7cd15d7605322e test: use f-strings in feature_settings.py (fanquake)
6651d77f22862716f5bd7d0b31cfbd3937ab7b1d test: use f-strings in feature_pruning.py (fanquake)
961f5813ba65b6a601081912c4ece96c2679794d test: use f-strings in feature_notifications.py (fanquake)
1a546e6f6ca95772f0d7dbc2792477becbb8ea63 test: use f-strings in feature_minchainwork.py (fanquake)
6679eceacc915a8ea7cd7063f103ffc5eb9da884 test: use f-strings in feature_logging.py (fanquake)
fb633933ab570e945d2a366f37eeff39f516c613 test: use f-strings in feature_loadblock.py (fanquake)
e9ca8b254d4b9567831c0e113ce1c0a2b4795a95 test: use f-strings in feature_help.py (fanquake)
ff7e3309995a8960ac371741b2b00c6da40f7490 test: use f-strings in feature_filelock.py (fanquake)
d5a6adc5e478fa5c6e562377eea873dc38e66578 test: use f-strings in feature_fee_estimation.py (fanquake)
a2de33cbdc79202bccddb4beadfde88266ac979f test: use f-strings in feature_dersig.py (fanquake)
a2502cc63fd308be8af840962da9c53339433fa6 test: use f-strings in feature_dbcrash.py (fanquake)
3e2f84e7a96cb4b97b609ac853f78edd0ed43f82 test: use f-strings in feature_csv_activation.py (fanquake)
e2f1fd8ee92fa421b6d293169044d6ddd5a9b8df test: use f-strings in feature_config_args.py (fanquake)
36d33d32b1b498b61f56d552f6e2c1d064f978c3 test: use f-strings in feature_cltv.py (fanquake)
dca173cc044270b30782b1e3355e9dcb8c534295 test: use f-strings in feature_blocksdir.py (fanquake)
5453e8706278918ac51a725e81599cfa18c8cdbc test: use f-strings in feature_backwards_compatibility.py (fanquake)
6f3d5ad67ac8e7b50abae1a2949898d858e38106 test: use f-strings in feature_asmap.py (fanquake)

Pull request description:

  Rather than using 3 different ways to build/format strings (sometimes all in the same test, i.e [`feature_config_args.py`](https://github.com/bitcoin/bitcoin/blob/master/test/functional/feature_config_args.py)), consolidate to using [f-strings (3.6+)](https://docs.python.org/3/reference/lexical_analysis.html#f-strings), which are generally more concise / readable, as well as more performant than existing methods.

  This deals with the `feature_*.py`, `interface_*.py` and `mining_*.py` tests.

  See also: [PEP 498](https://www.python.org/dev/peps/pep-0498/)

ACKs for top commit:
  mjdietzx:
    reACK 68faa87881f5334b2528db4adc72ec19d94316a3
  Zero-1729:
    crACK 68faa87881f5334b2528db4adc72ec19d94316a3

Tree-SHA512: d4e1a42e07d96d2c552387a46da1534223c4ce408703d7568ad2ef580797dd68d9695b8d19666b567af37f44de6e430e8be5db5d5404ba8fcecf9f5b026a6efb
2024-10-25 21:24:00 +07:00

403 lines
17 KiB
Python
Executable File

#!/usr/bin/env python3
# Copyright (c) 2018-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Backwards compatibility functional test
Test various backwards compatibility scenarios. Requires previous releases binaries,
see test/README.md.
v0.15.0.0 is not required by this test, but it is used in wallet_upgradewallet.py.
Due to a hardfork in regtest, it can't be used to sync nodes.
Due to RPC changes introduced in various versions the below tests
won't work for older versions without some patches or workarounds.
Use only the latest patch version of each release, unless a test specifically
needs an older patch version.
"""
import os
import shutil
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
class BackwardsCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 7
# Add new version after each release:
self.extra_args = [
[], # Pre-release: use to mine blocks
["-nowallet"], # Pre-release: use to receive coins, swap wallets, etc
["-nowallet"], # v20.0.1
["-nowallet"], # v19.3.0
["-nowallet"], # v18.2.2
["-nowallet"], # v0.17.0.3
["-nowallet"], # v0.16.1.1
]
self.wallet_names = [self.default_wallet_name]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
self.skip_if_no_previous_releases()
def setup_nodes(self):
self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
None,
None,
19030000,
19030000,
18020200,
170003,
160101,
])
self.start_nodes()
self.import_deterministic_coinbase_privkeys()
def run_test(self):
self.generatetoaddress(self.nodes[0], 101, self.nodes[0].getnewaddress())
self.sync_blocks()
# Sanity check the test framework:
res = self.nodes[self.num_nodes - 1].getblockchaininfo()
assert_equal(res['blocks'], 101)
node_master = self.nodes[self.num_nodes - 6]
node_v20 = self.nodes[self.num_nodes - 5]
node_v19 = self.nodes[self.num_nodes - 4]
node_v18 = self.nodes[self.num_nodes - 3]
node_v17 = self.nodes[self.num_nodes - 2]
node_v16 = self.nodes[self.num_nodes - 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()
self.nodes[0].sendtoaddress(address, 1)
self.sync_mempools()
self.generate(self.nodes[0], 1)
self.sync_blocks()
# w1_v19: regular wallet, created with v0.19
node_v19.rpc.createwallet(wallet_name="w1_v19")
wallet = node_v19.get_wallet_rpc("w1_v19")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
# Use addmultisigaddress (see #18075)
address_18075 = wallet.addmultisigaddress(1, ["0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52", "037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073"], "")["address"]
assert wallet.getaddressinfo(address_18075)["solvable"]
# w1_v18: regular wallet, created with v0.18
node_v18.rpc.createwallet(wallet_name="w1_v18")
wallet = node_v18.get_wallet_rpc("w1_v18")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
# 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()
assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
# w1_v20: regular wallet, created with v20.0
node_v20.rpc.createwallet(wallet_name="w1_v20")
wallet = node_v20.get_wallet_rpc("w1_v20")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
# w2_v19: wallet with private keys disabled, created with v0.19
node_v19.rpc.createwallet(wallet_name="w2_v19", disable_private_keys=True)
wallet = node_v19.get_wallet_rpc("w2_v19")
info = wallet.getwalletinfo()
assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
# w2_v18: wallet with private keys disabled, created with v0.18
node_v18.rpc.createwallet(wallet_name="w2_v18", disable_private_keys=True)
wallet = node_v18.get_wallet_rpc("w2_v18")
info = wallet.getwalletinfo()
assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
# w3: blank wallet, created on master: update this
# test when default blank wallets can no longer be opened by older versions.
node_master.createwallet(wallet_name="w3", blank=True)
wallet = node_master.get_wallet_rpc("w3")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] == 0
# w3_v19: blank wallet, created with v0.19
node_v19.rpc.createwallet(wallet_name="w3_v19", blank=True)
wallet = node_v19.get_wallet_rpc("w3_v19")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] == 0
# w3_v18: blank wallet, created with v0.18
node_v18.rpc.createwallet(wallet_name="w3_v18", blank=True)
wallet = node_v18.get_wallet_rpc("w3_v18")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] == 0
# Copy the wallets to older nodes:
node_master_wallets_dir = os.path.join(node_master.datadir, "regtest/wallets")
node_v20_wallets_dir = os.path.join(node_v20.datadir, "regtest/wallets")
node_v19_wallets_dir = os.path.join(node_v19.datadir, "regtest/wallets")
node_v18_wallets_dir = os.path.join(node_v18.datadir, "regtest/wallets")
node_v17_wallets_dir = os.path.join(node_v17.datadir, "regtest/wallets")
node_v16_wallets_dir = os.path.join(node_v16.datadir, "regtest")
node_master.unloadwallet("w1")
node_master.unloadwallet("w2")
node_v19.unloadwallet("w1_v19")
node_v19.unloadwallet("w2_v19")
node_v18.unloadwallet("w1_v18")
node_v18.unloadwallet("w2_v18")
# Copy wallets to v0.16
for wallet in os.listdir(node_master_wallets_dir):
shutil.copytree(
os.path.join(node_master_wallets_dir, wallet),
os.path.join(node_v16_wallets_dir, wallet)
)
# Copy wallets to v0.17
for wallet in os.listdir(node_master_wallets_dir):
shutil.copytree(
os.path.join(node_master_wallets_dir, wallet),
os.path.join(node_v17_wallets_dir, wallet)
)
for wallet in os.listdir(node_v18_wallets_dir):
shutil.copytree(
os.path.join(node_v18_wallets_dir, wallet),
os.path.join(node_v17_wallets_dir, wallet)
)
# Copy wallets to v0.18
for wallet in os.listdir(node_master_wallets_dir):
shutil.copytree(
os.path.join(node_master_wallets_dir, wallet),
os.path.join(node_v18_wallets_dir, wallet)
)
# Copy wallets to v0.19
for wallet in os.listdir(node_master_wallets_dir):
shutil.copytree(
os.path.join(node_master_wallets_dir, wallet),
os.path.join(node_v19_wallets_dir, wallet)
)
# Copy wallets to v0.20
for wallet in os.listdir(node_master_wallets_dir):
shutil.copytree(
os.path.join(node_master_wallets_dir, wallet),
os.path.join(node_v20_wallets_dir, wallet)
)
if not self.options.descriptors:
# Descriptor wallets break compatibility, only run this test for legacy wallet
# Open the wallets in v0.20
node_v20.loadwallet("w1")
wallet = node_v20.get_wallet_rpc("w1")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
txs = wallet.listtransactions()
assert_equal(len(txs), 1)
node_v20.loadwallet("w2")
wallet = node_v20.get_wallet_rpc("w2")
info = wallet.getwalletinfo()
assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
node_v20.loadwallet("w3")
wallet = node_v20.get_wallet_rpc("w3")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] == 0
# Open the wallets in v0.19
node_v19.loadwallet("w1")
wallet = node_v19.get_wallet_rpc("w1")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
txs = wallet.listtransactions()
assert_equal(len(txs), 1)
node_v19.loadwallet("w2")
wallet = node_v19.get_wallet_rpc("w2")
info = wallet.getwalletinfo()
assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
node_v19.loadwallet("w3")
wallet = node_v19.get_wallet_rpc("w3")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] == 0
# Open the wallets in v0.18
node_v18.loadwallet("w1")
wallet = node_v18.get_wallet_rpc("w1")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
txs = wallet.listtransactions()
assert_equal(len(txs), 1)
node_v18.loadwallet("w2")
wallet = node_v18.get_wallet_rpc("w2")
info = wallet.getwalletinfo()
assert info['private_keys_enabled'] == False
assert info['keypoolsize'] == 0
node_v18.loadwallet("w3")
wallet = node_v18.get_wallet_rpc("w3")
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] == 0
node_v17.loadwallet("w1")
wallet = node_v17.get_wallet_rpc("w1")
info = wallet.getwalletinfo()
# doesn't have private_keys_enabled in v17
#assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
node_v17.loadwallet("w2")
wallet = node_v17.get_wallet_rpc("w2")
info = wallet.getwalletinfo()
# doesn't have private_keys_enabled in v17
# TODO enable back when HD wallets are created by default
# assert info['private_keys_enabled'] == False
# assert info['keypoolsize'] == 0
else:
# Descriptor wallets appear to be corrupted wallets to old software
assert_raises_rpc_error(-4, "Wallet requires newer version of Dash Core", node_v19.loadwallet, "w1")
assert_raises_rpc_error(-4, "Wallet requires newer version of Dash Core", node_v19.loadwallet, "w2")
assert_raises_rpc_error(-4, "Wallet requires newer version of Dash Core", node_v19.loadwallet, "w3")
assert_raises_rpc_error(-18, "Data is not in recognized format", node_v18.loadwallet, "w1")
assert_raises_rpc_error(-18, "Data is not in recognized format", node_v18.loadwallet, "w2")
assert_raises_rpc_error(-18, "Data is not in recognized format", node_v18.loadwallet, "w3")
# Open the wallets in v0.17
node_v17.loadwallet("w1_v18")
wallet = node_v17.get_wallet_rpc("w1_v18")
info = wallet.getwalletinfo()
# doesn't have private_keys_enabled in v17
# assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
node_v17.loadwallet("w2_v18")
wallet = node_v17.get_wallet_rpc("w2_v18")
info = wallet.getwalletinfo()
# doesn't have private_keys_enabled in v17
# TODO enable back when HD wallets are created by default
#assert info['private_keys_enabled'] == False
#assert info['keypoolsize'] == 0
# RPC loadwallet failure causes bitcoind to exit, in addition to the RPC
# call failure, so the following test won't work:
# assert_raises_rpc_error(-4, "Wallet loading failed.", node_v17.loadwallet, 'w3_v18')
# Instead, we stop node and try to launch it with the wallet:
self.stop_node(5)
# it expected to fail with error 'DBErrors::TOO_NEW' but Dash Core can open v18 by version 17
# can be implemented in future if there's any incompatible versions
#node_v17.assert_start_raises_init_error(["-wallet=w3_v18"], "Error: Error loading w3_v18: Wallet requires newer version of Dash Core")
#node_v17.assert_start_raises_init_error(["-wallet=w3"], "Error: Error loading w3: Wallet requires newer version of Dash Core")
self.start_node(5)
# Open most recent wallet in v0.16 (no loadwallet RPC)
self.restart_node(6, extra_args=["-wallet=w2"])
wallet = node_v16.get_wallet_rpc("w2")
info = wallet.getwalletinfo()
assert info['keypoolsize'] == 1
self.log.info("Test wallet upgrade path...")
# u1: regular wallet, created with v0.17
node_v17.rpc.createwallet(wallet_name="u1_v17")
wallet = node_v17.get_wallet_rpc("u1_v17")
address = wallet.getnewaddress()
v17_info = wallet.getaddressinfo(address)
# TODO enable back when HD wallets are created by default
#v17_hdkeypath = v17_info["hdkeypath"]
v17_pubkey = v17_info["pubkey"]
if self.is_bdb_compiled():
# Old wallets are BDB and will only work if BDB is compiled
# Copy the 0.16 wallet to the last Bitcoin Core version and open it:
node_v17.unloadwallet("u1_v17")
shutil.copytree(
os.path.join(node_v17_wallets_dir, "u1_v17"),
os.path.join(node_master_wallets_dir, "u1_v17")
)
node_master.loadwallet("u1_v17")
wallet = node_master.get_wallet_rpc("u1_v17")
info = wallet.getaddressinfo(address)
# TODO enable back when HD wallets are created by default
#descriptor = f"pkh([{info["hdmasterfingerprint"]}{hdkeypath[1:]}]{v17_pubkey})"
#assert_equal(info["desc"], descsum_create(descriptor))
assert_equal(info["pubkey"], v17_pubkey)
# Now copy that same wallet back to 0.17 to make sure no automatic upgrade breaks it
node_master.unloadwallet("u1_v17")
shutil.rmtree(os.path.join(node_v17_wallets_dir, "u1_v17"))
shutil.copytree(
os.path.join(node_master_wallets_dir, "u1_v17"),
os.path.join(node_v17_wallets_dir, "u1_v17")
)
node_v17.loadwallet("u1_v17")
wallet = node_v17.get_wallet_rpc("u1_v17")
info = wallet.getaddressinfo(address)
assert_equal(info, v17_info)
# Copy the 0.19 wallet to the last Bitcoin Core version and open it:
shutil.copytree(
os.path.join(node_v19_wallets_dir, "w1_v19"),
os.path.join(node_master_wallets_dir, "w1_v19")
)
node_master.loadwallet("w1_v19")
wallet = node_master.get_wallet_rpc("w1_v19")
assert wallet.getaddressinfo(address_18075)["solvable"]
# Now copy that same wallet back to 0.19 to make sure no automatic upgrade breaks it
node_master.unloadwallet("w1_v19")
shutil.rmtree(os.path.join(node_v19_wallets_dir, "w1_v19"))
shutil.copytree(
os.path.join(node_master_wallets_dir, "w1_v19"),
os.path.join(node_v19_wallets_dir, "w1_v19")
)
node_v19.loadwallet("w1_v19")
wallet = node_v19.get_wallet_rpc("w1_v19")
assert wallet.getaddressinfo(address_18075)["solvable"]
if __name__ == '__main__':
BackwardsCompatibilityTest().main()