Skip to content

Commit

Permalink
test: Get rid of default wallet hacks
Browse files Browse the repository at this point in the history
- Get rid of hardcoded wallet "" names and -wallet="" args
- Get rid of setup_nodes (-wallet, -nowallet, -disablewallet) argument rewriting

Motivation:

- Simplify test framework behavior so it's easier to write new tests without
  having arguments mangled by the framework
- Make tests more readable, replacing unexplained "" string literals with
  default_wallet_name references
- Make it trivial to update default wallet name and wallet data filename for
  sqlite #19077 testing
- Stop relying on -wallet arguments to create wallets, so it is easy to change
  -wallet option in the future to only load existing wallets not create new
  ones (to avoid accidental wallet creation, and encourage use of wallet
  encryption and descriptor features)
  • Loading branch information
ryanofsky committed Sep 29, 2020
1 parent ed3acda commit c1585bc
Show file tree
Hide file tree
Showing 17 changed files with 57 additions and 57 deletions.
4 changes: 3 additions & 1 deletion test/functional/feature_backwards_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ def set_test_params(self):
self.num_nodes = 6
# Add new version after each release:
self.extra_args = [
["-addresstype=bech32", "-wallet="], # Pre-release: use to mine blocks
["-addresstype=bech32"], # Pre-release: use to mine blocks
["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # Pre-release: use to receive coins, swap wallets, etc
["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.19.1
["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.18.1
["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.17.2
["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-wallet=wallet.dat"], # v0.16.3
]
self.wallet_names = [self.default_wallet_name]

def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
Expand All @@ -59,6 +60,7 @@ def setup_nodes(self):
])

self.start_nodes()
self.import_deterministic_coinbase_privkeys()

def run_test(self):
self.nodes[0].generatetoaddress(101, self.nodes[0].getnewaddress())
Expand Down
1 change: 1 addition & 0 deletions test/functional/feature_config_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.supports_cli = False
self.wallet_names = []

def test_config_file_parser(self):
# Assume node is stopped
Expand Down
4 changes: 2 additions & 2 deletions test/functional/feature_dbcrash.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def set_test_params(self):
# Set -maxmempool=0 to turn off mempool memory sharing with dbcache
# Set -rpcservertimeout=900 to reduce socket disconnects in this
# long-running test
self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900", "-dbbatchsize=200000", "-wallet="]
self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900", "-dbbatchsize=200000"]

# Set different crash ratios and cache sizes. Note that not all of
# -dbcache goes to the in-memory coins cache.
Expand All @@ -66,7 +66,7 @@ def set_test_params(self):

# Node3 is a normal node with default args, except will mine full blocks
# and non-standard txs (e.g. txs with "dust" outputs)
self.node3_args = ["-blockmaxweight=4000000", "-acceptnonstdtxn", "-wallet="]
self.node3_args = ["-blockmaxweight=4000000", "-acceptnonstdtxn"]
self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]

def skip_test_if_missing_module(self):
Expand Down
6 changes: 3 additions & 3 deletions test/functional/feature_fee_estimation.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ def set_test_params(self):
# mine non-standard txs (e.g. txs with "dust" outputs)
# Force fSendTrickle to true (via whitelist.noban)
self.extra_args = [
["-acceptnonstdtxn", "[email protected]", "-wallet="],
["-acceptnonstdtxn", "[email protected]", "-blockmaxweight=68000", "-wallet="],
["-acceptnonstdtxn", "[email protected]", "-blockmaxweight=32000", "-wallet="],
["-acceptnonstdtxn", "[email protected]"],
["-acceptnonstdtxn", "[email protected]", "-blockmaxweight=68000"],
["-acceptnonstdtxn", "[email protected]", "-blockmaxweight=32000"],
]

def skip_test_if_missing_module(self):
Expand Down
3 changes: 2 additions & 1 deletion test/functional/feature_filelock.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def set_test_params(self):

def setup_network(self):
self.add_nodes(self.num_nodes, extra_args=None)
self.nodes[0].start(['-wallet='])
self.nodes[0].start()
self.nodes[0].wait_for_rpc_connection()

def run_test(self):
Expand All @@ -27,6 +27,7 @@ def run_test(self):
self.nodes[1].assert_start_raises_init_error(extra_args=['-datadir={}'.format(self.nodes[0].datadir), '-noserver'], expected_msg=expected_msg)

if self.is_wallet_compiled():
self.nodes[0].createwallet(self.default_wallet_name)
wallet_dir = os.path.join(datadir, 'wallets')
self.log.info("Check that we can't start a second bitcoind instance using the same wallet")
expected_msg = "Error: Error initializing wallet database environment"
Expand Down
2 changes: 1 addition & 1 deletion test/functional/feature_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ def setup_network(self):
"-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s'))],
["-blockversion=211",
"-rescan",
"-wallet={}".format(self.wallet),
"-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s')))]]
self.wallet_names = [self.default_wallet_name, self.wallet]
super().setup_network()

def run_test(self):
Expand Down
13 changes: 6 additions & 7 deletions test/functional/feature_pruning.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,16 @@ def set_test_params(self):

# Create nodes 0 and 1 to mine.
# Create node 2 to test pruning.
self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-wallet="]
self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5"]
# Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
# Create nodes 5 to test wallet in prune mode, but do not connect
self.extra_args = [
self.full_node_default_args,
self.full_node_default_args,
["-wallet=", "-maxreceivebuffer=20000", "-prune=550"],
["-wallet=", "-maxreceivebuffer=20000"],
["-wallet=", "-maxreceivebuffer=20000"],
["-wallet=", "-prune=550"],
["-maxreceivebuffer=20000", "-prune=550"],
["-maxreceivebuffer=20000"],
["-maxreceivebuffer=20000"],
["-prune=550"],
]
self.rpc_timeout = 120

Expand All @@ -112,8 +112,7 @@ def setup_network(self):
def setup_nodes(self):
self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
for n in self.nodes:
n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase', rescan=False)
self.import_deterministic_coinbase_privkeys()

def create_big_chain(self):
# Start by creating some coinbases we can spend later
Expand Down
1 change: 1 addition & 0 deletions test/functional/feature_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class SettingsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.wallet_names = []

def run_test(self):
node, = self.nodes
Expand Down
3 changes: 2 additions & 1 deletion test/functional/mempool_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
class MempoolCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.wallet_names = [None, self.default_wallet_name]

def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
Expand All @@ -31,7 +32,7 @@ def setup_network(self):
150200, # oldest version supported by the test framework
None,
])
self.start_nodes([[], ["-wallet="]])
self.start_nodes()
self.import_deterministic_coinbase_privkeys()

