aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/feature_assumeutxo.py10
-rwxr-xr-xtest/functional/feature_coinstatsindex.py6
-rwxr-xr-xtest/functional/feature_dbcrash.py8
-rwxr-xr-xtest/functional/feature_reindex_readonly.py43
-rwxr-xr-xtest/functional/feature_utxo_set_hash.py2
-rwxr-xr-xtest/functional/rpc_blockchain.py12
-rwxr-xr-xtest/functional/rpc_dumptxoutset.py2
-rwxr-xr-xtest/functional/wallet_migration.py56
8 files changed, 106 insertions, 33 deletions
diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py
index 2765509f84..9c265649d5 100755
--- a/test/functional/feature_assumeutxo.py
+++ b/test/functional/feature_assumeutxo.py
@@ -94,8 +94,10 @@ class AssumeutxoTest(BitcoinTestFramework):
self.log.info(" - snapshot file with alternated UTXO data")
cases = [
- [b"\xff" * 32, 0, "29926acf3ac81f908cf4f22515713ca541c08bb0f0ef1b2c3443a007134d69b8"], # wrong outpoint hash
- [(1).to_bytes(4, "little"), 32, "798266c2e1f9a98fe5ce61f5951cbf47130743f3764cf3cbc254be129142cf9d"], # wrong outpoint index
+ [b"\xff" * 32, 0, "05030e506678f2eca8d624ffed97090ab3beadad1b51ee6e5985ba91c5720e37"], # wrong outpoint hash
+ [(1).to_bytes(4, "little"), 32, "7d29cfe2c1e242bc6f103878bb70cfffa8b4dac20dbd001ff6ce24b7de2d2399"], # wrong outpoint index
+ [b"\x81", 36, "f03939a195531f96d5dff983e294a1af62af86049fa7a19a7627246f237c03f1"], # wrong coin code VARINT((coinbase ? 1 : 0) | (height << 1))
+ [b"\x83", 36, "e4577da84590fb288c0f7967e89575e1b0aa46624669640f6f5dfef028d39930"], # another wrong coin code
]
for content, offset, wrong_hash in cases:
@@ -103,7 +105,7 @@ class AssumeutxoTest(BitcoinTestFramework):
f.write(valid_snapshot_contents[:(32 + 8 + offset)])
f.write(content)
f.write(valid_snapshot_contents[(32 + 8 + offset + len(content)):])
- expected_error(log_msg=f"[snapshot] bad snapshot content hash: expected ef45ccdca5898b6c2145e4581d2b88c56564dd389e4bd75a1aaf6961d3edd3c0, got {wrong_hash}")
+ expected_error(log_msg=f"[snapshot] bad snapshot content hash: expected 61d9c2b29a2571a5fe285fe2d8554f91f93309666fc9b8223ee96338de25ff53, got {wrong_hash}")
def run_test(self):
"""
@@ -150,7 +152,7 @@ class AssumeutxoTest(BitcoinTestFramework):
assert_equal(
dump_output['txoutset_hash'],
- 'ef45ccdca5898b6c2145e4581d2b88c56564dd389e4bd75a1aaf6961d3edd3c0')
+ '61d9c2b29a2571a5fe285fe2d8554f91f93309666fc9b8223ee96338de25ff53')
assert_equal(dump_output['nchaintx'], 300)
assert_equal(n0.getblockchaininfo()["blocks"], SNAPSHOT_BASE_HEIGHT)
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index 2ffb182946..d6c1567e64 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -293,11 +293,11 @@ class CoinStatsIndexTest(BitcoinTestFramework):
def _test_index_rejects_hash_serialized(self):
self.log.info("Test that the rpc raises if the legacy hash is passed with the index")
- msg = "hash_serialized_2 hash type cannot be queried for a specific block"
- assert_raises_rpc_error(-8, msg, self.nodes[1].gettxoutsetinfo, hash_type='hash_serialized_2', hash_or_height=111)
+ msg = "hash_serialized_3 hash type cannot be queried for a specific block"
+ assert_raises_rpc_error(-8, msg, self.nodes[1].gettxoutsetinfo, hash_type='hash_serialized_3', hash_or_height=111)
for use_index in {True, False, None}:
- assert_raises_rpc_error(-8, msg, self.nodes[1].gettxoutsetinfo, hash_type='hash_serialized_2', hash_or_height=111, use_index=use_index)
+ assert_raises_rpc_error(-8, msg, self.nodes[1].gettxoutsetinfo, hash_type='hash_serialized_3', hash_or_height=111, use_index=use_index)
def _test_init_index_after_reorg(self):
self.log.info("Test a reorg while the index is deactivated")
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index 3f94bbc9d1..afd0246209 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -85,7 +85,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
# Any of these RPC calls could throw due to node crash
self.start_node(node_index)
self.nodes[node_index].waitforblock(expected_tip)
- utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2']
+ utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_3']
return utxo_hash
except Exception:
# An exception here should mean the node is about to crash.
@@ -130,7 +130,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
If any nodes crash while updating, we'll compare utxo hashes to
ensure recovery was successful."""
- node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_2']
+ node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_3']
# Retrieve all the blocks from node3
blocks = []
@@ -172,12 +172,12 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
"""Verify that the utxo hash of each node matches node3.
Restart any nodes that crash while querying."""
- node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_2']
+ node3_utxo_hash = self.nodes[3].gettxoutsetinfo()['hash_serialized_3']
self.log.info("Verifying utxo hash matches for all nodes")
for i in range(3):
try:
- nodei_utxo_hash = self.nodes[i].gettxoutsetinfo()['hash_serialized_2']
+ nodei_utxo_hash = self.nodes[i].gettxoutsetinfo()['hash_serialized_3']
except OSError:
# probably a crash on db flushing
nodei_utxo_hash = self.restart_node(i, self.nodes[3].getbestblockhash())
diff --git a/test/functional/feature_reindex_readonly.py b/test/functional/feature_reindex_readonly.py
index 26531f472b..dd99c3c4fa 100755
--- a/test/functional/feature_reindex_readonly.py
+++ b/test/functional/feature_reindex_readonly.py
@@ -7,7 +7,6 @@
"""
import os
-import platform
import stat
import subprocess
from test_framework.test_framework import BitcoinTestFramework
@@ -34,11 +33,13 @@ class BlockstoreReindexTest(BitcoinTestFramework):
filename = self.nodes[0].chain_path / "blocks" / "blk00000.dat"
filename.chmod(stat.S_IREAD)
- used_chattr = False
- if platform.system() == "Linux":
+ undo_immutable = lambda: None
+ # Linux
+ try:
+ subprocess.run(['chattr'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
try:
subprocess.run(['chattr', '+i', filename], capture_output=True, check=True)
- used_chattr = True
+ undo_immutable = lambda: subprocess.check_call(['chattr', '-i', filename])
self.log.info("Made file immutable with chattr")
except subprocess.CalledProcessError as e:
self.log.warning(str(e))
@@ -50,15 +51,33 @@ class BlockstoreReindexTest(BitcoinTestFramework):
self.log.warning("Return early on Linux under root, because chattr failed.")
self.log.warning("This should only happen due to missing capabilities in a container.")
self.log.warning("Make sure to --cap-add LINUX_IMMUTABLE if you want to run this test.")
- return
-
- self.log.debug("Attempt to restart and reindex the node with the unwritable block file")
- with self.nodes[0].assert_debug_log(expected_msgs=['FlushStateToDisk', 'failed to open file'], unexpected_msgs=[]):
- self.nodes[0].assert_start_raises_init_error(extra_args=['-reindex', '-fastprune'],
- expected_msg="Error: A fatal internal error occurred, see debug.log for details")
+ undo_immutable = False
+ except Exception:
+ # macOS, and *BSD
+ try:
+ subprocess.run(['chflags'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ try:
+ subprocess.run(['chflags', 'uchg', filename], capture_output=True, check=True)
+ undo_immutable = lambda: subprocess.check_call(['chflags', 'nouchg', filename])
+ self.log.info("Made file immutable with chflags")
+ except subprocess.CalledProcessError as e:
+ self.log.warning(str(e))
+ if e.stdout:
+ self.log.warning(f"stdout: {e.stdout}")
+ if e.stderr:
+ self.log.warning(f"stderr: {e.stderr}")
+ if os.getuid() == 0:
+ self.log.warning("Return early on BSD under root, because chflags failed.")
+ undo_immutable = False
+ except Exception:
+ pass
- if used_chattr:
- subprocess.check_call(['chattr', '-i', filename])
+ if undo_immutable:
+ self.log.info("Attempt to restart and reindex the node with the unwritable block file")
+ with self.nodes[0].assert_debug_log(expected_msgs=['FlushStateToDisk', 'failed to open file'], unexpected_msgs=[]):
+ self.nodes[0].assert_start_raises_init_error(extra_args=['-reindex', '-fastprune'],
+ expected_msg="Error: A fatal internal error occurred, see debug.log for details")
+ undo_immutable()
filename.chmod(0o777)
diff --git a/test/functional/feature_utxo_set_hash.py b/test/functional/feature_utxo_set_hash.py
index 0f510ced89..ce2a5ab8ac 100755
--- a/test/functional/feature_utxo_set_hash.py
+++ b/test/functional/feature_utxo_set_hash.py
@@ -69,7 +69,7 @@ class UTXOSetHashTest(BitcoinTestFramework):
assert_equal(finalized[::-1].hex(), node_muhash)
self.log.info("Test deterministic UTXO set hash results")
- assert_equal(node.gettxoutsetinfo()['hash_serialized_2'], "f9aa4fb5ffd10489b9a6994e70ccf1de8a8bfa2d5f201d9857332e9954b0855d")
+ assert_equal(node.gettxoutsetinfo()['hash_serialized_3'], "d1c7fec1c0623f6793839878cbe2a531eb968b50b27edd6e2a57077a5aed6094")
assert_equal(node.gettxoutsetinfo("muhash")['muhash'], "d1725b2fe3ef43e55aa4907480aea98d406fc9e0bf8f60169e2305f1fbf5961b")
def run_test(self):
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 18a0a0c6cc..53163720bb 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -340,7 +340,7 @@ class BlockchainTest(BitcoinTestFramework):
assert size > 6400
assert size < 64000
assert_equal(len(res['bestblock']), 64)
- assert_equal(len(res['hash_serialized_2']), 64)
+ assert_equal(len(res['hash_serialized_3']), 64)
self.log.info("Test gettxoutsetinfo works for blockchain with just the genesis block")
b1hash = node.getblockhash(1)
@@ -353,7 +353,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res2['txouts'], 0)
assert_equal(res2['bogosize'], 0),
assert_equal(res2['bestblock'], node.getblockhash(0))
- assert_equal(len(res2['hash_serialized_2']), 64)
+ assert_equal(len(res2['hash_serialized_3']), 64)
self.log.info("Test gettxoutsetinfo returns the same result after invalidate/reconsider block")
node.reconsiderblock(b1hash)
@@ -365,20 +365,20 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res, res3)
self.log.info("Test gettxoutsetinfo hash_type option")
- # Adding hash_type 'hash_serialized_2', which is the default, should
+ # Adding hash_type 'hash_serialized_3', which is the default, should
# not change the result.
- res4 = node.gettxoutsetinfo(hash_type='hash_serialized_2')
+ res4 = node.gettxoutsetinfo(hash_type='hash_serialized_3')
del res4['disk_size']
assert_equal(res, res4)
# hash_type none should not return a UTXO set hash.
res5 = node.gettxoutsetinfo(hash_type='none')
- assert 'hash_serialized_2' not in res5
+ assert 'hash_serialized_3' not in res5
# hash_type muhash should return a different UTXO set hash.
res6 = node.gettxoutsetinfo(hash_type='muhash')
assert 'muhash' in res6
- assert res['hash_serialized_2'] != res6['muhash']
+ assert res['hash_serialized_3'] != res6['muhash']
# muhash should not be returned unless requested.
for r in [res, res2, res3, res4, res5]:
diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py
index f378878181..1ea6cf52d1 100755
--- a/test/functional/rpc_dumptxoutset.py
+++ b/test/functional/rpc_dumptxoutset.py
@@ -46,7 +46,7 @@ class DumptxoutsetTest(BitcoinTestFramework):
'b1bacb602eacf5fbc9a7c2ef6eeb0d229c04e98bdf0c2ea5929012cd0eae3830')
assert_equal(
- out['txoutset_hash'], '1f7e3befd45dc13ae198dfbb22869a9c5c4196f8e9ef9735831af1288033f890')
+ out['txoutset_hash'], 'a0b7baa3bf5ccbd3279728f230d7ca0c44a76e9923fca8f32dbfd08d65ea496a')
assert_equal(out['nchaintx'], 101)
# Specifying a path to an existing or invalid file will fail.
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index 286dcb5fda..aede9281d5 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -6,11 +6,15 @@
import random
import shutil
+import struct
+import time
+
from test_framework.address import (
script_to_p2sh,
key_to_p2pkh,
key_to_p2wpkh,
)
+from test_framework.bdb import BTREE_MAGIC
from test_framework.descriptors import descsum_create
from test_framework.key import ECPubKey
from test_framework.test_framework import BitcoinTestFramework
@@ -20,6 +24,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
find_vout_for_address,
+ sha256sum_file,
)
from test_framework.wallet_util import (
get_generate_key,
@@ -311,12 +316,17 @@ class WalletMigrationTest(BitcoinTestFramework):
sent_watchonly_txid = send["txid"]
self.generate(self.nodes[0], 1)
+ received_watchonly_tx_info = imports0.gettransaction(received_watchonly_txid, True)
+ received_sent_watchonly_tx_info = imports0.gettransaction(received_sent_watchonly_txid, True)
balances = imports0.getbalances()
spendable_bal = balances["mine"]["trusted"]
watchonly_bal = balances["watchonly"]["trusted"]
assert_equal(len(imports0.listtransactions(include_watchonly=True)), 4)
+ # Mock time forward a bit so we can check that tx metadata is preserved
+ self.nodes[0].setmocktime(int(time.time()) + 100)
+
# Migrate
imports0.migratewallet()
assert_equal(imports0.getwalletinfo()["descriptors"], True)
@@ -334,8 +344,12 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(watchonly_info["descriptors"], True)
self.assert_is_sqlite("imports0_watchonly")
assert_equal(watchonly_info["private_keys_enabled"], False)
- watchonly.gettransaction(received_watchonly_txid)
- watchonly.gettransaction(received_sent_watchonly_txid)
+ received_migrated_watchonly_tx_info = watchonly.gettransaction(received_watchonly_txid)
+ assert_equal(received_watchonly_tx_info["time"], received_migrated_watchonly_tx_info["time"])
+ assert_equal(received_watchonly_tx_info["timereceived"], received_migrated_watchonly_tx_info["timereceived"])
+ received_sent_migrated_watchonly_tx_info = watchonly.gettransaction(received_sent_watchonly_txid)
+ assert_equal(received_sent_watchonly_tx_info["time"], received_sent_migrated_watchonly_tx_info["time"])
+ assert_equal(received_sent_watchonly_tx_info["timereceived"], received_sent_migrated_watchonly_tx_info["timereceived"])
watchonly.gettransaction(sent_watchonly_txid)
assert_equal(watchonly.getbalance(), watchonly_bal)
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", watchonly.gettransaction, received_txid)
@@ -827,6 +841,43 @@ class WalletMigrationTest(BitcoinTestFramework):
wallet.unloadwallet()
+ def test_failed_migration_cleanup(self):
+ self.log.info("Test that a failed migration is cleaned up")
+ wallet = self.create_legacy_wallet("failed")
+
+ # Make a copy of the wallet with the solvables wallet name so that we are unable
+ # to create the solvables wallet when migrating, thus failing to migrate
+ wallet.unloadwallet()
+ solvables_path = self.nodes[0].wallets_path / "failed_solvables"
+ shutil.copytree(self.nodes[0].wallets_path / "failed", solvables_path)
+ original_shasum = sha256sum_file(solvables_path / "wallet.dat")
+
+ self.nodes[0].loadwallet("failed")
+
+ # Add a multisig so that a solvables wallet is created
+ wallet.addmultisigaddress(2, [wallet.getnewaddress(), get_generate_key().pubkey])
+ wallet.importaddress(get_generate_key().p2pkh_addr)
+
+ assert_raises_rpc_error(-4, "Failed to create database", wallet.migratewallet)
+
+ assert "failed" in self.nodes[0].listwallets()
+ assert "failed_watchonly" not in self.nodes[0].listwallets()
+ assert "failed_solvables" not in self.nodes[0].listwallets()
+
+ assert not (self.nodes[0].wallets_path / "failed_watchonly").exists()
+ # Since the file in failed_solvables is one that we put there, migration shouldn't touch it
+ assert solvables_path.exists()
+ new_shasum = sha256sum_file(solvables_path / "wallet.dat")
+ assert_equal(original_shasum, new_shasum)
+
+ wallet.unloadwallet()
+ # Check the wallet we tried to migrate is still BDB
+ with open(self.nodes[0].wallets_path / "failed" / "wallet.dat", "rb") as f:
+ data = f.read(16)
+ _, _, magic = struct.unpack("QII", data)
+ assert_equal(magic, BTREE_MAGIC)
+
+
def run_test(self):
self.generate(self.nodes[0], 101)
@@ -845,6 +896,7 @@ class WalletMigrationTest(BitcoinTestFramework):
self.test_migrate_raw_p2sh()
self.test_conflict_txs()
self.test_hybrid_pubkey()
+ self.test_failed_migration_cleanup()
if __name__ == '__main__':
WalletMigrationTest().main()