Skip to content

Commit 0e4b695

Browse files
committed
test: backwards compatibility: misc fixes
This cleanup may slightly impact test coverage. Reduce code repition by looping over the list of nodes. Reduce brittleness by refering to nodes by name rather than index. Add helper method nodes_wallet_dir.
1 parent 76557cb commit 0e4b695

File tree

1 file changed

+80
-183
lines changed

1 file changed

+80
-183
lines changed

test/functional/feature_backwards_compatibility.py

Lines changed: 80 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,27 @@ def setup_nodes(self):
6363
self.start_nodes()
6464
self.import_deterministic_coinbase_privkeys()
6565

66-
def run_test(self):
67-
self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, self.nodes[0].getnewaddress())
68-
69-
# Sanity check the test framework:
70-
res = self.nodes[self.num_nodes - 1].getblockchaininfo()
71-
assert_equal(res['blocks'], COINBASE_MATURITY + 1)
66+
def nodes_wallet_dir(self, node):
67+
if node.version < 170000:
68+
return os.path.join(node.datadir, "regtest")
69+
return os.path.join(node.datadir, "regtest/wallets")
7270

73-
node_master = self.nodes[self.num_nodes - 5]
71+
def run_test(self):
72+
node_miner = self.nodes[0]
73+
node_master = self.nodes[1]
7474
node_v19 = self.nodes[self.num_nodes - 4]
7575
node_v18 = self.nodes[self.num_nodes - 3]
7676
node_v17 = self.nodes[self.num_nodes - 2]
7777
node_v16 = self.nodes[self.num_nodes - 1]
7878

79+
legacy_nodes = self.nodes[2:]
80+
81+
self.generatetoaddress(node_miner, COINBASE_MATURITY + 1, node_miner.getnewaddress())
82+
83+
# Sanity check the test framework:
84+
res = node_v16.getblockchaininfo()
85+
assert_equal(res['blocks'], COINBASE_MATURITY + 1)
86+
7987
self.log.info("Test wallet backwards compatibility...")
8088
# Create a number of wallets and open them in older versions:
8189

@@ -88,21 +96,21 @@ def run_test(self):
8896
assert info['keypoolsize'] > 0
8997
# Create a confirmed transaction, receiving coins
9098
address = wallet.getnewaddress()
91-
self.nodes[0].sendtoaddress(address, 10)
99+
node_miner.sendtoaddress(address, 10)
92100
self.sync_mempools()
93-
self.generate(self.nodes[0], 1)
101+
self.generate(node_miner, 1)
94102
# Create a conflicting transaction using RBF
95-
return_address = self.nodes[0].getnewaddress()
96-
tx1_id = self.nodes[1].sendtoaddress(return_address, 1)
97-
tx2_id = self.nodes[1].bumpfee(tx1_id)["txid"]
103+
return_address = node_miner.getnewaddress()
104+
tx1_id = node_master.sendtoaddress(return_address, 1)
105+
tx2_id = node_master.bumpfee(tx1_id)["txid"]
98106
# Confirm the transaction
99107
self.sync_mempools()
100-
self.generate(self.nodes[0], 1)
108+
self.generate(node_miner, 1)
101109
# Create another conflicting transaction using RBF
102-
tx3_id = self.nodes[1].sendtoaddress(return_address, 1)
103-
tx4_id = self.nodes[1].bumpfee(tx3_id)["txid"]
110+
tx3_id = node_master.sendtoaddress(return_address, 1)
111+
tx4_id = node_master.bumpfee(tx3_id)["txid"]
104112
# Abandon transaction, but don't confirm
105-
self.nodes[1].abandontransaction(tx3_id)
113+
node_master.abandontransaction(tx3_id)
106114

107115
# w1_v19: regular wallet, created with v0.19
108116
node_v19.rpc.createwallet(wallet_name="w1_v19")
@@ -113,6 +121,7 @@ def run_test(self):
113121
# Use addmultisigaddress (see #18075)
114122
address_18075 = wallet.rpc.addmultisigaddress(1, ["0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52", "037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073"], "", "legacy")["address"]
115123
assert wallet.getaddressinfo(address_18075)["solvable"]
124+
node_v19.unloadwallet("w1_v19")
116125

117126
# w1_v18: regular wallet, created with v0.18
118127
node_v18.rpc.createwallet(wallet_name="w1_v18")
@@ -130,20 +139,6 @@ def run_test(self):
130139
assert info['private_keys_enabled'] == False
131140
assert info['keypoolsize'] == 0
132141

