aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/functional/README.md16
-rwxr-xr-xtest/functional/bumpfee.py2
-rwxr-xr-xtest/functional/segwit.py56
-rw-r--r--test/functional/test_framework/blocktools.py64
-rwxr-xr-xtest/functional/test_runner.py23
5 files changed, 111 insertions, 50 deletions
diff --git a/test/functional/README.md b/test/functional/README.md
index 4d52751b05..d6ce490ab3 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -27,6 +27,20 @@ don't have test cases for.
`set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of
the subclass, then locally-defined helper methods, then the `run_test()` method.
+#### Naming guidelines
+
+- Name the test `<area>_test.py`, where area can be one of the following:
+ - `feature` for tests for full features that aren't wallet/mining/mempool, eg `feature_rbf.py`
+ - `interface` for tests for other interfaces (REST, ZMQ, etc), eg `interface_rest.py`
+ - `mempool` for tests for mempool behaviour, eg `mempool_reorg.py`
+ - `mining` for tests for mining features, eg `mining_prioritisetransaction.py`
+ - `p2p` for tests that explicitly test the p2p interface, eg `p2p_disconnect_ban.py`
+ - `rpc` for tests for individual RPC methods or features, eg `rpc_listtransactions.py`
+ - `wallet` for tests for wallet features, eg `wallet_keypool.py`
+- use an underscore to separate words
+ - exception: for tests for specific RPCs or command line options which don't include underscores, name the test after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py`
+- Don't use the redundant word `test` in the name, eg `interface_zmq.py`, not `interface_zmq_test.py`
+
#### General test-writing advice
- Set `self.num_nodes` to the minimum number of nodes necessary for the test.
@@ -73,7 +87,7 @@ start the networking thread. (Continue with the test logic in your existing
thread.)
- Can be used to write tests where specific P2P protocol behavior is tested.
-Examples tests are `p2p-accept-block.py`, `p2p-compactblocks.py`.
+Examples tests are `p2p-acceptblock.py`, `p2p-compactblocks.py`.
#### Comptool
diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py
index 5cbd9f5cf7..1e5620736b 100755
--- a/test/functional/bumpfee.py
+++ b/test/functional/bumpfee.py
@@ -14,7 +14,7 @@ added in the future, they should try to follow the same convention and not
make assumptions about execution order.
"""
-from segwit import send_to_witness
+from test_framework.blocktools import send_to_witness
from test_framework.test_framework import BitcoinTestFramework
from test_framework import blocktools
from test_framework.mininode import CTransaction
diff --git a/test/functional/segwit.py b/test/functional/segwit.py
index 5a4a7468e5..7d5c760ad9 100755
--- a/test/functional/segwit.py
+++ b/test/functional/segwit.py
@@ -4,10 +4,18 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the SegWit changeover logic."""
+from test_framework.address import (
+ key_to_p2sh_p2wpkh,
+ key_to_p2wpkh,
+ program_to_witness,
+ script_to_p2sh_p2wsh,
+ script_to_p2wsh,
+)
+from test_framework.blocktools import witness_script, send_to_witness
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.mininode import sha256, CTransaction, CTxIn, COutPoint, CTxOut, COIN, ToHex, FromHex
-from test_framework.address import script_to_p2sh, key_to_p2pkh, key_to_p2sh_p2wpkh, key_to_p2wpkh, script_to_p2sh_p2wsh, script_to_p2wsh, program_to_witness
+from test_framework.address import script_to_p2sh, key_to_p2pkh
from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, OP_TRUE
from io import BytesIO
@@ -16,52 +24,6 @@ NODE_2 = 2
WIT_V0 = 0
WIT_V1 = 1
-# Create a scriptPubKey corresponding to either a P2WPKH output for the
-# given pubkey, or a P2WSH output of a 1-of-1 multisig for the given
-# pubkey. Returns the hex encoding of the scriptPubKey.
-def witness_script(use_p2wsh, pubkey):
- if (use_p2wsh == False):
- # P2WPKH instead
- pubkeyhash = hash160(hex_str_to_bytes(pubkey))
- pkscript = CScript([OP_0, pubkeyhash])
- else:
- # 1-of-1 multisig
- witness_program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
- scripthash = sha256(witness_program)
- pkscript = CScript([OP_0, scripthash])
- return bytes_to_hex_str(pkscript)
-
-# Return a transaction (in hex) that spends the given utxo to a segwit output,
-# optionally wrapping the segwit output using P2SH.
-def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
- if use_p2wsh:
- program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
- addr = script_to_p2sh_p2wsh(program) if encode_p2sh else script_to_p2wsh(program)
- else:
- addr = key_to_p2sh_p2wpkh(pubkey) if encode_p2sh else key_to_p2wpkh(pubkey)
- if not encode_p2sh:
- assert_equal(node.validateaddress(addr)['scriptPubKey'], witness_script(use_p2wsh, pubkey))
- return node.createrawtransaction([utxo], {addr: amount})
-
-# Create a transaction spending a given utxo to a segwit output corresponding
-# to the given pubkey: use_p2wsh determines whether to use P2WPKH or P2WSH;
-# encode_p2sh determines whether to wrap in P2SH.
-# sign=True will have the given node sign the transaction.
-# insert_redeem_script will be added to the scriptSig, if given.
-def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
- tx_to_witness = create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount)
- if (sign):
- signed = node.signrawtransaction(tx_to_witness)
- assert("errors" not in signed or len(["errors"]) == 0)
- return node.sendrawtransaction(signed["hex"])
- else:
- if (insert_redeem_script):
- tx = FromHex(CTransaction(), tx_to_witness)
- tx.vin[0].scriptSig += CScript([hex_str_to_bytes(insert_redeem_script)])
- tx_to_witness = ToHex(tx)
-
- return node.sendrawtransaction(tx_to_witness)
-
def getutxo(txid):
utxo = {}
utxo["vout"] = 0
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 93af0037e9..642ef98a27 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -4,8 +4,24 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for manipulating blocks and transactions."""
+from .address import (
+ key_to_p2sh_p2wpkh,
+ key_to_p2wpkh,
+ script_to_p2sh_p2wsh,
+ script_to_p2wsh,
+)
from .mininode import *
-from .script import CScript, OP_TRUE, OP_CHECKSIG, OP_RETURN
+from .script import (
+ CScript,
+ OP_0,
+ OP_1,
+ OP_CHECKMULTISIG,
+ OP_CHECKSIG,
+ OP_RETURN,
+ OP_TRUE,
+ hash160,
+)
+from .util import assert_equal
# Create a block (with regtest difficulty)
def create_block(hashprev, coinbase, nTime=None):
@@ -108,3 +124,49 @@ def get_legacy_sigopcount_tx(tx, fAccurate=True):
# scriptSig might be of type bytes, so convert to CScript for the moment
count += CScript(j.scriptSig).GetSigOpCount(fAccurate)
return count
+
+# Create a scriptPubKey corresponding to either a P2WPKH output for the
+# given pubkey, or a P2WSH output of a 1-of-1 multisig for the given
+# pubkey. Returns the hex encoding of the scriptPubKey.
+def witness_script(use_p2wsh, pubkey):
+ if (use_p2wsh == False):
+ # P2WPKH instead
+ pubkeyhash = hash160(hex_str_to_bytes(pubkey))
+ pkscript = CScript([OP_0, pubkeyhash])
+ else:
+ # 1-of-1 multisig
+ witness_program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
+ scripthash = sha256(witness_program)
+ pkscript = CScript([OP_0, scripthash])
+ return bytes_to_hex_str(pkscript)
+
+# Return a transaction (in hex) that spends the given utxo to a segwit output,
+# optionally wrapping the segwit output using P2SH.
+def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
+ if use_p2wsh:
+ program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
+ addr = script_to_p2sh_p2wsh(program) if encode_p2sh else script_to_p2wsh(program)
+ else:
+ addr = key_to_p2sh_p2wpkh(pubkey) if encode_p2sh else key_to_p2wpkh(pubkey)
+ if not encode_p2sh:
+ assert_equal(node.validateaddress(addr)['scriptPubKey'], witness_script(use_p2wsh, pubkey))
+ return node.createrawtransaction([utxo], {addr: amount})
+
+# Create a transaction spending a given utxo to a segwit output corresponding
+# to the given pubkey: use_p2wsh determines whether to use P2WPKH or P2WSH;
+# encode_p2sh determines whether to wrap in P2SH.
+# sign=True will have the given node sign the transaction.
+# insert_redeem_script will be added to the scriptSig, if given.
+def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
+ tx_to_witness = create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount)
+ if (sign):
+ signed = node.signrawtransaction(tx_to_witness)
+ assert("errors" not in signed or len(["errors"]) == 0)
+ return node.sendrawtransaction(signed["hex"])
+ else:
+ if (insert_redeem_script):
+ tx = FromHex(CTransaction(), tx_to_witness)
+ tx.vin[0].scriptSig += CScript([hex_str_to_bytes(insert_redeem_script)])
+ tx_to_witness = ToHex(tx)
+
+ return node.sendrawtransaction(tx_to_witness)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 957a2bc5a7..72ad300e7e 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -272,6 +272,7 @@ def main():
sys.exit(0)
check_script_list(config["environment"]["SRCDIR"])
+ check_script_prefixes()
if not args.keepcache:
shutil.rmtree("%s/test/cache" % config["environment"]["BUILDDIR"], ignore_errors=True)
@@ -470,6 +471,28 @@ class TestResult():
return self.status != "Failed"
+def check_script_prefixes():
+ """Check that no more than `EXPECTED_VIOLATION_COUNT` of the
+ test scripts don't start with one of the allowed name prefixes."""
+ EXPECTED_VIOLATION_COUNT = 77
+
+ # LEEWAY is provided as a transition measure, so that pull-requests
+ # that introduce new tests that don't conform with the naming
+ # convention don't immediately cause the tests to fail.
+ LEEWAY = 10
+
+ good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet)_")
+ bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None]
+
+ if len(bad_script_names) < EXPECTED_VIOLATION_COUNT:
+ print("{}HURRAY!{} Number of functional tests violating naming convention reduced!".format(BOLD[1], BOLD[0]))
+ print("Consider reducing EXPECTED_VIOLATION_COUNT from %d to %d" % (EXPECTED_VIOLATION_COUNT, len(bad_script_names)))
+ elif len(bad_script_names) > EXPECTED_VIOLATION_COUNT:
+ print("INFO: %d tests not meeting naming conventions (expected %d):" % (len(bad_script_names), EXPECTED_VIOLATION_COUNT))
+ print(" %s" % ("\n ".join(sorted(bad_script_names))))
+ assert len(bad_script_names) <= EXPECTED_VIOLATION_COUNT + LEEWAY, "Too many tests not following naming convention! (%d found, expected: <= %d)" % (len(bad_script_names), EXPECTED_VIOLATION_COUNT)
+
+
def check_script_list(src_dir):
"""Check scripts directory.