Skip to content

Commit f30d340

Browse files
Merge #6844: backport: bitcoin#19013: test: fixes intermittent failure for backwards compatibility test
25b82ab test: final cleanups for feature_backwards_compatibility.py accordingly linter (Konstantin Akimov) 93902fc test: add v21.1.1 to the list of version to test backwards compatibility (Konstantin Akimov) 1957892 feat: bump version 21.0.1 to 21.1.1 for feature_backwards_compatibility.py (Konstantin Akimov) d7e382e Merge bitcoin#19013: test: add v0.20.1, v0.21.0 and v22.0 to backwards compatibility test (MarcoFalke) 0f92a66 test: Fix intermittent test failure in feature_backwards_compatibility (MarcoFalke) 556b869 test: backwards compatibility: misc fixes (Sjors Provoost) 3d1c70e test: Remove i686 from test/get_previous_releases.py (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented Functional test feature_backwards_compatibility.py has ~15% failure rate. ## What was done? This backport is dashified and heavily modified to fit our codebase. - It refactors functional test (as original PR 19013) - It fixes intermittent error (as original PR 19013) - It drops support of i686 from list of previous releases (as original PR 19013) - It adds v21.1.1 and replace v20.0.1 to v21.1.1 while original PR adds version v0.20.1, v0.21.0 and v22.0. ## How Has This Been Tested? Run multiple time. Failure rate dropped from 15% to 0 failures. ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [x] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: UdjinM6: utACK 25b82ab Tree-SHA512: 404f45e78326c0b6982fbd969cc16414c066f73c1af3d78e4fd7a64cfb21f83b49c689243caa17fd4f475b3f262bde996eb47efafb3c55c891efdccd46e3eeef
2 parents 043548a + 25b82ab commit f30d340

File tree

4 files changed

+105
-208
lines changed

4 files changed

+105
-208
lines changed

ci/test/00_setup_env_native_qt5.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude fe
1414
export RUN_UNIT_TESTS_SEQUENTIAL="true"
1515
export RUN_UNIT_TESTS="false"
1616
export GOAL="install"
17-
export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.12.1.5 v0.15.0.0 v0.16.1.1 v0.17.0.3 v18.2.2 v19.3.0 v20.0.1"
17+
export PREVIOUS_RELEASES_TO_DOWNLOAD="v0.12.1.5 v0.15.0.0 v0.16.1.1 v0.17.0.3 v18.2.2 v19.3.0 v20.1.1 v21.1.1"
1818
export BITCOIN_CONFIG="--enable-zmq --with-libs=no --enable-reduce-exports --disable-fuzz-binary LDFLAGS=-static-libstdc++ --with-boost-process"

test/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ test/functional/test_runner.py --extended
103103
In order to run backwards compatibility tests, download the previous node binaries:
104104

105105
```
106-
test/get_previous_releases.py -b v19.3.0 v18.2.2 v0.17.0.3 v0.16.1.1 v0.15.0.0 v0.12.1.5
106+
test/get_previous_releases.py -b v0.12.1.5 v0.15.0.0 v0.16.1.1 v0.17.0.3 v18.2.2 v19.3.0 v20.1.1 v21.1.1
107107
```
108108

109109
By default, up to 4 tests will be run in parallel by test_runner. To specify

test/functional/feature_backwards_compatibility.py

Lines changed: 79 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import os
2121
import shutil
2222

23+
from test_framework.blocktools import COINBASE_MATURITY
2324
from test_framework.descriptors import descsum_create
2425
from test_framework.test_framework import BitcoinTestFramework
2526