133-
# w2_v19: wallet with private keys disabled, created with v0.19
134-
node_v19.rpc.createwallet(wallet_name="w2_v19", disable_private_keys=True)
135-
wallet = node_v19.get_wallet_rpc("w2_v19")
136-
info = wallet.getwalletinfo()
137-
assert info['private_keys_enabled'] == False
138-
assert info['keypoolsize'] == 0
139-
140-
# w2_v18: wallet with private keys disabled, created with v0.18
141-
node_v18.rpc.createwallet(wallet_name="w2_v18", disable_private_keys=True)
142-
wallet = node_v18.get_wallet_rpc("w2_v18")
143-
info = wallet.getwalletinfo()
144-
assert info['private_keys_enabled'] == False
145-
assert info['keypoolsize'] == 0
146-
147142
# w3: blank wallet, created on master: update this
148143
# test when default blank wallets can no longer be opened by older versions.
149144
node_master.createwallet(wallet_name="w3", blank=True)
@@ -152,194 +147,96 @@ def run_test(self):
152147
assert info['private_keys_enabled']
153148
assert info['keypoolsize'] == 0
154149

155-
# w3_v19: blank wallet, created with v0.19
156-
node_v19.rpc.createwallet(wallet_name="w3_v19", blank=True)
157-
wallet = node_v19.get_wallet_rpc("w3_v19")
158-
info = wallet.getwalletinfo()
159-
assert info['private_keys_enabled']
160-
assert info['keypoolsize'] == 0
161-
162-
# w3_v18: blank wallet, created with v0.18
163-
node_v18.rpc.createwallet(wallet_name="w3_v18", blank=True)
164-
wallet = node_v18.get_wallet_rpc("w3_v18")
165-
info = wallet.getwalletinfo()
166-
assert info['private_keys_enabled']
167-
assert info['keypoolsize'] == 0
168-
169-
# Copy the wallets to older nodes:
150+
# Unload wallets and copy to older nodes:
170151
node_master_wallets_dir = os.path.join(node_master.datadir, "regtest/wallets")
171152
node_v19_wallets_dir = os.path.join(node_v19.datadir, "regtest/wallets")
172-
node_v18_wallets_dir = os.path.join(node_v18.datadir, "regtest/wallets")
173153
node_v17_wallets_dir = os.path.join(node_v17.datadir, "regtest/wallets")
174154
node_v16_wallets_dir = os.path.join(node_v16.datadir, "regtest")
175155
node_master.unloadwallet("w1")
176156
node_master.unloadwallet("w2")
177-
node_v19.unloadwallet("w1_v19")
178-
node_v19.unloadwallet("w2_v19")
179-
node_v18.unloadwallet("w1_v18")
180-
node_v18.unloadwallet("w2_v18")
181-
182-
# Copy wallets to v0.16
183-
for wallet in os.listdir(node_master_wallets_dir):
184-
shutil.copytree(
185-
os.path.join(node_master_wallets_dir, wallet),
186-
os.path.join(node_v16_wallets_dir, wallet)
187-
)
157+
node_master.unloadwallet("w3")
188158

189-
# Copy wallets to v0.17
190-
for wallet in os.listdir(node_master_wallets_dir):
191-
shutil.copytree(
192-
os.path.join(node_master_wallets_dir, wallet),
193-
os.path.join(node_v17_wallets_dir, wallet)
194-
)
195-
for wallet in os.listdir(node_v18_wallets_dir):
196-
shutil.copytree(
197-
os.path.join(node_v18_wallets_dir, wallet),
198-
os.path.join(node_v17_wallets_dir, wallet)
199-
)
200-
201-
# Copy wallets to v0.18
202-
for wallet in os.listdir(node_master_wallets_dir):
203-
shutil.copytree(
204-
os.path.join(node_master_wallets_dir, wallet),
205-
os.path.join(node_v18_wallets_dir, wallet)
206-
)
207-
208-
# Copy wallets to v0.19
209-
for wallet in os.listdir(node_master_wallets_dir):
210-
shutil.copytree(
211-
os.path.join(node_master_wallets_dir, wallet),
212-
os.path.join(node_v19_wallets_dir, wallet)
213-
)
159+
for node in legacy_nodes:
160+
# Copy wallets to previous version
161+
for wallet in os.listdir(node_master_wallets_dir):
162+
shutil.copytree(
163+
os.path.join(node_master_wallets_dir, wallet),
164+
os.path.join(self.nodes_wallet_dir(node), wallet)
165+
)
214166

