aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/feature_backwards_compatibility.py14
-rwxr-xr-xtest/functional/feature_cltv.py2
-rwxr-xr-xtest/functional/feature_csv_activation.py79
-rwxr-xr-xtest/functional/feature_dersig.py5
-rwxr-xr-xtest/functional/feature_fee_estimation.py8
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py5
-rwxr-xr-xtest/functional/feature_nulldummy.py5
-rwxr-xr-xtest/functional/mempool_expiry.py100
-rwxr-xr-xtest/functional/mempool_packages.py32
-rwxr-xr-xtest/functional/p2p_invalid_block.py2
-rwxr-xr-xtest/functional/p2p_permissions.py10
-rwxr-xr-xtest/functional/p2p_segwit.py6
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py2
-rwxr-xr-xtest/functional/rpc_psbt.py22
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_address_types.py2
-rwxr-xr-xtest/functional/wallet_avoidreuse.py2
-rwxr-xr-xtest/functional/wallet_backup.py8
-rwxr-xr-xtest/fuzz/test_runner.py36
19 files changed, 282 insertions, 59 deletions
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py
index 1ac10f971a..7a6e3df702 100755
--- a/test/functional/feature_backwards_compatibility.py
+++ b/test/functional/feature_backwards_compatibility.py
@@ -122,6 +122,9 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
info = wallet.getwalletinfo()
assert info['private_keys_enabled']
assert info['keypoolsize'] > 0
+ # Use addmultisigaddress (see #18075)
+ address_18075 = wallet.addmultisigaddress(1, ["0296b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52", "037211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073"], "", "legacy")["address"]
+ assert wallet.getaddressinfo(address_18075)["solvable"]
# w1_v18: regular wallet, created with v0.18
node_v18.createwallet(wallet_name="w1_v18")
@@ -319,7 +322,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
hdkeypath = info["hdkeypath"]
pubkey = info["pubkey"]
- # Copy the wallet to the last Bitcoin Core version and open it:
+ # Copy the 0.17 wallet to the last Bitcoin Core version and open it:
node_v17.unloadwallet("u1_v17")
shutil.copytree(
os.path.join(node_v17_wallets_dir, "u1_v17"),
@@ -331,5 +334,14 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
descriptor = "wpkh([" + info["hdmasterfingerprint"] + hdkeypath[1:] + "]" + pubkey + ")"
assert_equal(info["desc"], descsum_create(descriptor))
+ # Copy the 0.19 wallet to the last Bitcoin Core version and open it:
+ shutil.copytree(
+ os.path.join(node_v19_wallets_dir, "w1_v19"),
+ os.path.join(node_master_wallets_dir, "w1_v19")
+ )
+ node_master.loadwallet("w1_v19")
+ wallet = node_master.get_wallet_rpc("w1_v19")
+ assert wallet.getaddressinfo(address_18075)["solvable"]
+
if __name__ == '__main__':
BackwardsCompatibilityTest().main()
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 2c6f2e733b..e2b347f925 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -55,7 +55,7 @@ class BIP65Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.extra_args = [[
- '-whitelist=127.0.0.1',
+ '-whitelist=noban@127.0.0.1',
'-par=1', # Use only one script thread to get the exact reject reason for testing
'-acceptnonstdtxn=1', # cltv_invalidate is nonstandard
]]
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index c2b4de54f2..a98480a6dd 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -35,6 +35,7 @@ bip112txs_vary_nSequence_9 - 16 txs with nSequence relative_locktimes of 9 evalu
bip112txs_vary_OP_CSV - 16 txs with nSequence = 10 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
bip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
bip112tx_special - test negative argument to OP_CSV
+bip112tx_emptystack - test empty stack (= no argument) OP_CSV
"""
from decimal import Decimal
from itertools import product
@@ -56,6 +57,8 @@ from test_framework.util import (
softfork_active,
)
+TESTING_TX_COUNT = 83 # Number of testing transactions: 1 BIP113 tx, 16 BIP68 txs, 66 BIP112 txs (see comments above)
+COINBASE_BLOCK_COUNT = TESTING_TX_COUNT # Number of coinbase blocks we need to generate as inputs for our txs
BASE_RELATIVE_LOCKTIME = 10
CSV_ACTIVATION_HEIGHT = 432
SEQ_DISABLE_FLAG = 1 << 31
@@ -95,6 +98,13 @@ def create_bip112special(node, input, txversion, address):
signtx.vin[0].scriptSig = CScript([-1, OP_CHECKSEQUENCEVERIFY, OP_DROP] + list(CScript(signtx.vin[0].scriptSig)))
return signtx
+def create_bip112emptystack(node, input, txversion, address):
+ tx = create_transaction(node, input, address, amount=Decimal("49.98"))
+ tx.nVersion = txversion
+ signtx = sign_transaction(node, tx)
+ signtx.vin[0].scriptSig = CScript([OP_CHECKSEQUENCEVERIFY] + list(CScript(signtx.vin[0].scriptSig)))
+ return signtx
+
def send_generic_input_tx(node, coinbases, address):
return node.sendrawtransaction(ToHex(sign_transaction(node, create_transaction(node, node.getblock(coinbases.pop())['tx'][0], address, amount=Decimal("49.99")))))
@@ -138,7 +148,12 @@ class BIP68_112_113Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
- self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4', '-addresstype=legacy']]
+ self.extra_args = [[
+ '-whitelist=noban@127.0.0.1',
+ '-blockversion=4',
+ '-addresstype=legacy',
+ '-par=1', # Use only one script thread to get the exact reject reason for testing
+ ]]
self.supports_cli = False
def skip_test_if_missing_module(self):
@@ -163,11 +178,11 @@ class BIP68_112_113Test(BitcoinTestFramework):
block.solve()
return block
- def send_blocks(self, blocks, success=True):
+ def send_blocks(self, blocks, success=True, reject_reason=None):
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
Call with success = False if the tip shouldn't advance to the most recent block."""
- self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success)
+ self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason)
def run_test(self):
self.nodes[0].add_p2p_connection(P2PDataStore())
@@ -175,15 +190,16 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.log.info("Generate blocks in the past for coinbase outputs.")
long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future
self.nodes[0].setmocktime(long_past_time - 100) # enough so that the generated blocks will still all be before long_past_time
- self.coinbase_blocks = self.nodes[0].generate(1 + 16 + 2 * 32 + 1) # 82 blocks generated for inputs
+ self.coinbase_blocks = self.nodes[0].generate(COINBASE_BLOCK_COUNT) # blocks generated for inputs
self.nodes[0].setmocktime(0) # set time back to present so yielded blocks aren't in the future as we advance last_block_time
- self.tipheight = 82 # height of the next block to build
+ self.tipheight = COINBASE_BLOCK_COUNT # height of the next block to build
self.last_block_time = long_past_time
self.tip = int(self.nodes[0].getbestblockhash(), 16)
self.nodeaddress = self.nodes[0].getnewaddress()
# Activation height is hardcoded
- test_blocks = self.generate_blocks(345)
+ # We advance to block height five below BIP112 activation for the following tests
+ test_blocks = self.generate_blocks(CSV_ACTIVATION_HEIGHT-5 - COINBASE_BLOCK_COUNT)
self.send_blocks(test_blocks)
assert not softfork_active(self.nodes[0], 'csv')
@@ -214,6 +230,8 @@ class BIP68_112_113Test(BitcoinTestFramework):
# 1 special input with -1 OP_CSV OP_DROP (actually will be prepended to spending scriptSig)
bip112specialinput = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)
+ # 1 special input with (empty stack) OP_CSV (actually will be prepended to spending scriptSig)
+ bip112emptystackinput = send_generic_input_tx(self.nodes[0],self.coinbase_blocks, self.nodeaddress)
# 1 normal input
bip113input = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)
@@ -224,7 +242,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.tip = int(inputblockhash, 16)
self.tipheight += 1
self.last_block_time += 600
- assert_equal(len(self.nodes[0].getblock(inputblockhash, True)["tx"]), 82 + 1)
+ assert_equal(len(self.nodes[0].getblock(inputblockhash, True)["tx"]), TESTING_TX_COUNT + 1)
# 2 more version 4 blocks
test_blocks = self.generate_blocks(2)
@@ -263,6 +281,9 @@ class BIP68_112_113Test(BitcoinTestFramework):
# -1 OP_CSV OP_DROP input
bip112tx_special_v1 = create_bip112special(self.nodes[0], bip112specialinput, 1, self.nodeaddress)
bip112tx_special_v2 = create_bip112special(self.nodes[0], bip112specialinput, 2, self.nodeaddress)
+ # (empty stack) OP_CSV input
+ bip112tx_emptystack_v1 = create_bip112emptystack(self.nodes[0], bip112emptystackinput, 1, self.nodeaddress)
+ bip112tx_emptystack_v2 = create_bip112emptystack(self.nodes[0], bip112emptystackinput, 2, self.nodeaddress)
self.log.info("TESTING")
@@ -270,11 +291,12 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.log.info("Test version 1 txs")
success_txs = []
- # add BIP113 tx and -1 CSV tx
+ # BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1)
success_txs.append(bip113signed1)
success_txs.append(bip112tx_special_v1)
+ success_txs.append(bip112tx_emptystack_v1)
# add BIP 68 txs
success_txs.extend(all_rlt_txs(bip68txs_v1))
# add BIP 112 with seq=10 txs
@@ -289,11 +311,12 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.log.info("Test version 2 txs")
success_txs = []
- # add BIP113 tx and -1 CSV tx
+ # BIP113 tx, -1 CSV tx and empty stack CSV tx should succeed
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2)
success_txs.append(bip113signed2)
success_txs.append(bip112tx_special_v2)
+ success_txs.append(bip112tx_emptystack_v2)
# add BIP 68 txs
success_txs.extend(all_rlt_txs(bip68txs_v2))
# add BIP 112 with seq=10 txs
@@ -320,7 +343,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2)
for bip113tx in [bip113signed1, bip113signed2]:
- self.send_blocks([self.create_test_block([bip113tx])], success=False)
+ self.send_blocks([self.create_test_block([bip113tx])], success=False, reject_reason='bad-txns-nonfinal')
# BIP 113 tests should now pass if the locktime is < MTP
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block
bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1)
@@ -352,11 +375,11 @@ class BIP68_112_113Test(BitcoinTestFramework):
# All txs without flag fail as we are at delta height = 8 < 10 and delta time = 8 * 600 < 10 * 512
bip68timetxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and tx['stf']]
for tx in bip68timetxs:
- self.send_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False, reject_reason='bad-txns-nonfinal')
bip68heighttxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and not tx['stf']]
for tx in bip68heighttxs:
- self.send_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False, reject_reason='bad-txns-nonfinal')
# Advance one block to 438
test_blocks = self.generate_blocks(1)
@@ -367,7 +390,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.send_blocks([self.create_test_block(bip68success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
for tx in bip68heighttxs:
- self.send_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False, reject_reason='bad-txns-nonfinal')
# Advance one block to 439
test_blocks = self.generate_blocks(1)
@@ -381,8 +404,11 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.log.info("BIP 112 tests")
self.log.info("Test version 1 txs")
- # -1 OP_CSV tx should fail
- self.send_blocks([self.create_test_block([bip112tx_special_v1])], success=False)
+ # -1 OP_CSV tx and (empty stack) OP_CSV tx should fail
+ self.send_blocks([self.create_test_block([bip112tx_special_v1])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Negative locktime)')
+ self.send_blocks([self.create_test_block([bip112tx_emptystack_v1])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Operation not valid with the current stack size)')
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass
success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v1 if tx['sdf']]
@@ -393,15 +419,19 @@ class BIP68_112_113Test(BitcoinTestFramework):
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV, version 1 txs should now fail
fail_txs = all_rlt_txs(bip112txs_vary_nSequence_v1)
fail_txs += all_rlt_txs(bip112txs_vary_nSequence_9_v1)
- fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]
+ fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v1 if not tx['sdf']]
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]
for tx in fail_txs:
- self.send_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Locktime requirement not satisfied)')
self.log.info("Test version 2 txs")
- # -1 OP_CSV tx should fail
- self.send_blocks([self.create_test_block([bip112tx_special_v2])], success=False)
+ # -1 OP_CSV tx and (empty stack) OP_CSV tx should fail
+ self.send_blocks([self.create_test_block([bip112tx_special_v2])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Negative locktime)')
+ self.send_blocks([self.create_test_block([bip112tx_emptystack_v2])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Operation not valid with the current stack size)')
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met)
success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if tx['sdf']]
@@ -416,18 +446,21 @@ class BIP68_112_113Test(BitcoinTestFramework):
fail_txs = all_rlt_txs(bip112txs_vary_nSequence_9_v2)
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v2 if not tx['sdf']]
for tx in fail_txs:
- self.send_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Locktime requirement not satisfied)')
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in nSequence, tx should fail
fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if tx['sdf']]
for tx in fail_txs:
- self.send_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Locktime requirement not satisfied)')
# If sequencelock types mismatch, tx should fail
fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and tx['stf']]
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]
for tx in fail_txs:
- self.send_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False,
+ reject_reason='non-mandatory-script-verify-flag (Locktime requirement not satisfied)')
# Remaining txs should pass, just test masking works properly
success_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and not tx['stf']]
@@ -445,7 +478,5 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.send_blocks([self.create_test_block(time_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
- # TODO: Test empty stack fails
-
if __name__ == '__main__':
BIP68_112_113Test().main()
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 27da49cf24..9628945a80 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -40,7 +40,10 @@ def unDERify(tx):
class BIP66Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-whitelist=127.0.0.1', '-par=1']] # Use only one script thread to get the exact log msg for testing
+ self.extra_args = [[
+ '-whitelist=noban@127.0.0.1',
+ '-par=1', # Use only one script thread to get the exact log msg for testing
+ ]]
self.setup_clean_chain = True
self.rpc_timeout = 120
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index d2d41b1206..1b33724594 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -128,11 +128,11 @@ class EstimateFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
# mine non-standard txs (e.g. txs with "dust" outputs)
- # Force fSendTrickle to true (via whitelist)
+ # Force fSendTrickle to true (via whitelist.noban)
self.extra_args = [
- ["-acceptnonstdtxn", "-whitelist=127.0.0.1"],
- ["-acceptnonstdtxn", "-whitelist=127.0.0.1", "-blockmaxweight=68000"],
- ["-acceptnonstdtxn", "-whitelist=127.0.0.1", "-blockmaxweight=32000"],
+ ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1"],
+ ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=68000"],
+ ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=32000"],
]
def skip_test_if_missing_module(self):
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index 8d200915bd..974388d798 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -140,10 +140,9 @@ class MaxUploadTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
- #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1
- self.log.info("Restarting nodes with -whitelist=127.0.0.1")
+ self.log.info("Restarting node 0 with noban permission and 1MB maxuploadtarget")
self.stop_node(0)
- self.start_node(0, ["-whitelist=127.0.0.1", "-maxuploadtarget=1"])
+ self.start_node(0, ["-whitelist=noban@127.0.0.1", "-maxuploadtarget=1"])
# Reconnect to self.nodes[0]
self.nodes[0].add_p2p_connection(TestP2PConn())
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index aaf56a42d0..9c92ee7f90 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -41,7 +41,10 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.setup_clean_chain = True
# This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through
# normal segwit activation here (and don't use the default always-on behaviour).
- self.extra_args = [['-whitelist=127.0.0.1', '-segwitheight=432', '-addresstype=legacy']]
+ self.extra_args = [[
+ '-segwitheight=432',
+ '-addresstype=legacy',
+ ]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py
new file mode 100755
index 0000000000..8b9b7b155a
--- /dev/null
+++ b/test/functional/mempool_expiry.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Tests that a mempool transaction expires after a given timeout and that its
+children are removed as well.
+
+Both the default expiry timeout defined by DEFAULT_MEMPOOL_EXPIRY and a user
+definable expiry timeout via the '-mempoolexpiry=<n>' command line argument
+(<n> is the timeout in hours) are tested.
+"""
+
+from datetime import timedelta
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ find_vout_for_address,
+)
+
+DEFAULT_MEMPOOL_EXPIRY = 336 # hours
+CUSTOM_MEMPOOL_EXPIRY = 10 # hours
+
+
+class MempoolExpiryTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def test_transaction_expiry(self, timeout):
+ """Tests that a transaction expires after the expiry timeout and its
+ children are removed as well."""
+ node = self.nodes[0]
+
+ # Send a parent transaction that will expire.
+ parent_address = node.getnewaddress()
+ parent_txid = node.sendtoaddress(parent_address, 1.0)
+
+ # Set the mocktime to the arrival time of the parent transaction.
+ entry_time = node.getmempoolentry(parent_txid)['time']
+ node.setmocktime(entry_time)
+
+ # Create child transaction spending the parent transaction
+ vout = find_vout_for_address(node, parent_txid, parent_address)
+ inputs = [{'txid': parent_txid, 'vout': vout}]
+ outputs = {node.getnewaddress(): 0.99}
+ child_raw = node.createrawtransaction(inputs, outputs)
+ child_signed = node.signrawtransactionwithwallet(child_raw)['hex']
+
+ # Let half of the timeout elapse and broadcast the child transaction.
+ half_expiry_time = entry_time + int(60 * 60 * timeout/2)
+ node.setmocktime(half_expiry_time)
+ child_txid = node.sendrawtransaction(child_signed)
+ self.log.info('Broadcast child transaction after {} hours.'.format(
+ timedelta(seconds=(half_expiry_time-entry_time))))
+
+ # Let most of the timeout elapse and check that the parent tx is still
+ # in the mempool.
+ nearly_expiry_time = entry_time + 60 * 60 * timeout - 5
+ node.setmocktime(nearly_expiry_time)
+ # Expiry of mempool transactions is only checked when a new transaction
+ # is added to the to the mempool.
+ node.sendtoaddress(node.getnewaddress(), 1.0)
+ self.log.info('Test parent tx not expired after {} hours.'.format(
+ timedelta(seconds=(nearly_expiry_time-entry_time))))
+ assert_equal(entry_time, node.getmempoolentry(parent_txid)['time'])
+
+ # Transaction should be evicted from the mempool after the expiry time
+ # has passed.
+ expiry_time = entry_time + 60 * 60 * timeout + 5
+ node.setmocktime(expiry_time)
+ # Expiry of mempool transactions is only checked when a new transaction
+ # is added to the to the mempool.
+ node.sendtoaddress(node.getnewaddress(), 1.0)
+ self.log.info('Test parent tx expiry after {} hours.'.format(
+ timedelta(seconds=(expiry_time-entry_time))))
+ assert_raises_rpc_error(-5, 'Transaction not in mempool',
+ node.getmempoolentry, parent_txid)
+
+ # The child transaction should be removed from the mempool as well.
+ self.log.info('Test child tx is evicted as well.')
+ assert_raises_rpc_error(-5, 'Transaction not in mempool',
+ node.getmempoolentry, child_txid)
+
+ def run_test(self):
+ self.log.info('Test default mempool expiry timeout of %d hours.' %
+ DEFAULT_MEMPOOL_EXPIRY)
+ self.test_transaction_expiry(DEFAULT_MEMPOOL_EXPIRY)
+
+ self.log.info('Test custom mempool expiry timeout of %d hours.' %
+ CUSTOM_MEMPOOL_EXPIRY)
+ self.restart_node(0, ['-mempoolexpiry=%d' % CUSTOM_MEMPOOL_EXPIRY])
+ self.test_transaction_expiry(CUSTOM_MEMPOOL_EXPIRY)
+
+
+if __name__ == '__main__':
+ MempoolExpiryTest().main()
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 7014105d88..a07dad18d6 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -12,6 +12,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
satoshi_round,
+ wait_until,
)
# default limits
@@ -19,13 +20,22 @@ MAX_ANCESTORS = 25
MAX_DESCENDANTS = 25
# custom limits for node1
MAX_ANCESTORS_CUSTOM = 5
+MAX_DESCENDANTS_CUSTOM = 10
+assert MAX_DESCENDANTS_CUSTOM >= MAX_ANCESTORS_CUSTOM
class MempoolPackagesTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [
- ["-maxorphantx=1000"],
- ["-maxorphantx=1000", "-limitancestorcount={}".format(MAX_ANCESTORS_CUSTOM)],
+ [
+ "-maxorphantx=1000",
+ "-whitelist=noban@127.0.0.1", # immediate tx relay
+ ],
+ [
+ "-maxorphantx=1000",
+ "-limitancestorcount={}".format(MAX_ANCESTORS_CUSTOM),
+ "-limitdescendantcount={}".format(MAX_DESCENDANTS_CUSTOM),
+ ],
]
def skip_test_if_missing_module(self):
@@ -219,9 +229,11 @@ class MempoolPackagesTest(BitcoinTestFramework):
transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})
# Sign and send up to MAX_DESCENDANT transactions chained off the parent tx
+ chain = [] # save sent txs for the purpose of checking node1's mempool later (see below)
for i in range(MAX_DESCENDANTS - 1):
utxo = transaction_package.pop(0)
(txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
+ chain.append(txid)
if utxo['txid'] is parent_transaction:
tx_children.append(txid)
for j in range(10):
@@ -238,7 +250,21 @@ class MempoolPackagesTest(BitcoinTestFramework):
utxo = transaction_package.pop(0)
assert_raises_rpc_error(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
- # TODO: check that node1's mempool is as expected
+ # Check that node1's mempool is as expected, containing:
+ # - txs from previous ancestor test (-> custom ancestor limit)
+ # - parent tx for descendant test
+ # - txs chained off parent tx (-> custom descendant limit)
+ wait_until(lambda: len(self.nodes[1].getrawmempool(False)) ==
+ MAX_ANCESTORS_CUSTOM + 1 + MAX_DESCENDANTS_CUSTOM, timeout=10)
+ mempool0 = self.nodes[0].getrawmempool(False)
+ mempool1 = self.nodes[1].getrawmempool(False)
+ assert set(mempool1).issubset(set(mempool0))
+ assert parent_transaction in mempool1
+ for tx in chain[:MAX_DESCENDANTS_CUSTOM]:
+ assert tx in mempool1
+ for tx in chain[MAX_DESCENDANTS_CUSTOM:]:
+ assert tx not in mempool1
+ # TODO: more detailed check of node1's mempool (fees etc.)
# TODO: test descendant size limits
diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py
index 905534b862..801407757f 100755
--- a/test/functional/p2p_invalid_block.py
+++ b/test/functional/p2p_invalid_block.py
@@ -22,7 +22,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
- self.extra_args = [["-whitelist=127.0.0.1"]]
+ self.extra_args = [["-whitelist=noban@127.0.0.1"]]
def run_test(self):
# Add p2p connection to node0
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index 93e2957fd0..3a7bf4bfc3 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -132,6 +132,16 @@ class P2PPermissionsTests(BitcoinTestFramework):
p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1])
wait_until(lambda: txid in self.nodes[0].getrawmempool())
+ self.log.debug("Check that node[1] will not send an invalid tx to node[0]")
+ tx.vout[0].nValue += 1
+ txid = tx.rehash()
+ p2p_rebroadcast_wallet.send_txs_and_test(
+ [tx],
+ self.nodes[1],
+ success=False,
+ reject_reason='Not relaying non-mempool transaction {} from whitelisted peer=0'.format(txid),
+ )
+
def checkpermission(self, args, expectedPermissions, whitelisted):
self.restart_node(1, args)
connect_nodes(self.nodes[0], 1)
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 3223c27e0b..ad5a124680 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -188,9 +188,9 @@ class SegWitTest(BitcoinTestFramework):
self.num_nodes = 3
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
self.extra_args = [
- ["-whitelist=127.0.0.1", "-acceptnonstdtxn=1", "-segwitheight={}".format(SEGWIT_HEIGHT)],
- ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-segwitheight={}".format(SEGWIT_HEIGHT)],
- ["-whitelist=127.0.0.1", "-acceptnonstdtxn=1", "-segwitheight=-1"]
+ ["-acceptnonstdtxn=1", "-segwitheight={}".format(SEGWIT_HEIGHT), "-whitelist=noban@127.0.0.1"],
+ ["-acceptnonstdtxn=0", "-segwitheight={}".format(SEGWIT_HEIGHT)],
+ ["-acceptnonstdtxn=1", "-segwitheight=-1"],
]
self.supports_cli = False
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 6f1ae0d3ba..c435ef24ce 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -30,7 +30,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.setup_clean_chain = True
# This test isn't testing tx relay. Set whitelist on the peers for
# instant tx relay.
- self.extra_args = [['-whitelist=127.0.0.1']] * self.num_nodes
+ self.extra_args = [['-whitelist=noban@127.0.0.1']] * self.num_nodes
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 33af819d34..3a63377545 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -193,12 +193,20 @@ class PSBTTest(BitcoinTestFramework):
psbt_orig = self.nodes[0].createpsbt([{"txid":txid1, "vout":vout1}, {"txid":txid2, "vout":vout2}], {self.nodes[0].getnewaddress():25.999})
# Update psbts, should only have data for one input and not the other
- psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']
+ psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig, False, "ALL")['psbt']
psbt1_decoded = self.nodes[0].decodepsbt(psbt1)
assert psbt1_decoded['inputs'][0] and not psbt1_decoded['inputs'][1]
- psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']
+ # Check that BIP32 path was added
+ assert "bip32_derivs" in psbt1_decoded['inputs'][0]
+ psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig, False, "ALL", False)['psbt']
psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
assert not psbt2_decoded['inputs'][0] and psbt2_decoded['inputs'][1]
+ # Check that BIP32 paths were not added
+ assert "bip32_derivs" not in psbt2_decoded['inputs'][1]
+
+ # Sign PSBTs (workaround issue #18039)
+ psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']
+ psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']
# Combine, finalize, and send the psbts
combined = self.nodes[0].combinepsbt([psbt1, psbt2])
@@ -231,16 +239,18 @@ class PSBTTest(BitcoinTestFramework):
# Same construction without optional arguments
psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}])
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
- for tx_in in decoded_psbt["tx"]["vin"]:
+ for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
+ assert "bip32_derivs" in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], 0)
# Same construction without optional arguments, for a node with -walletrbf=0
unspent1 = self.nodes[1].listunspent()[0]
psbtx_info = self.nodes[1].walletcreatefundedpsbt([{"txid":unspent1["txid"], "vout":unspent1["vout"]}], [{self.nodes[2].getnewaddress():unspent1["amount"]+1}], block_height)
decoded_psbt = self.nodes[1].decodepsbt(psbtx_info["psbt"])
- for tx_in in decoded_psbt["tx"]["vin"]:
+ for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
assert_greater_than(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
+ assert "bip32_derivs" in psbt_in
# Make sure change address wallet does not have P2SH innerscript access to results in success
# when attempting BnB coin selection
@@ -427,6 +437,10 @@ class PSBTTest(BitcoinTestFramework):
assert_equal(analysis['next'], 'creator')
assert_equal(analysis['error'], 'PSBT is not valid. Input 0 has invalid value')
+ self.log.info("PSBT with signed, but not finalized, inputs should have Finalizer as next")
+ analysis = self.nodes[0].analyzepsbt('cHNidP8BAHECAAAAAZYezcxdnbXoQCmrD79t/LzDgtUo9ERqixk8wgioAobrAAAAAAD9////AlDDAAAAAAAAFgAUy/UxxZuzZswcmFnN/E9DGSiHLUsuGPUFAAAAABYAFLsH5o0R38wXx+X2cCosTMCZnQ4baAAAAAABAR8A4fUFAAAAABYAFOBI2h5thf3+Lflb2LGCsVSZwsltIgIC/i4dtVARCRWtROG0HHoGcaVklzJUcwo5homgGkSNAnJHMEQCIGx7zKcMIGr7cEES9BR4Kdt/pzPTK3fKWcGyCJXb7MVnAiALOBgqlMH4GbC1HDh/HmylmO54fyEy4lKde7/BT/PWxwEBAwQBAAAAIgYC/i4dtVARCRWtROG0HHoGcaVklzJUcwo5homgGkSNAnIYDwVpQ1QAAIABAACAAAAAgAAAAAAAAAAAAAAiAgL+CIiB59NSCssOJRGiMYQK1chahgAaaJpIXE41Cyir+xgPBWlDVAAAgAEAAIAAAACAAQAAAAAAAAAA')
+ assert_equal(analysis['next'], 'finalizer')
+
analysis = self.nodes[0].analyzepsbt('cHNidP8BAHECAAAAAfA00BFgAm6tp86RowwH6BMImQNL5zXUcTT97XoLGz0BAAAAAAD/////AgCAgWrj0AcAFgAUKNw0x8HRctAgmvoevm4u1SbN7XL87QKVAAAAABYAFPck4gF7iL4NL4wtfRAKgQbghiTUAAAAAAABAR8A8gUqAQAAABYAFJUDtxf2PHo641HEOBOAIvFMNTr2AAAA')
assert_equal(analysis['next'], 'creator')
assert_equal(analysis['error'], 'PSBT is not valid. Output amount invalid')
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index ea8a340081..06d939afb7 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -175,6 +175,7 @@ BASE_SCRIPTS = [
'wallet_balance.py',
'feature_nulldummy.py',
'mempool_accept.py',
+ 'mempool_expiry.py',
'wallet_import_rescan.py',
'wallet_import_with_label.py',
'rpc_bind.py --ipv4',
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index f08606e622..79b6db986b 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -82,7 +82,7 @@ class AddressTypeTest(BitcoinTestFramework):
]
# whitelist all peers to speed up tx relay / mempool sync
for args in self.extra_args:
- args.append("-whitelist=127.0.0.1")
+ args.append("-whitelist=noban@127.0.0.1")
self.supports_cli = False
def skip_test_if_missing_module(self):
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index 1ca02a695c..8e2dc03ac2 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -70,7 +70,7 @@ class AvoidReuseTest(BitcoinTestFramework):
self.num_nodes = 2
# This test isn't testing txn relay/timing, so set whitelist on the
# peers for instant txn relay. This speeds up the test run time 2-3x.
- self.extra_args = [["-whitelist=127.0.0.1"]] * self.num_nodes
+ self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index 16c69f304a..fb80a06433 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -50,10 +50,10 @@ class WalletBackupTest(BitcoinTestFramework):
# 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 = [
- ["-keypool=100", "-whitelist=127.0.0.1"],
- ["-keypool=100", "-whitelist=127.0.0.1"],
- ["-keypool=100", "-whitelist=127.0.0.1"],
- ["-whitelist=127.0.0.1"]
+ ["-whitelist=noban@127.0.0.1", "-keypool=100"],
+ ["-whitelist=noban@127.0.0.1", "-keypool=100"],
+ ["-whitelist=noban@127.0.0.1", "-keypool=100"],
+ ["-whitelist=noban@127.0.0.1"],
]
self.rpc_timeout = 120
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 61c3e700c5..1a74c67503 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -21,6 +21,7 @@ FUZZERS_MISSING_CORPORA = [
"block_file_info_deserialize",
"block_filter_deserialize",
"block_header_and_short_txids_deserialize",
+ "bloom_filter",
"decode_tx",
"fee_rate_deserialize",
"flat_file_pos_deserialize",
@@ -29,6 +30,7 @@ FUZZERS_MISSING_CORPORA = [
"key_origin_info_deserialize",
"merkle_block_deserialize",
"out_point_deserialize",
+ "p2p_transport_deserializer",
"parse_hd_keypath",
"parse_numbers",
"parse_script",
@@ -39,6 +41,7 @@ FUZZERS_MISSING_CORPORA = [
"psbt_input_deserialize",
"psbt_output_deserialize",
"pub_key_deserialize",
+ "rolling_bloom_filter",
"script_deserialize",
"strprintf",
"sub_net_deserialize",
@@ -47,6 +50,7 @@ FUZZERS_MISSING_CORPORA = [
"tx_out",
]
+
def main():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
@@ -64,7 +68,12 @@ def main():
parser.add_argument(
'--valgrind',
action='store_true',
- help='If true, run fuzzing binaries under the valgrind memory error detector. Valgrind 3.14 or later required.',
+ help='If true, run fuzzing binaries under the valgrind memory error detector',
+ )
+ parser.add_argument(
+ '-x',
+ '--exclude',
+ help="A comma-separated list of targets to exclude",
)
parser.add_argument(
'seed_dir',
@@ -100,7 +109,7 @@ def main():
logging.error("No fuzz targets found")
sys.exit(1)
- logging.info("Fuzz targets found: {}".format(test_list_all))
+ logging.debug("{} fuzz target(s) found: {}".format(len(test_list_all), " ".join(sorted(test_list_all))))
args.target = args.target or test_list_all # By default run all
test_list_error = list(set(args.target).difference(set(test_list_all)))
@@ -109,7 +118,15 @@ def main():
test_list_selection = list(set(test_list_all).intersection(set(args.target)))
if not test_list_selection:
logging.error("No fuzz targets selected")
- logging.info("Fuzz targets selected: {}".format(test_list_selection))
+ if args.exclude:
+ for excluded_target in args.exclude.split(","):
+ if excluded_target not in test_list_selection:
+ logging.error("Target \"{}\" not found in current target list.".format(excluded_target))
+ continue
+ test_list_selection.remove(excluded_target)
+ test_list_selection.sort()
+
+ logging.info("{} of {} detected fuzz target(s) selected: {}".format(len(test_list_selection), len(test_list_all), " ".join(test_list_selection)))
try:
help_output = subprocess.run(
@@ -146,16 +163,23 @@ def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind):
args = [
os.path.join(build_dir, 'src', 'test', 'fuzz', t),
'-runs=1',
- '-detect_leaks=0',
corpus_path,
]
if use_valgrind:
- args = ['valgrind', '--quiet', '--error-exitcode=1', '--exit-on-first-error=yes'] + args
+ args = ['valgrind', '--quiet', '--error-exitcode=1'] + args
logging.debug('Run {} with args {}'.format(t, args))
result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True)
output = result.stderr
logging.debug('Output: {}'.format(output))
- result.check_returncode()
+ try:
+ result.check_returncode()
+ except subprocess.CalledProcessError as e:
+ if e.stdout:
+ logging.info(e.stdout)
+ if e.stderr:
+ logging.info(e.stderr)
+ logging.info("Target \"{}\" failed with exit code {}: {}".format(t, e.returncode, " ".join(args)))
+ sys.exit(1)
if not export_coverage:
continue
for l in output.splitlines():