aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/feature_assumeutxo.py56
-rwxr-xr-xtest/functional/feature_coinstatsindex.py6
-rwxr-xr-xtest/functional/feature_dbcrash.py8
-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/rpc_net.py9
-rwxr-xr-xtest/functional/test_framework/wallet_util.py19
-rwxr-xr-xtest/functional/wallet_createwallet.py60
-rwxr-xr-xtest/functional/wallet_descriptor.py25
-rwxr-xr-xtest/functional/wallet_dump.py41
-rwxr-xr-xtest/functional/wallet_encryption.py22
-rwxr-xr-xtest/functional/wallet_fundrawtransaction.py48
-rwxr-xr-xtest/functional/wallet_keypool.py56
-rwxr-xr-xtest/fuzz/test_runner.py16
-rwxr-xr-xtest/lint/lint-shell.py2
16 files changed, 206 insertions, 178 deletions
diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py
index c900736ae9..9c265649d5 100755
--- a/test/functional/feature_assumeutxo.py
+++ b/test/functional/feature_assumeutxo.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
+# Copyright (c) 2021-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test for assumeutxo, a means of quickly bootstrapping a node using
@@ -17,10 +17,8 @@ The assumeutxo value generated and used here is committed to in
Interesting test cases could be loading an assumeutxo snapshot file with:
-- TODO: An invalid hash
-- TODO: Valid hash but invalid snapshot file (bad coin height or truncated file or
+- TODO: Valid hash but invalid snapshot file (bad coin height or
bad other serialization)
-- TODO: Valid snapshot file, but referencing an unknown block
- TODO: Valid snapshot file, but referencing a snapshot block that turns out to be
invalid, or has an invalid parent
- TODO: Valid snapshot file and snapshot block, but the block is not on the
@@ -40,7 +38,6 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-import struct
START_HEIGHT = 199
SNAPSHOT_BASE_HEIGHT = 299
@@ -72,30 +69,43 @@ class AssumeutxoTest(BitcoinTestFramework):
valid_snapshot_contents = f.read()
bad_snapshot_path = valid_snapshot_path + '.mod'
+ def expected_error(log_msg="", rpc_details=""):
+ with self.nodes[1].assert_debug_log([log_msg]):
+ assert_raises_rpc_error(-32603, f"Unable to load UTXO snapshot{rpc_details}", self.nodes[1].loadtxoutset, bad_snapshot_path)
+
self.log.info(" - snapshot file refering to a block that is not in the assumeutxo parameters")
- # we can only test this with a block that is already known, as otherwise the `loadtxoutset` RPC
- # would time out (waiting to see the hash in the headers chain), rather than error immediately
- bad_snapshot_height = SNAPSHOT_BASE_HEIGHT - 1
- with open(bad_snapshot_path, 'wb') as f:
- bad_snapshot_block_hash = self.nodes[0].getblockhash(bad_snapshot_height)
- # block hash of the snapshot base is stored right at the start (first 32 bytes)
- f.write(bytes.fromhex(bad_snapshot_block_hash)[::-1] + valid_snapshot_contents[32:])
-
- expected_log = f"assumeutxo height in snapshot metadata not recognized ({bad_snapshot_height}) - refusing to load snapshot"
- with self.nodes[1].assert_debug_log([expected_log]):
- assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", self.nodes[1].loadtxoutset, bad_snapshot_path)
+ prev_block_hash = self.nodes[0].getblockhash(SNAPSHOT_BASE_HEIGHT - 1)
+ bogus_block_hash = "0" * 64 # Represents any unknown block hash
+ for bad_block_hash in [bogus_block_hash, prev_block_hash]:
+ with open(bad_snapshot_path, 'wb') as f:
+ # block hash of the snapshot base is stored right at the start (first 32 bytes)
+ f.write(bytes.fromhex(bad_block_hash)[::-1] + valid_snapshot_contents[32:])
+ error_details = f", assumeutxo block hash in snapshot metadata not recognized ({bad_block_hash})"
+ expected_error(rpc_details=error_details)
self.log.info(" - snapshot file with wrong number of coins")
- valid_num_coins = struct.unpack("<I", valid_snapshot_contents[32:32 + 4])[0]
+ valid_num_coins = int.from_bytes(valid_snapshot_contents[32:32 + 8], "little")
for off in [-1, +1]:
with open(bad_snapshot_path, 'wb') as f:
f.write(valid_snapshot_contents[:32])
- f.write(struct.pack("<I", valid_num_coins + off))
- f.write(valid_snapshot_contents[32 + 4:])
+ f.write((valid_num_coins + off).to_bytes(8, "little"))
+ f.write(valid_snapshot_contents[32 + 8:])
+ expected_error(log_msg=f"bad snapshot - coins left over after deserializing 298 coins" if off == -1 else f"bad snapshot format or truncated snapshot after deserializing 299 coins")
+
+ self.log.info(" - snapshot file with alternated UTXO data")
+ cases = [
+ [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
+ ]
- expected_log = f"bad snapshot - coins left over after deserializing 298 coins" if off == -1 else f"bad snapshot format or truncated snapshot after deserializing 299 coins"
- with self.nodes[1].assert_debug_log([expected_log]):
- assert_raises_rpc_error(-32603, "Unable to load UTXO snapshot", self.nodes[1].loadtxoutset, bad_snapshot_path)
+ for content, offset, wrong_hash in cases:
+ with open(bad_snapshot_path, "wb") as f:
+ 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 61d9c2b29a2571a5fe285fe2d8554f91f93309666fc9b8223ee96338de25ff53, got {wrong_hash}")
def run_test(self):
"""
@@ -142,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_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/rpc_net.py b/test/functional/rpc_net.py
index 44b86662ea..50a022fc7e 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2022 The Bitcoin Core developers
+# Copyright (c) 2017-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC calls related to net.
@@ -315,9 +315,11 @@ class NetTest(BitcoinTestFramework):
self.log.debug("Test that adding an address with invalid port fails")
assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=-1)
- assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress,address="1.2.3.4", port=65536)
+ assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=65536)
self.log.debug("Test that adding a valid address to the tried table succeeds")
+ self.addr_time = int(time.time())
+ node.setmocktime(self.addr_time)
assert_equal(node.addpeeraddress(address="1.2.3.4", tried=True, port=8333), {"success": True})
with node.assert_debug_log(expected_msgs=["CheckAddrman: new 0, tried 1, total 1 started"]):
addrs = node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks
@@ -402,8 +404,7 @@ class NetTest(BitcoinTestFramework):
assert_equal(result["network"], expected["network"])
assert_equal(result["source"], expected["source"])
assert_equal(result["source_network"], expected["source_network"])
- # To avoid failing on slow test runners, use a 10s vspan here.
- assert_approx(result["time"], time.time(), vspan=10)
+ assert_equal(result["time"], self.addr_time)
def check_getrawaddrman_entries(expected):
"""Utility to compare a getrawaddrman result with expected addrman contents"""
diff --git a/test/functional/test_framework/wallet_util.py b/test/functional/test_framework/wallet_util.py
index 319f120297..44811918bf 100755
--- a/test/functional/test_framework/wallet_util.py
+++ b/test/functional/test_framework/wallet_util.py
@@ -122,3 +122,22 @@ def generate_keypair(compressed=True, wif=False):
if wif:
privkey = bytes_to_wif(privkey.get_bytes(), compressed)
return privkey, pubkey
+
+class WalletUnlock():
+ """
+ A context manager for unlocking a wallet with a passphrase and automatically locking it afterward.
+ """
+
+ MAXIMUM_TIMEOUT = 999000
+
+ def __init__(self, wallet, passphrase, timeout=MAXIMUM_TIMEOUT):
+ self.wallet = wallet
+ self.passphrase = passphrase
+ self.timeout = timeout
+
+ def __enter__(self):
+ self.wallet.walletpassphrase(self.passphrase, self.timeout)
+
+ def __exit__(self, *args):
+ _ = args
+ self.wallet.walletlock()
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index eb83e11f36..8e07021e03 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -12,7 +12,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-from test_framework.wallet_util import generate_keypair
+from test_framework.wallet_util import generate_keypair, WalletUnlock
EMPTY_PASSPHRASE_MSG = "Empty string given as passphrase, wallet will not be encrypted."
@@ -108,24 +108,24 @@ class CreateWalletTest(BitcoinTestFramework):
w4.encryptwallet('pass')
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress)
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress)
- # Now set a seed and it should work. Wallet should also be encrypted
- w4.walletpassphrase("pass", 999000)
- if self.options.descriptors:
- w4.importdescriptors([{
- 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'),
- 'timestamp': 'now',
- 'active': True
- },
- {
- 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'),
- 'timestamp': 'now',
- 'active': True,
- 'internal': True
- }])
- else:
- w4.sethdseed()
- w4.getnewaddress()
- w4.getrawchangeaddress()
+ with WalletUnlock(w4, "pass"):
+ # Now set a seed and it should work. Wallet should also be encrypted
+ if self.options.descriptors:
+ w4.importdescriptors([{
+ 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'),
+ 'timestamp': 'now',
+ 'active': True
+ },
+ {
+ 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'),
+ 'timestamp': 'now',
+ 'active': True,
+ 'internal': True
+ }])
+ else:
+ w4.sethdseed()
+ w4.getnewaddress()
+ w4.getrawchangeaddress()
self.log.info("Test blank creation with privkeys disabled and then encryption")
self.nodes[0].createwallet(wallet_name='w5', disable_private_keys=True, blank=True)
@@ -142,23 +142,23 @@ class CreateWalletTest(BitcoinTestFramework):
self.nodes[0].createwallet(wallet_name='wblank', disable_private_keys=False, blank=True, passphrase='thisisapassphrase')
wblank = node.get_wallet_rpc('wblank')
assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wblank.signmessage, "needanargument", "test")
- wblank.walletpassphrase("thisisapassphrase", 999000)
- assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getnewaddress)
- assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getrawchangeaddress)
+ with WalletUnlock(wblank, "thisisapassphrase"):
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getrawchangeaddress)
self.log.info('Test creating a new encrypted wallet.')
# Born encrypted wallet is created (has keys)
self.nodes[0].createwallet(wallet_name='w6', disable_private_keys=False, blank=False, passphrase='thisisapassphrase')
w6 = node.get_wallet_rpc('w6')
assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", w6.signmessage, "needanargument", "test")
- w6.walletpassphrase("thisisapassphrase", 999000)
- w6.signmessage(w6.getnewaddress('', 'legacy'), "test")
- w6.keypoolrefill(1)
- # There should only be 1 key for legacy, 3 for descriptors
- walletinfo = w6.getwalletinfo()
- keys = 4 if self.options.descriptors else 1
- assert_equal(walletinfo['keypoolsize'], keys)
- assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
+ with WalletUnlock(w6, "thisisapassphrase"):
+ w6.signmessage(w6.getnewaddress('', 'legacy'), "test")
+ w6.keypoolrefill(1)
+ # There should only be 1 key for legacy, 3 for descriptors
+ walletinfo = w6.getwalletinfo()
+ keys = 4 if self.options.descriptors else 1
+ assert_equal(walletinfo['keypoolsize'], keys)
+ assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
# Allow empty passphrase, but there should be a warning
resp = self.nodes[0].createwallet(wallet_name='w7', disable_private_keys=False, blank=False, passphrase='')
assert_equal(resp["warnings"], [EMPTY_PASSPHRASE_MSG] if self.options.descriptors else [EMPTY_PASSPHRASE_MSG, LEGACY_WALLET_MSG])
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index c220675eb6..e9321b72e2 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -15,6 +15,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error
)
+from test_framework.wallet_util import WalletUnlock
class WalletDescriptorTest(BitcoinTestFramework):
@@ -128,11 +129,10 @@ class WalletDescriptorTest(BitcoinTestFramework):
# Encrypt wallet 0
send_wrpc.encryptwallet('pass')
- send_wrpc.walletpassphrase("pass", 999000)
- addr = send_wrpc.getnewaddress()
- info2 = send_wrpc.getaddressinfo(addr)
- assert info1['hdmasterfingerprint'] != info2['hdmasterfingerprint']
- send_wrpc.walletlock()
+ with WalletUnlock(send_wrpc, "pass"):
+ addr = send_wrpc.getnewaddress()
+ info2 = send_wrpc.getaddressinfo(addr)
+ assert info1['hdmasterfingerprint'] != info2['hdmasterfingerprint']
assert 'hdmasterfingerprint' in send_wrpc.getaddressinfo(send_wrpc.getnewaddress())
info3 = send_wrpc.getaddressinfo(addr)
assert_equal(info2['desc'], info3['desc'])
@@ -142,14 +142,13 @@ class WalletDescriptorTest(BitcoinTestFramework):
send_wrpc.getnewaddress()
self.log.info("Test that unlock is needed when deriving only hardened keys in an encrypted wallet")
- send_wrpc.walletpassphrase("pass", 999000)
- send_wrpc.importdescriptors([{
- "desc": "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h)#y4dfsj7n",
- "timestamp": "now",
- "range": [0,10],
- "active": True
- }])
- send_wrpc.walletlock()
+ with WalletUnlock(send_wrpc, "pass"):
+ send_wrpc.importdescriptors([{
+ "desc": "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/*h)#y4dfsj7n",
+ "timestamp": "now",
+ "range": [0,10],
+ "active": True
+ }])
# Exhaust keypool of 100
for _ in range(100):
send_wrpc.getnewaddress(address_type='bech32')
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index fdce9739eb..f50aae0c53 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -11,6 +11,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
+from test_framework.wallet_util import WalletUnlock
def read_dump(file_name, addrs, script_addrs, hd_master_addr_old):
@@ -172,26 +173,26 @@ class WalletDumpTest(BitcoinTestFramework):
# encrypt wallet, restart, unlock and dump
self.nodes[0].encryptwallet('test')
- self.nodes[0].walletpassphrase("test", 999000)
- # Should be a no-op:
- self.nodes[0].keypoolrefill()
- self.nodes[0].dumpwallet(wallet_enc_dump)
-
- found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, _ = \
- read_dump(wallet_enc_dump, addrs, [multisig_addr], hd_master_addr_unenc)
- assert '# End of dump' in found_comments # Check that file is not corrupt
- assert_equal(dump_time_str, next(c for c in found_comments if c.startswith('# * Created on')))
- assert_equal(dump_best_block_1, next(c for c in found_comments if c.startswith('# * Best block')))
- assert_equal(dump_best_block_2, next(c for c in found_comments if c.startswith('# mined on')))
- assert_equal(found_legacy_addr, test_addr_count) # all keys must be in the dump
- assert_equal(found_p2sh_segwit_addr, test_addr_count) # all keys must be in the dump
- assert_equal(found_bech32_addr, test_addr_count) # all keys must be in the dump
- assert_equal(found_script_addr, 1)
- assert_equal(found_addr_chg, 90 * 2) # old reserve keys are marked as change now
- assert_equal(found_addr_rsv, 90 * 2)
-
- # Overwriting should fail
- assert_raises_rpc_error(-8, "already exists", lambda: self.nodes[0].dumpwallet(wallet_enc_dump))
+ with WalletUnlock(self.nodes[0], "test"):
+ # Should be a no-op:
+ self.nodes[0].keypoolrefill()
+ self.nodes[0].dumpwallet(wallet_enc_dump)
+
+ found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, _ = \
+ read_dump(wallet_enc_dump, addrs, [multisig_addr], hd_master_addr_unenc)
+ assert '# End of dump' in found_comments # Check that file is not corrupt
+ assert_equal(dump_time_str, next(c for c in found_comments if c.startswith('# * Created on')))
+ assert_equal(dump_best_block_1, next(c for c in found_comments if c.startswith('# * Best block')))
+ assert_equal(dump_best_block_2, next(c for c in found_comments if c.startswith('# mined on')))
+ assert_equal(found_legacy_addr, test_addr_count) # all keys must be in the dump
+ assert_equal(found_p2sh_segwit_addr, test_addr_count) # all keys must be in the dump
+ assert_equal(found_bech32_addr, test_addr_count) # all keys must be in the dump
+ assert_equal(found_script_addr, 1)
+ assert_equal(found_addr_chg, 90 * 2) # old reserve keys are marked as change now
+ assert_equal(found_addr_rsv, 90 * 2)
+
+ # Overwriting should fail
+ assert_raises_rpc_error(-8, "already exists", lambda: self.nodes[0].dumpwallet(wallet_enc_dump))
# Restart node with new wallet, and test importwallet
self.restart_node(0)
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index e8381ba8f2..b30634010d 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -11,6 +11,7 @@ from test_framework.util import (
assert_raises_rpc_error,
assert_equal,
)
+from test_framework.wallet_util import WalletUnlock
class WalletEncryptionTest(BitcoinTestFramework):
@@ -59,19 +60,17 @@ class WalletEncryptionTest(BitcoinTestFramework):
assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase + "wrong", 10)
# Test walletlock
- self.nodes[0].walletpassphrase(passphrase, 999000)
- sig = self.nodes[0].signmessage(address, msg)
- assert self.nodes[0].verifymessage(address, sig, msg)
- self.nodes[0].walletlock()
+ with WalletUnlock(self.nodes[0], passphrase):
+ sig = self.nodes[0].signmessage(address, msg)
+ assert self.nodes[0].verifymessage(address, sig, msg)
assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].signmessage, address, msg)
# Test passphrase changes
self.nodes[0].walletpassphrasechange(passphrase, passphrase2)
assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase, 10)
- self.nodes[0].walletpassphrase(passphrase2, 999000)
- sig = self.nodes[0].signmessage(address, msg)
- assert self.nodes[0].verifymessage(address, sig, msg)
- self.nodes[0].walletlock()
+ with WalletUnlock(self.nodes[0], passphrase2):
+ sig = self.nodes[0].signmessage(address, msg)
+ assert self.nodes[0].verifymessage(address, sig, msg)
# Test timeout bounds
assert_raises_rpc_error(-8, "Timeout cannot be negative.", self.nodes[0].walletpassphrase, passphrase2, -10)
@@ -97,10 +96,9 @@ class WalletEncryptionTest(BitcoinTestFramework):
self.nodes[0].walletpassphrasechange(passphrase2, passphrase_with_nulls)
# walletpassphrasechange should not stop at null characters
assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase_with_nulls.partition("\0")[0], 10)
- self.nodes[0].walletpassphrase(passphrase_with_nulls, 999000)
- sig = self.nodes[0].signmessage(address, msg)
- assert self.nodes[0].verifymessage(address, sig, msg)
- self.nodes[0].walletlock()
+ with WalletUnlock(self.nodes[0], passphrase_with_nulls):
+ sig = self.nodes[0].signmessage(address, msg)
+ assert self.nodes[0].verifymessage(address, sig, msg)
if __name__ == '__main__':
diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py
index 9b125d998b..77611649ac 100755
--- a/test/functional/wallet_fundrawtransaction.py
+++ b/test/functional/wallet_fundrawtransaction.py
@@ -25,7 +25,7 @@ from test_framework.util import (
find_vout_for_address,
get_fee,
)
-from test_framework.wallet_util import generate_keypair
+from test_framework.wallet_util import generate_keypair, WalletUnlock
ERR_NOT_ENOUGH_PRESET_INPUTS = "The preselected coins total amount does not cover the transaction target. " \
"Please allow other inputs to be automatically selected or include more coins manually"
@@ -581,19 +581,18 @@ class RawTransactionsTest(BitcoinTestFramework):
wallet.encryptwallet("test")
if self.options.descriptors:
- wallet.walletpassphrase("test", 999000)
- wallet.importdescriptors([{
- 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
- 'timestamp': 'now',
- 'active': True
- },
- {
- 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
- 'timestamp': 'now',
- 'active': True,
- 'internal': True
- }])
- wallet.walletlock()
+ with WalletUnlock(wallet, "test"):
+ wallet.importdescriptors([{
+ 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
+ 'timestamp': 'now',
+ 'active': True
+ },
+ {
+ 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
+ 'timestamp': 'now',
+ 'active': True,
+ 'internal': True
+ }])
# Drain the keypool.
wallet.getnewaddress()
@@ -619,9 +618,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", wallet.fundrawtransaction, rawtx)
# Refill the keypool.
- wallet.walletpassphrase("test", 999000)
- wallet.keypoolrefill(8) #need to refill the keypool to get an internal change address
- wallet.walletlock()
+ with WalletUnlock(wallet, "test"):
+ wallet.keypoolrefill(8) #need to refill the keypool to get an internal change address
assert_raises_rpc_error(-13, "walletpassphrase", wallet.sendtoaddress, self.nodes[0].getnewaddress(), 1.2)
@@ -634,16 +632,16 @@ class RawTransactionsTest(BitcoinTestFramework):
assert fundedTx["changepos"] != -1
# Now we need to unlock.
- wallet.walletpassphrase("test", 999000)
- signedTx = wallet.signrawtransactionwithwallet(fundedTx['hex'])
- wallet.sendrawtransaction(signedTx['hex'])
- self.generate(self.nodes[1], 1)
+ with WalletUnlock(wallet, "test"):
+ signedTx = wallet.signrawtransactionwithwallet(fundedTx['hex'])
+ wallet.sendrawtransaction(signedTx['hex'])
+ self.generate(self.nodes[1], 1)
- # Make sure funds are received at node1.
- assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance())
+ # Make sure funds are received at node1.
+ assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance())
- # Restore pre-test wallet state
- wallet.sendall(recipients=[df_wallet.getnewaddress(), df_wallet.getnewaddress(), df_wallet.getnewaddress()])
+ # Restore pre-test wallet state
+ wallet.sendall(recipients=[df_wallet.getnewaddress(), df_wallet.getnewaddress(), df_wallet.getnewaddress()])
wallet.unloadwallet()
self.generate(self.nodes[1], 1)
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 0ba8a46bae..d2341fb12e 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -9,6 +9,7 @@ from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
+from test_framework.wallet_util import WalletUnlock
class KeyPoolTest(BitcoinTestFramework):
def add_options(self, parser):
@@ -85,9 +86,8 @@ class KeyPoolTest(BitcoinTestFramework):
assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
# put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min)
- nodes[0].walletpassphrase("test", 999000)
- nodes[0].keypoolrefill(6)
- nodes[0].walletlock()
+ with WalletUnlock(nodes[0], 'test'):
+ nodes[0].keypoolrefill(6)
wi = nodes[0].getwalletinfo()
if self.options.descriptors:
assert_equal(wi['keypoolsize_hd_internal'], 24)
@@ -131,29 +131,29 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].getnewaddress()
assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].getnewaddress)
- nodes[0].walletpassphrase("test", 999000)
- nodes[0].keypoolrefill(100)
- wi = nodes[0].getwalletinfo()
- if self.options.descriptors:
- assert_equal(wi['keypoolsize_hd_internal'], 400)
- assert_equal(wi['keypoolsize'], 400)
- else:
- assert_equal(wi['keypoolsize_hd_internal'], 100)
- assert_equal(wi['keypoolsize'], 100)
-
- if not self.options.descriptors:
- # Check that newkeypool entirely flushes the keypool
- start_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
- start_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
- # flush keypool and get new addresses
- nodes[0].newkeypool()
- end_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
- end_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
- # The new keypath index should be 100 more than the old one
- new_index = int(start_keypath.rsplit('/', 1)[1][:-1]) + 100
- new_change_index = int(start_change_keypath.rsplit('/', 1)[1][:-1]) + 100
- assert_equal(end_keypath, "m/0'/0'/" + str(new_index) + "'")
- assert_equal(end_change_keypath, "m/0'/1'/" + str(new_change_index) + "'")
+ with WalletUnlock(nodes[0], 'test'):
+ nodes[0].keypoolrefill(100)
+ wi = nodes[0].getwalletinfo()
+ if self.options.descriptors:
+ assert_equal(wi['keypoolsize_hd_internal'], 400)
+ assert_equal(wi['keypoolsize'], 400)
+ else:
+ assert_equal(wi['keypoolsize_hd_internal'], 100)
+ assert_equal(wi['keypoolsize'], 100)
+
+ if not self.options.descriptors:
+ # Check that newkeypool entirely flushes the keypool
+ start_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
+ start_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
+ # flush keypool and get new addresses
+ nodes[0].newkeypool()
+ end_keypath = nodes[0].getaddressinfo(nodes[0].getnewaddress())['hdkeypath']
+ end_change_keypath = nodes[0].getaddressinfo(nodes[0].getrawchangeaddress())['hdkeypath']
+ # The new keypath index should be 100 more than the old one
+ new_index = int(start_keypath.rsplit('/', 1)[1][:-1]) + 100
+ new_change_index = int(start_change_keypath.rsplit('/', 1)[1][:-1]) + 100
+ assert_equal(end_keypath, "m/0'/0'/" + str(new_index) + "'")
+ assert_equal(end_change_keypath, "m/0'/1'/" + str(new_change_index) + "'")
# create a blank wallet
nodes[0].createwallet(wallet_name='w2', blank=True, disable_private_keys=True)
@@ -170,9 +170,9 @@ class KeyPoolTest(BitcoinTestFramework):
else:
res = w2.importmulti([{'desc': desc, 'timestamp': 'now'}])
assert_equal(res[0]['success'], True)
- w1.walletpassphrase("test", 999000)
- res = w1.sendtoaddress(address=address, amount=0.00010000)
+ with WalletUnlock(w1, 'test'):
+ res = w1.sendtoaddress(address=address, amount=0.00010000)
self.generate(nodes[0], 1)
destination = addr.pop()
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 446a4551da..ec74f7705c 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -69,7 +69,8 @@ def main():
)
parser.add_argument(
'--m_dir',
- help='Merge inputs from this directory into the corpus_dir.',
+ action="append",
+ help="Merge inputs from these directories into the corpus_dir.",
)
parser.add_argument(
'-g',
@@ -176,7 +177,7 @@ def main():
test_list=test_list_selection,
src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
- merge_dir=args.m_dir,
+ merge_dirs=[Path(m_dir) for m_dir in args.m_dir],
)
return
@@ -270,12 +271,13 @@ def generate_corpus(*, fuzz_pool, src_dir, build_dir, corpus_dir, targets):
future.result()
-def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir):
- logging.info("Merge the inputs from the passed dir into the corpus_dir. Passed dir {}".format(merge_dir))
+def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dirs):
+ logging.info(f"Merge the inputs from the passed dir into the corpus_dir. Passed dirs {merge_dirs}")
jobs = []
for t in test_list:
args = [
os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
+ '-rss_limit_mb=8000',
'-set_cover_merge=1',
# set_cover_merge is used instead of -merge=1 to reduce the overall
# size of the qa-assets git repository a bit, but more importantly,
@@ -289,10 +291,10 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir)
# [0] https://github.com/google/oss-fuzz/issues/1406#issuecomment-387790487
# [1] https://github.com/bitcoin-core/qa-assets/issues/130#issuecomment-1749075891
os.path.join(corpus, t),
- os.path.join(merge_dir, t),
- ]
+ ] + [str(m_dir / t) for m_dir in merge_dirs]
os.makedirs(os.path.join(corpus, t), exist_ok=True)
- os.makedirs(os.path.join(merge_dir, t), exist_ok=True)
+ for m_dir in merge_dirs:
+ (m_dir / t).mkdir(exist_ok=True)
def job(t, args):
output = 'Run {} with args {}\n'.format(t, " ".join(args))
diff --git a/test/lint/lint-shell.py b/test/lint/lint-shell.py
index db84ca3d39..7fb78894af 100755
--- a/test/lint/lint-shell.py
+++ b/test/lint/lint-shell.py
@@ -70,7 +70,7 @@ def main():
reg = re.compile(r'src/[leveldb,secp256k1,minisketch]')
def should_exclude(fname: str) -> bool:
- return bool(reg.match(fname)) or 'test_utxo_snapshots.sh' in fname
+ return bool(reg.match(fname))
# remove everything that doesn't match this regex
files[:] = [file for file in files if not should_exclude(file)]