def run_test(self):
Expand Down
1 change: 1 addition & 0 deletions test/functional/rpc_getdescriptorinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class DescriptorTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [["-disablewallet"]]
self.wallet_names = []

def test_desc(self, desc, isrange, issolvable, hasprivatekeys):
info = self.nodes[0].getdescriptorinfo(desc)
Expand Down
35 changes: 14 additions & 21 deletions test/functional/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,16 @@ def __init__(self):
self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond
self.supports_cli = True
self.bind_to_localhost_only = True
self.parse_args()
self.default_wallet_name = ""
self.wallet_data_filename = "wallet.dat"
# Optional list of wallet names that can be set in set_test_params to
# create and import keys to. If unset, default is len(nodes) *
# [default_wallet_name]. If wallet names are None, wallet creation is
# skipped. If list is truncated, wallet creation is skipped and keys
# are not imported.
self.wallet_names = None
self.set_test_params()
self.parse_args()
if self.options.timeout_factor == 0 :
self.options.timeout_factor = 99999
self.rpc_timeout = int(self.rpc_timeout * self.options.timeout_factor) # optionally, increase timeout by a factor
Expand Down Expand Up @@ -364,23 +370,12 @@ def setup_network(self):
def setup_nodes(self):
"""Override this method to customize test node setup"""
extra_args = [[]] * self.num_nodes
wallets = [[]] * self.num_nodes
if hasattr(self, "extra_args"):
extra_args = self.extra_args
wallets = [[x for x in eargs if x.startswith('-wallet=')] for eargs in extra_args]
extra_args = [x + ['-nowallet'] for x in extra_args]
self.add_nodes(self.num_nodes, extra_args)
self.start_nodes()
for i, n in enumerate(self.nodes):
n.extra_args.pop()
if '-wallet=0' in n.extra_args or '-nowallet' in n.extra_args or '-disablewallet' in n.extra_args or not self.is_wallet_compiled():
continue
if '-wallet=' not in wallets[i] and not any([x.startswith('-wallet=') for x in wallets[i]]):
wallets[i].append('-wallet=')
for w in wallets[i]:
wallet_name = w.split('=', 1)[1]
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors)
self.import_deterministic_coinbase_privkeys()
if self.is_wallet_compiled():
self.import_deterministic_coinbase_privkeys()
if not self.setup_clean_chain:
for n in self.nodes:
assert_equal(n.getblockchaininfo()["blocks"], 199)
Expand All @@ -396,13 +391,11 @@ def setup_nodes(self):
assert_equal(chain_info["initialblockdownload"], False)