@@ -32,16 +33,17 @@
3233
class BackwardsCompatibilityTest(BitcoinTestFramework):
3334
def set_test_params(self):
3435
self.setup_clean_chain = True
35-
self.num_nodes = 7
36+
self.num_nodes = 8
3637
# Add new version after each release:
3738
self.extra_args = [
38-
[], # Pre-release: use to mine blocks
39-
["-nowallet"], # Pre-release: use to receive coins, swap wallets, etc
40-
["-nowallet"], # v20.0.1
41-
["-nowallet"], # v19.3.0
42-
["-nowallet"], # v18.2.2
43-
["-nowallet"], # v0.17.0.3
44-
["-nowallet"], # v0.16.1.1
39+
["-whitelist=noban@127.0.0.1"], # Pre-release: use to mine blocks
40+
["-nowallet", "-whitelist=noban@127.0.0.1"], # Pre-release: use to receive coins, swap wallets, etc
41+
["-nowallet", "-whitelist=noban@127.0.0.1"], # v21.1.1 - supports descriptor wallets
42+
["-nowallet", "-whitelist=noban@127.0.0.1"], # v20.1.1 - last legacy-only version, no descriptor wallets
43+
["-nowallet", "-whitelist=noban@127.0.0.1"], # v19.3.0
44+
["-nowallet", "-whitelist=noban@127.0.0.1"], # v18.2.2
45+
["-nowallet", "-whitelist=127.0.0.1"], # v0.17.0.3
46+
["-nowallet", "-whitelist=127.0.0.1"], # v0.16.1.1
4547
]
4648
self.wallet_names = [self.default_wallet_name]
4749

@@ -53,7 +55,8 @@ def setup_nodes(self):
5355
self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
5456
None,
5557
None,
56-
19030000,
58+
21010100,
59+
20010100,
5760
19030000,
5861
18020200,
5962
170003,
@@ -63,20 +66,28 @@ def setup_nodes(self):
6366
self.start_nodes()
6467
self.import_deterministic_coinbase_privkeys()
6568