215167
if not self.options.descriptors:
216168
# Descriptor wallets break compatibility, only run this test for legacy wallet
217-
# Open the wallets in v0.19
218-
node_v19.loadwallet("w1")
219-
wallet = node_v19.get_wallet_rpc("w1")
220-
info = wallet.getwalletinfo()
221-
assert info['private_keys_enabled']
222-
assert info['keypoolsize'] > 0
223-
txs = wallet.listtransactions()
224-
assert_equal(len(txs), 5)
225-
assert_equal(txs[1]["txid"], tx1_id)
226-
assert_equal(txs[2]["walletconflicts"], [tx1_id])
227-
assert_equal(txs[1]["replaced_by_txid"], tx2_id)
228-
assert not(txs[1]["abandoned"])
229-
assert_equal(txs[1]["confirmations"], -1)
230-
assert_equal(txs[2]["blockindex"], 1)
231-
assert txs[3]["abandoned"]
232-
assert_equal(txs[4]["walletconflicts"], [tx3_id])
233-
assert_equal(txs[3]["replaced_by_txid"], tx4_id)
234-
assert not(hasattr(txs[3], "blockindex"))
235-
236-
node_v19.loadwallet("w2")
237-
wallet = node_v19.get_wallet_rpc("w2")
238-
info = wallet.getwalletinfo()
239-
assert info['private_keys_enabled'] == False
240-
assert info['keypoolsize'] == 0
241-
242-
node_v19.loadwallet("w3")
243-
wallet = node_v19.get_wallet_rpc("w3")
244-
info = wallet.getwalletinfo()
245-
assert info['private_keys_enabled']
246-
assert info['keypoolsize'] == 0
247-
248-
# Open the wallets in v0.18
249-
node_v18.loadwallet("w1")
250-
wallet = node_v18.get_wallet_rpc("w1")
251-
info = wallet.getwalletinfo()
252-
assert info['private_keys_enabled']
253-
assert info['keypoolsize'] > 0
254-
txs = wallet.listtransactions()
255-
assert_equal(len(txs), 5)
256-
assert_equal(txs[1]["txid"], tx1_id)
257-
assert_equal(txs[2]["walletconflicts"], [tx1_id])
258-
assert_equal(txs[1]["replaced_by_txid"], tx2_id)
259-
assert not(txs[1]["abandoned"])
260-
assert_equal(txs[1]["confirmations"], -1)
261-
assert_equal(txs[2]["blockindex"], 1)
262-
assert txs[3]["abandoned"]
263-
assert_equal(txs[4]["walletconflicts"], [tx3_id])
264-
assert_equal(txs[3]["replaced_by_txid"], tx4_id)
265-
assert not(hasattr(txs[3], "blockindex"))
266-
267-
node_v18.loadwallet("w2")
268-
wallet = node_v18.get_wallet_rpc("w2")
269-
info = wallet.getwalletinfo()
270-
assert info['private_keys_enabled'] == False
271-
assert info['keypoolsize'] == 0
272-
273-
node_v18.loadwallet("w3")
274-
wallet = node_v18.get_wallet_rpc("w3")
275-
info = wallet.getwalletinfo()
276-
assert info['private_keys_enabled']
277-
assert info['keypoolsize'] == 0
278-
279-
node_v17.loadwallet("w1")
280-
wallet = node_v17.get_wallet_rpc("w1")
281-
info = wallet.getwalletinfo()
282-
assert info['private_keys_enabled']
283-
assert info['keypoolsize'] > 0
284-
285-
node_v17.loadwallet("w2")
286-
wallet = node_v17.get_wallet_rpc("w2")
287-
info = wallet.getwalletinfo()
288-
assert info['private_keys_enabled'] == False
289-
assert info['keypoolsize'] == 0
169+
# Load modern wallet with older nodes
170+
for node in legacy_nodes:
171+
for wallet_name in ["w1", "w2", "w3"]:
172+
if node.version < 170000:
173+
# loadwallet was introduced in v0.17.0
174+
continue
175+
if node.version < 180000 and wallet_name == "w3":
176+
# Blank wallets were introduced in v0.18.0. We test the loading error below.
177+
continue
178+
node.loadwallet(wallet_name)
179+
wallet = node.get_wallet_rpc(wallet_name)
180+
info = wallet.getwalletinfo()
181+
if wallet_name == "w1":
182+
assert info['private_keys_enabled'] == True
183+
assert info['keypoolsize'] > 0
184+
txs = wallet.listtransactions()
185+
assert_equal(len(txs), 5)
186+
assert_equal(txs[1]["txid"], tx1_id)
187+
assert_equal(txs[2]["walletconflicts"], [tx1_id])
188+
assert_equal(txs[1]["replaced_by_txid"], tx2_id)
189+
assert not(txs[1]["abandoned"])
190+
assert_equal(txs[1]["confirmations"], -1)
191+
assert_equal(txs[2]["blockindex"], 1)
192+
assert txs[3]["abandoned"]
193+
assert_equal(txs[4]["walletconflicts"], [tx3_id])
194+
assert_equal(txs[3]["replaced_by_txid"], tx4_id)
195+
assert not(hasattr(txs[3], "blockindex"))
196+
elif wallet_name == "w2":
197+
assert(info['private_keys_enabled'] == False)
198+
assert info['keypoolsize'] == 0
199+
else:
200+
assert(info['private_keys_enabled'] == True)
201+
assert info['keypoolsize'] == 0
290202
else:
291-
# Descriptor wallets appear to be corrupted wallets to old software
292-
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v19.loadwallet, "w1")
293-
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v19.loadwallet, "w2")
294-
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v19.loadwallet, "w3")
295-
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v18.loadwallet, "w1")
296-
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v18.loadwallet, "w2")
297-
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node_v18.loadwallet, "w3")
298-
299-
# Open the wallets in v0.17
300-
node_v17.loadwallet("w1_v18")
301-
wallet = node_v17.get_wallet_rpc("w1_v18")
302-
info = wallet.getwalletinfo()
303-
assert info['private_keys_enabled']
304-
assert info['keypoolsize'] > 0
305-
306-
node_v17.loadwallet("w2_v18")
307-
wallet = node_v17.get_wallet_rpc("w2_v18")
308-
info = wallet.getwalletinfo()
309-
assert info['private_keys_enabled'] == False
310-
assert info['keypoolsize'] == 0
203+
for node in legacy_nodes:
204+
# Descriptor wallets appear to be corrupted wallets to old software
205+
# and loadwallet is introduced in v0.17.0
206+
if node.version >= 170000 and node.version < 210000:
207+
for wallet_name in ["w1", "w2", "w3"]:
208+
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node.loadwallet, wallet_name)
311209