def import_deterministic_coinbase_privkeys(self):
for n in self.nodes:
try:
n.getwalletinfo()
except JSONRPCException as e:
assert str(e).startswith('Method not found')
continue

wallet_names = [self.default_wallet_name] * len(self.nodes) if self.wallet_names is None else self.wallet_names
assert len(wallet_names) <= len(self.nodes)
for wallet_name, n in zip(wallet_names, self.nodes):
if wallet_name is not None:
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors, load_on_startup=True)
n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')

def run_test(self):
Expand Down
8 changes: 4 additions & 4 deletions test/functional/tool_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def test_invalid_tool_commands_and_args(self):
locked_dir = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets")
self.assert_raises_tool_error(
'Error initializing wallet database environment "{}"!'.format(locked_dir),
'-wallet=wallet.dat',
'-wallet=' + self.default_wallet_name,
'info',
)
path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "nonexistent.dat")
Expand Down Expand Up @@ -104,7 +104,7 @@ def test_tool_wallet_info(self):
Transactions: 0
Address Book: 3
''')
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
timestamp_after = self.wallet_timestamp()
self.log.debug('Wallet file timestamp after calling info: {}'.format(timestamp_after))
self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
Expand Down Expand Up @@ -143,7 +143,7 @@ def test_tool_wallet_info_after_transaction(self):
Transactions: 1
Address Book: 3
''')
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
shasum_after = self.wallet_shasum()
timestamp_after = self.wallet_timestamp()
self.log.debug('Wallet file timestamp after calling info: {}'.format(timestamp_after))
Expand Down Expand Up @@ -181,7 +181,7 @@ def test_tool_wallet_create_on_existing_wallet(self):

def test_getwalletinfo_on_different_wallet(self):
self.log.info('Starting node with arg -wallet=foo')
self.start_node(0, ['-wallet=foo'])
self.start_node(0, ['-nowallet', '-wallet=foo'])

self.log.info('Calling getwalletinfo on a different wallet ("foo"), testing output')
shasum_before = self.wallet_shasum()
Expand Down
8 changes: 4 additions & 4 deletions test/functional/wallet_backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ def set_test_params(self):
# nodes 1, 2,3 are spenders, let's give them a keypool=100
# whitelist all peers to speed up tx relay / mempool sync
self.extra_args = [
["[email protected]", "-keypool=100", "-wallet="],
["[email protected]", "-keypool=100", "-wallet="],
["[email protected]", "-keypool=100", "-wallet="],
["[email protected]", "-wallet="],
["[email protected]", "-keypool=100"],
["[email protected]", "-keypool=100"],
["[email protected]", "-keypool=100"],
["[email protected]"],
]
self.rpc_timeout = 120

Expand Down
1 change: 1 addition & 0 deletions test/functional/wallet_disable.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-disablewallet"]]
self.wallet_names = []

def run_test (self):
# Make sure wallet is really disabled
Expand Down
7 changes: 3 additions & 4 deletions test/functional/wallet_import_rescan.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,16 @@ def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

def setup_network(self):
self.extra_args = [["-wallet="] for _ in range(self.num_nodes)]
self.extra_args = [[] for _ in range(self.num_nodes)]
for i, import_node in enumerate(IMPORT_NODES, 2):
if import_node.prune:
self.extra_args[i] += ["-prune=1"]

self.add_nodes(self.num_nodes, extra_args=self.extra_args)

# Import keys with pruning disabled
self.start_nodes(extra_args=[["-wallet="]] * self.num_nodes)
for n in self.nodes:
n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')
self.start_nodes(extra_args=[[]] * self.num_nodes)
self.import_deterministic_coinbase_privkeys()
self.stop_nodes()