66-
def run_test(self):
67-
self.generatetoaddress(self.nodes[0], 101, 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'], 101)
69+
def nodes_wallet_dir(self, node):
70+
if node.version < 160000:
71+
return os.path.join(node.datadir, "regtest")
72+
return os.path.join(node.datadir, "regtest/wallets")
7273

73-
node_master = self.nodes[self.num_nodes - 6]
74+
def run_test(self):
75+
node_miner = self.nodes[0]
76+
node_master = self.nodes[1]
7477
node_v20 = self.nodes[self.num_nodes - 5]
7578
node_v19 = self.nodes[self.num_nodes - 4]
7679
node_v18 = self.nodes[self.num_nodes - 3]
7780
node_v17 = self.nodes[self.num_nodes - 2]
7881
node_v16 = self.nodes[self.num_nodes - 1]
7982

83+
legacy_nodes = self.nodes[3:]
84+
85+
self.generatetoaddress(node_miner, COINBASE_MATURITY + 1, node_miner.getnewaddress())
86+
87+
# Sanity check the test framework:
88+
res = node_v16.getblockchaininfo()
89+
assert_equal(res['blocks'], COINBASE_MATURITY + 1)
90+
8091
self.log.info("Test wallet backwards compatibility...")
8192
# Create a number of wallets and open them in older versions:
8293

@@ -89,9 +100,9 @@ def run_test(self):
89100
assert info['keypoolsize'] > 0
90101
# Create a confirmed transaction, receiving coins
91102
address = wallet.getnewaddress()
92-
self.nodes[0].sendtoaddress(address, 1)
103+
node_miner.sendtoaddress(address, 1)
93104
self.sync_mempools()
94-
self.generate(self.nodes[0], 1)
105+
self.generate(node_miner, 1)
95106

96107
# w1_v19: regular wallet, created with v0.19
97108
node_v19.rpc.createwallet(wallet_name="w1_v19")
@@ -102,6 +113,7 @@ def run_test(self):
102113
# Use addmultisigaddress (see #18075)
103114
address_18075 = wallet.addmultisigaddress(1, ["0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52", "037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073"], "")["address"]
104115
assert wallet.getaddressinfo(address_18075)["solvable"]
116+
node_v19.unloadwallet("w1_v19")
105117

106118
# w1_v18: regular wallet, created with v0.18
107119
node_v18.rpc.createwallet(wallet_name="w1_v18")
@@ -148,198 +160,78 @@ def run_test(self):
148160
assert info['private_keys_enabled']
149161
assert info['keypoolsize'] == 0
150162

151-
# w3_v19: blank wallet, created with v0.19
152-
node_v19.rpc.createwallet(wallet_name="w3_v19", blank=True)
153-
wallet = node_v19.get_wallet_rpc("w3_v19")
154-
info = wallet.getwalletinfo()
155-
assert info['private_keys_enabled']
156-
assert info['keypoolsize'] == 0
157-
158-
# w3_v18: blank wallet, created with v0.18
159-
node_v18.rpc.createwallet(wallet_name="w3_v18", blank=True)
160-
wallet = node_v18.get_wallet_rpc("w3_v18")
161-
info = wallet.getwalletinfo()
162-
assert info['private_keys_enabled']
163-
assert info['keypoolsize'] == 0
164-
165-
# Copy the wallets to older nodes:
163+
# Unload wallets and copy to older nodes:
166164
node_master_wallets_dir = os.path.join(node_master.datadir, "regtest/wallets")
167-
node_v20_wallets_dir = os.path.join(node_v20.datadir, "regtest/wallets")
168165
node_v19_wallets_dir = os.path.join(node_v19.datadir, "regtest/wallets")
169-
node_v18_wallets_dir = os.path.join(node_v18.datadir, "regtest/wallets")
170166
node_v17_wallets_dir = os.path.join(node_v17.datadir, "regtest/wallets")
171-
node_v16_wallets_dir = os.path.join(node_v16.datadir, "regtest")
172167
node_master.unloadwallet("w1")
173168
node_master.unloadwallet("w2")
174-
node_v19.unloadwallet("w1_v19")
175-
node_v19.unloadwallet("w2_v19")
176-
node_v18.unloadwallet("w1_v18")
177-
node_v18.unloadwallet("w2_v18")
178-
179-
# Copy wallets to v0.16
180-
for wallet in os.listdir(node_master_wallets_dir):
181-
shutil.copytree(
182-
os.path.join(node_master_wallets_dir, wallet),
183-
os.path.join(node_v16_wallets_dir, wallet)
184-
)
185-
186-
# Copy wallets to v0.17
187-
for wallet in os.listdir(node_master_wallets_dir):
188-
shutil.copytree(
189-
os.path.join(node_master_wallets_dir, wallet),
190-
os.path.join(node_v17_wallets_dir, wallet)
191-
)
192-
for wallet in os.listdir(node_v18_wallets_dir):
193-
shutil.copytree(
194-
os.path.join(node_v18_wallets_dir, wallet),
195-
os.path.join(node_v17_wallets_dir, wallet)
196-
)
197-
198-
# Copy wallets to v0.18
199-
for wallet in os.listdir(node_master_wallets_dir):
200-
shutil.copytree(
201-
os.path.join(node_master_wallets_dir, wallet),
202-
os.path.join(node_v18_wallets_dir, wallet)
203-
)
204-
205-
# Copy wallets to v0.19
206-
for wallet in os.listdir(node_master_wallets_dir):
207-
shutil.copytree(
208-
os.path.join(node_master_wallets_dir, wallet),
209-
os.path.join(node_v19_wallets_dir, wallet)
210-
)
169+
node_master.unloadwallet("w3")
211170

212-
# Copy wallets to v0.20
213-
for wallet in os.listdir(node_master_wallets_dir):
214-
shutil.copytree(
215-
os.path.join(node_master_wallets_dir, wallet),
216-
os.path.join(node_v20_wallets_dir, wallet)
217-
)
171+
for node in legacy_nodes:
172+
# Copy wallets to previous version
173+
for wallet in os.listdir(node_master_wallets_dir):
174+
shutil.copytree(
175+
os.path.join(node_master_wallets_dir, wallet),
176+
os.path.join(self.nodes_wallet_dir(node), wallet)
177+
)
218178

219179
if not self.options.descriptors:
220180
# Descriptor wallets break compatibility, only run this test for legacy wallet
221-
# Open the wallets in v0.20
222-
node_v20.loadwallet("w1")
223-
wallet = node_v20.get_wallet_rpc("w1")
224-
info = wallet.getwalletinfo()
225-
assert info['private_keys_enabled']
226-
assert info['keypoolsize'] > 0
227-
txs = wallet.listtransactions()
228-
assert_equal(len(txs), 1)
229-
230-
node_v20.loadwallet("w2")
231-
wallet = node_v20.get_wallet_rpc("w2")
232-
info = wallet.getwalletinfo()
233-
assert info['private_keys_enabled'] == False
234-
assert info['keypoolsize'] == 0
235-
236-
node_v20.loadwallet("w3")
237-
wallet = node_v20.get_wallet_rpc("w3")
238-
info = wallet.getwalletinfo()
239-
assert info['private_keys_enabled']
240-
assert info['keypoolsize'] == 0
241-
242-
# Open the wallets in v0.19
243-
node_v19.loadwallet("w1")
244-
wallet = node_v19.get_wallet_rpc("w1")
245-
info = wallet.getwalletinfo()
246-
assert info['private_keys_enabled']
247-
assert info['keypoolsize'] > 0
248-
txs = wallet.listtransactions()
249-
assert_equal(len(txs), 1)
250-
251-
node_v19.loadwallet("w2")
252-
wallet = node_v19.get_wallet_rpc("w2")
253-
info = wallet.getwalletinfo()
254-
assert info['private_keys_enabled'] == False
255-
assert info['keypoolsize'] == 0
256-
257-
node_v19.loadwallet("w3")
258-
wallet = node_v19.get_wallet_rpc("w3")
259-
info = wallet.getwalletinfo()
260-
assert info['private_keys_enabled']
261-
assert info['keypoolsize'] == 0
262-
263-
# Open the wallets in v0.18
264-
node_v18.loadwallet("w1")
265-
wallet = node_v18.get_wallet_rpc("w1")
266-
info = wallet.getwalletinfo()
267-
assert info['private_keys_enabled']
268-
assert info['keypoolsize'] > 0
269-
txs = wallet.listtransactions()
270-
assert_equal(len(txs), 1)
271-
272-
node_v18.loadwallet("w2")
273-
wallet = node_v18.get_wallet_rpc("w2")
274-
info = wallet.getwalletinfo()
275-
assert info['private_keys_enabled'] == False
276-
assert info['keypoolsize'] == 0
277-
278-
node_v18.loadwallet("w3")
279-
wallet = node_v18.get_wallet_rpc("w3")
280-
info = wallet.getwalletinfo()
281-
assert info['private_keys_enabled']
282-
assert info['keypoolsize'] == 0
283-
284-
node_v17.loadwallet("w1")
285-
wallet = node_v17.get_wallet_rpc("w1")
286-
info = wallet.getwalletinfo()
287-
# doesn't have WALLET_FLAG_DISABLE_PRIVATE_KEYS in v17
288-
assert 'private_keys_enabled' not in info
289-
assert info['keypoolsize'] > 0
290-
291-
node_v17.loadwallet("w2")
292-
wallet = node_v17.get_wallet_rpc("w2")
293-
info = wallet.getwalletinfo()
294-
# doesn't have WALLET_FLAG_DISABLE_PRIVATE_KEYS in v17
295-
assert 'private_keys_enabled' not in info
296-
assert info['keypoolsize'] > 0
181+
# Load modern wallet with older nodes
182+
for node in legacy_nodes:
183+
for wallet_name in ["w1", "w2", "w3"]:
184+
if node.version < 180000:
185+
# doesn't have WALLET_FLAG_DISABLE_PRIVATE_KEYS in v17
186+
continue
187+
self.log.info(f"Test wallet wallet: {wallet_name} on node {node.index} version: {node.version}")
188+
node.loadwallet(wallet_name)
189+
wallet = node.get_wallet_rpc(wallet_name)
190+
info = wallet.getwalletinfo()
191+
if wallet_name == "w1":
192+
assert info['private_keys_enabled'] == True
193+
assert info['keypoolsize'] > 0
194+
txs = wallet.listtransactions()
195+
assert_equal(len(txs), 1)
196+
elif wallet_name == "w2":
197+
assert(info['private_keys_enabled'] == False)
198+
if node.version > 20999999:
199+
assert info['keypoolsize'] > 0
200+
elif wallet_name == "w3":
201+
assert(info['private_keys_enabled'] == True)
202+
assert 'keypoolsize' not in info or info['keypoolsize'] == 0
203+
else:
204+
assert False
297205
else:
298-
# Descriptor wallets appear to be corrupted wallets to old software
299-
assert_raises_rpc_error(-4, "Wallet requires newer version of Dash Core", node_v19.loadwallet, "w1")
300-
assert_raises_rpc_error(-4, "Wallet requires newer version of Dash Core", node_v19.loadwallet, "w2")
301-
assert_raises_rpc_error(-4, "Wallet requires newer version of Dash Core", node_v19.loadwallet, "w3")
302-
assert_raises_rpc_error(-18, "Data is not in recognized format", node_v18.loadwallet, "w1")
303-
assert_raises_rpc_error(-18, "Data is not in recognized format", node_v18.loadwallet, "w2")
304-
assert_raises_rpc_error(-18, "Data is not in recognized format", node_v18.loadwallet, "w3")
305-
306-
# Open the wallets in v0.17
307-
node_v17.loadwallet("w1_v18")
308-
wallet = node_v17.get_wallet_rpc("w1_v18")
309-
info = wallet.getwalletinfo()
310-
# doesn't have WALLET_FLAG_DISABLE_PRIVATE_KEYS in v17
311-
assert 'private_keys_enabled' not in info
312-
assert info['keypoolsize'] > 0
313-
314-
node_v17.loadwallet("w2_v18")
315-
wallet = node_v17.get_wallet_rpc("w2_v18")
316-
info = wallet.getwalletinfo()
317-
# doesn't have WALLET_FLAG_DISABLE_PRIVATE_KEYS in v17
318-
assert 'private_keys_enabled' not in info
319-
assert info['keypoolsize'] > 0
206+
for node in legacy_nodes:
207+
# Descriptor wallets appear to be corrupted wallets to old software
208+
if node.version < 210000:
209+
for wallet_name in ["w1", "w2", "w3"]:
210+
assert_raises_rpc_error(-4, "Wallet file verification failed: wallet.dat corrupt, salvage failed", node.loadwallet, wallet_name)
320211

321212
# RPC loadwallet failure causes bitcoind to exit, in addition to the RPC
322213
# call failure, so the following test won't work:
323-
# assert_raises_rpc_error(-4, "Wallet loading failed.", node_v17.loadwallet, 'w3_v18')
214+
# assert_raises_rpc_error(-4, "Wallet loading failed.", node_v17.loadwallet, 'w3')
324215

325216
# Instead, we stop node and try to launch it with the wallet:
326-
self.stop_node(5)
217+
self.stop_node(node_v17.index)
327218
# it expected to fail with error 'DBErrors::TOO_NEW' but Dash Core can open v18 by version 17
328219
# can be implemented in future if there's any incompatible versions
329220
#node_v17.assert_start_raises_init_error(["-wallet=w3_v18"], "Error: Error loading w3_v18: Wallet requires newer version of Dash Core")
330221
#node_v17.assert_start_raises_init_error(["-wallet=w3"], "Error: Error loading w3: Wallet requires newer version of Dash Core")
331-
self.start_node(5)
222+
self.start_node(node_v17.index)
332223

333-
# Open most recent wallet in v0.16 (no loadwallet RPC)
334-
self.restart_node(6, extra_args=["-wallet=w2"])
335-
wallet = node_v16.get_wallet_rpc("w2")
336-
info = wallet.getwalletinfo()
337-
assert info['keypoolsize'] == 1
224+
if not self.options.descriptors:
225+
# Open most recent wallet in v0.16 (no loadwallet RPC)
226+
self.restart_node(node_v16.index, extra_args=["-wallet=w2"])
227+
wallet = node_v16.get_wallet_rpc("w2")
228+
info = wallet.getwalletinfo()
229+
assert info['keypoolsize'] == 1
338230

339231
self.log.info("Test wallet upgrade path...")
340232
# Bitcoin creates hd wallets by default since v16, but Dash Core v17 does not.
341233
# enforce it by restarting v17
342-
self.restart_node(5, extra_args=["-usehd=1"])
234+
self.restart_node(node_v17.index, extra_args=["-usehd=1"])
343235
# u1: regular wallet, created with v0.17
344236
node_v17.rpc.createwallet(wallet_name="u1_v17")
345237
wallet = node_v17.get_wallet_rpc("u1_v17")
@@ -395,7 +287,7 @@ def run_test(self):
395287
wallet = node_v19.get_wallet_rpc("w1_v19")
396288
assert wallet.getaddressinfo(address_18075)["solvable"]
397289

398-
self.stop_node(5, expected_stderr=("Warning: Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works!\n"*3)[:-1])
290+
self.stop_node(node_v17.index, expected_stderr=("Warning: Make sure to encrypt your wallet and delete all non-encrypted backups after you have verified that the wallet works!\n"*3)[:-1])
399291

400292
if __name__ == '__main__':
401293
BackwardsCompatibilityTest().main()

0 commit comments

Comments
 (0)