312210
# RPC loadwallet failure causes bitcoind to exit, in addition to the RPC
313211
# call failure, so the following test won't work:
314-
# assert_raises_rpc_error(-4, "Wallet loading failed.", node_v17.loadwallet, 'w3_v18')
212+
# assert_raises_rpc_error(-4, "Wallet loading failed.", node_v17.loadwallet, 'w3')
315213

316214
# Instead, we stop node and try to launch it with the wallet:
317-
self.stop_node(4)
318-
node_v17.assert_start_raises_init_error(["-wallet=w3_v18"], "Error: Error loading w3_v18: Wallet requires newer version of Bitcoin Core")
215+
self.stop_node(node_v17.index)
319216
if self.options.descriptors:
320217
# Descriptor wallets appear to be corrupted wallets to old software
321218
node_v17.assert_start_raises_init_error(["-wallet=w1"], "Error: wallet.dat corrupt, salvage failed")
322219
node_v17.assert_start_raises_init_error(["-wallet=w2"], "Error: wallet.dat corrupt, salvage failed")
323220
node_v17.assert_start_raises_init_error(["-wallet=w3"], "Error: wallet.dat corrupt, salvage failed")
324221
else:
325222
node_v17.assert_start_raises_init_error(["-wallet=w3"], "Error: Error loading w3: Wallet requires newer version of Bitcoin Core")
326-
self.start_node(4)
223+
self.start_node(node_v17.index)
327224

328225
if not self.options.descriptors:
329226
# Descriptor wallets break compatibility, only run this test for legacy wallets
330227
# Open most recent wallet in v0.16 (no loadwallet RPC)
331-
self.restart_node(5, extra_args=["-wallet=w2"])
228+
self.restart_node(node_v16.index, extra_args=["-wallet=w2"])
332229
wallet = node_v16.get_wallet_rpc("w2")
333230
info = wallet.getwalletinfo()
334231
assert info['keypoolsize'] == 1
335232

336233
# Create upgrade wallet in v0.16
337-
self.restart_node(-1, extra_args=["-wallet=u1_v16"])
234+
self.restart_node(node_v16.index, extra_args=["-wallet=u1_v16"])
338235
wallet = node_v16.get_wallet_rpc("u1_v16")
339236
v16_addr = wallet.getnewaddress('', "bech32")
340237
v16_info = wallet.validateaddress(v16_addr)
341238
v16_pubkey = v16_info['pubkey']
342-
self.stop_node(-1)
239+
self.stop_node(node_v16.index)
343240

344241
self.log.info("Test wallet upgrade path...")
345242
# u1: regular wallet, created with v0.17
@@ -371,7 +268,7 @@ def run_test(self):
371268
os.path.join(node_master_wallets_dir, "u1_v16"),
372269
os.path.join(node_v16_wallets_dir, "wallets/u1_v16")
373270
)
374-
self.start_node(-1, extra_args=["-wallet=u1_v16"])
271+
self.start_node(node_v16.index, extra_args=["-wallet=u1_v16"])
375272
wallet = node_v16.get_wallet_rpc("u1_v16")
376273
info = wallet.validateaddress(v16_addr)
377274
assert_equal(info, v16_info)

0 commit comments

Comments
 (0)