self.start_nodes()
Expand Down
13 changes: 6 additions & 7 deletions test/functional/wallet_multiwallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
self.rpc_timeout = 120
self.extra_args = [["-wallet="], ["-wallet="]]

def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
Expand Down Expand Up @@ -81,7 +80,7 @@ def wallet_file(name):
os.rename(wallet_dir(self.default_wallet_name, self.wallet_data_filename), wallet_dir("w8"))

# create another dummy wallet for use in testing backups later
self.start_node(0, ["-wallet=" + self.default_wallet_name])
self.start_node(0, ["-nowallet", "-wallet=" + self.default_wallet_name])
self.stop_nodes()
empty_wallet = os.path.join(self.options.tmpdir, 'empty.dat')
os.rename(wallet_dir(self.default_wallet_name, self.wallet_data_filename), empty_wallet)
Expand All @@ -95,7 +94,7 @@ def wallet_file(name):
# w8 - to verify existing wallet file is loaded correctly
# '' - to verify default wallet file is created correctly
wallet_names = ['w1', 'w2', 'w3', 'w', 'sub/w5', os.path.join(self.options.tmpdir, 'extern/w6'), 'w7_symlink', 'w8', self.default_wallet_name]
extra_args = ['-wallet={}'.format(n) for n in wallet_names]
extra_args = ['-nowallet'] + ['-wallet={}'.format(n) for n in wallet_names]
self.start_node(0, extra_args)
assert_equal(sorted(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), [self.default_wallet_name, os.path.join('sub', 'w5'), 'w', 'w1', 'w2', 'w3', 'w7', 'w7_symlink', 'w8'])

Expand All @@ -108,7 +107,7 @@ def wallet_file(name):

# should not initialize if wallet path can't be created
exp_stderr = "boost::filesystem::create_directory:"
self.nodes[0].assert_start_raises_init_error(['-wallet=wallet.dat/bad'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)
self.nodes[0].assert_start_raises_init_error(['-wallet=w8/bad'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)

self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist')
self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" is a relative path', cwd=data_dir())
Expand Down Expand Up @@ -136,22 +135,22 @@ def wallet_file(name):
# if wallets/ doesn't exist, datadir should be the default wallet dir
wallet_dir2 = data_dir('walletdir')
os.rename(wallet_dir(), wallet_dir2)
self.start_node(0, ['-wallet=w4', '-wallet=w5'])
self.start_node(0, ['-nowallet', '-wallet=w4', '-wallet=w5'])
assert_equal(set(node.listwallets()), {"w4", "w5"})
w5 = wallet("w5")
node.generatetoaddress(nblocks=1, address=w5.getnewaddress())

# now if wallets/ exists again, but the rootdir is specified as the walletdir, w4 and w5 should still be loaded
os.rename(wallet_dir2, wallet_dir())
self.restart_node(0, ['-wallet=w4', '-wallet=w5', '-walletdir=' + data_dir()])
self.restart_node(0, ['-nowallet', '-wallet=w4', '-wallet=w5', '-walletdir=' + data_dir()])
assert_equal(set(node.listwallets()), {"w4", "w5"})
w5 = wallet("w5")
w5_info = w5.getwalletinfo()
assert_equal(w5_info['immature_balance'], 50)

competing_wallet_dir = os.path.join(self.options.tmpdir, 'competing_walletdir')
os.mkdir(competing_wallet_dir)
self.restart_node(0, ['-walletdir=' + competing_wallet_dir, '-wallet='])
self.restart_node(0, ['-walletdir=' + competing_wallet_dir])
exp_stderr = r"Error: Error initializing wallet database environment \"\S+competing_walletdir\"!"
self.nodes[1].assert_start_raises_init_error(['-walletdir=' + competing_wallet_dir], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)

Expand Down
4 changes: 3 additions & 1 deletion test/functional/wallet_upgradewallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
self.extra_args = [
["-addresstype=bech32", "-wallet="], # current wallet version
["-addresstype=bech32"], # current wallet version
["-usehd=1"], # v0.16.3 wallet
["-usehd=0"] # v0.15.2 wallet
]
self.wallet_names = [self.default_wallet_name, None, None]

def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
Expand All @@ -46,6 +47,7 @@ def setup_nodes(self):
150200,
])
self.start_nodes()
self.import_deterministic_coinbase_privkeys()

def dumb_sync_blocks(self):
"""
Expand Down

0 comments on commit c1585bc

Please sign in to comment.