aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rw-r--r--test/functional/README.md7
-rwxr-xr-xtest/functional/combine_logs.py78
-rw-r--r--test/functional/data/rpc_psbt.json11
-rwxr-xr-xtest/functional/example_test.py18
-rwxr-xr-xtest/functional/feature_bip68_sequence.py3
-rwxr-xr-xtest/functional/feature_block.py99
-rwxr-xr-xtest/functional/feature_blocksdir.py2
-rwxr-xr-xtest/functional/feature_cltv.py43
-rwxr-xr-xtest/functional/feature_config_args.py37
-rwxr-xr-xtest/functional/feature_csv_activation.py7
-rwxr-xr-xtest/functional/feature_dbcrash.py4
-rwxr-xr-xtest/functional/feature_dersig.py41
-rwxr-xr-xtest/functional/feature_fee_estimation.py6
-rwxr-xr-xtest/functional/feature_filelock.py36
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py3
-rwxr-xr-xtest/functional/feature_minchainwork.py5
-rwxr-xr-xtest/functional/feature_notifications.py80
-rwxr-xr-xtest/functional/feature_nulldummy.py21
-rwxr-xr-xtest/functional/feature_pruning.py23
-rwxr-xr-xtest/functional/feature_rbf.py25
-rwxr-xr-xtest/functional/feature_reindex.py2
-rwxr-xr-xtest/functional/feature_segwit.py171
-rwxr-xr-xtest/functional/feature_uacomment.py2
-rwxr-xr-xtest/functional/feature_versionbits_warning.py13
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py31
-rwxr-xr-xtest/functional/interface_rest.py3
-rwxr-xr-xtest/functional/interface_rpc.py46
-rwxr-xr-xtest/functional/interface_zmq.py62
-rwxr-xr-xtest/functional/mempool_accept.py6
-rwxr-xr-xtest/functional/mempool_limit.py3
-rwxr-xr-xtest/functional/mempool_packages.py5
-rwxr-xr-xtest/functional/mempool_persist.py3
-rwxr-xr-xtest/functional/mempool_reorg.py3
-rwxr-xr-xtest/functional/mempool_resurrect.py8
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py3
-rwxr-xr-xtest/functional/mining_basic.py30
-rwxr-xr-xtest/functional/mining_getblocktemplate_longpoll.py16
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py6
-rwxr-xr-xtest/functional/p2p_compactblocks.py41
-rwxr-xr-xtest/functional/p2p_disconnect_ban.py2
-rwxr-xr-xtest/functional/p2p_feefilter.py3
-rwxr-xr-xtest/functional/p2p_fingerprint.py4
-rwxr-xr-xtest/functional/p2p_invalid_block.py21
-rwxr-xr-xtest/functional/p2p_invalid_locator.py2
-rwxr-xr-xtest/functional/p2p_invalid_messages.py179
-rwxr-xr-xtest/functional/p2p_invalid_tx.py19
-rwxr-xr-xtest/functional/p2p_leak.py2
-rwxr-xr-xtest/functional/p2p_leak_tx.py57
-rwxr-xr-xtest/functional/p2p_node_network_limited.py10
-rwxr-xr-xtest/functional/p2p_segwit.py273
-rwxr-xr-xtest/functional/p2p_sendheaders.py11
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py4
-rwxr-xr-xtest/functional/rpc_blockchain.py23
-rwxr-xr-xtest/functional/rpc_createmultisig.py5
-rwxr-xr-xtest/functional/rpc_deprecated.py16
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py9
-rwxr-xr-xtest/functional/rpc_getblockstats.py2
-rwxr-xr-xtest/functional/rpc_getchaintips.py18
-rwxr-xr-xtest/functional/rpc_help.py57
-rwxr-xr-xtest/functional/rpc_invalidateblock.py6
-rwxr-xr-xtest/functional/rpc_net.py45
-rwxr-xr-xtest/functional/rpc_preciousblock.py13
-rwxr-xr-xtest/functional/rpc_psbt.py80
-rwxr-xr-xtest/functional/rpc_rawtransaction.py17
-rwxr-xr-xtest/functional/rpc_scantxoutset.py16
-rwxr-xr-xtest/functional/rpc_signmessage.py3
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py22
-rwxr-xr-xtest/functional/rpc_txoutproof.py11
-rwxr-xr-xtest/functional/rpc_zmq.py36
-rw-r--r--test/functional/test_framework/address.py3
-rw-r--r--test/functional/test_framework/authproxy.py26
-rw-r--r--test/functional/test_framework/blocktools.py4
-rwxr-xr-xtest/functional/test_framework/messages.py195
-rwxr-xr-xtest/functional/test_framework/mininode.py142
-rw-r--r--test/functional/test_framework/script.py9
-rw-r--r--test/functional/test_framework/socks5.py7
-rwxr-xr-xtest/functional/test_framework/test_framework.py94
-rwxr-xr-xtest/functional/test_framework/test_node.py80
-rwxr-xr-xtest/functional/test_runner.py155
-rwxr-xr-xtest/functional/wallet_abandonconflict.py3
-rwxr-xr-xtest/functional/wallet_address_types.py62
-rwxr-xr-xtest/functional/wallet_backup.py3
-rwxr-xr-xtest/functional/wallet_balance.py133
-rwxr-xr-xtest/functional/wallet_basic.py54
-rwxr-xr-xtest/functional/wallet_bumpfee.py30
-rwxr-xr-xtest/functional/wallet_disableprivatekeys.py3
-rwxr-xr-xtest/functional/wallet_dump.py179
-rwxr-xr-xtest/functional/wallet_encryption.py12
-rwxr-xr-xtest/functional/wallet_fallbackfee.py3
-rwxr-xr-xtest/functional/wallet_groups.py5
-rwxr-xr-xtest/functional/wallet_hd.py9
-rwxr-xr-xtest/functional/wallet_import_rescan.py45
-rwxr-xr-xtest/functional/wallet_import_with_label.py134
-rwxr-xr-xtest/functional/wallet_importmulti.py225
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py5
-rwxr-xr-xtest/functional/wallet_keypool.py16
-rwxr-xr-xtest/functional/wallet_keypool_topup.py3
-rwxr-xr-xtest/functional/wallet_labels.py12
-rwxr-xr-xtest/functional/wallet_listreceivedby.py14
-rwxr-xr-xtest/functional/wallet_listsinceblock.py7
-rwxr-xr-xtest/functional/wallet_listtransactions.py10
-rwxr-xr-xtest/functional/wallet_multiwallet.py33
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py3
-rwxr-xr-xtest/functional/wallet_txn_clone.py3
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py3
-rwxr-xr-xtest/functional/wallet_zapwallettxes.py3
106 files changed, 2635 insertions, 1061 deletions
diff --git a/test/functional/README.md b/test/functional/README.md
index 6929ab5991..d40052ac93 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -60,6 +60,11 @@ don't have test cases for.
- When calling RPCs with lots of arguments, consider using named keyword
arguments instead of positional arguments to make the intent of the call
clear to readers.
+- Many of the core test framework classes such as `CBlock` and `CTransaction`
+ don't allow new attributes to be added to their objects at runtime like
+ typical Python objects allow. This helps prevent unpredictable side effects
+ from typographical errors or usage of the objects outside of their intended
+ purpose.
#### RPC and P2P definitions
@@ -72,7 +77,7 @@ P2P messages. These can be found in the following source files:
#### Using the P2P interface
-- `mininode.py` contains all the definitions for objects that pass
+- `messages.py` contains all the definitions for objects that pass
over the network (`CBlock`, `CTransaction`, etc, along with the network-level
wrappers for them, `msg_block`, `msg_tx`, etc).
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index 91b6415a7c..5bb3b5c094 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -2,7 +2,9 @@
"""Combine logs from multiple bitcoin nodes as well as the test_framework log.
This streams the combined log output to stdout. Use combine_logs.py > outputfile
-to write to an outputfile."""
+to write to an outputfile.
+
+If no argument is provided, the most recent test directory will be used."""
import argparse
from collections import defaultdict, namedtuple
@@ -11,34 +13,45 @@ import itertools
import os
import re
import sys
+import tempfile
+
+# N.B.: don't import any local modules here - this script must remain executable
+# without the parent module installed.
+
+# Should match same symbol in `test_framework.test_framework`.
+TMPDIR_PREFIX = "bitcoin_func_test_"
# Matches on the date format at the start of the log event
-TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z")
+TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{6})?Z")
LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event'])
def main():
"""Main function. Parses args, reads the log files and renders them as text or html."""
-
- parser = argparse.ArgumentParser(usage='%(prog)s [options] <test temporary directory>', description=__doc__)
+ parser = argparse.ArgumentParser(
+ description=__doc__, formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument(
+ 'testdir', nargs='?', default='',
+ help=('temporary test directory to combine logs from. '
+ 'Defaults to the most recent'))
parser.add_argument('-c', '--color', dest='color', action='store_true', help='outputs the combined log with events colored by source (requires posix terminal colors. Use less -r for viewing)')
parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2')
- args, unknown_args = parser.parse_known_args()
-
- if args.color and os.name != 'posix':
- print("Color output requires posix terminal colors.")
- sys.exit(1)
+ args = parser.parse_args()
if args.html and args.color:
print("Only one out of --color or --html should be specified")
sys.exit(1)
- # There should only be one unknown argument - the path of the temporary test directory
- if len(unknown_args) != 1:
- print("Unexpected arguments" + str(unknown_args))
+ testdir = args.testdir or find_latest_test_dir()
+
+ if not testdir:
+ print("No test directories found")
sys.exit(1)
- log_events = read_logs(unknown_args[0])
+ if not args.testdir:
+ print("Opening latest test directory: {}".format(testdir), file=sys.stderr)
+
+ log_events = read_logs(testdir)
print_logs(log_events, color=args.color, html=args.html)
@@ -57,6 +70,29 @@ def read_logs(tmp_dir):
return heapq.merge(*[get_log_events(source, f) for source, f in files])
+
+def find_latest_test_dir():
+ """Returns the latest tmpfile test directory prefix."""
+ tmpdir = tempfile.gettempdir()
+
+ def join_tmp(basename):
+ return os.path.join(tmpdir, basename)
+
+ def is_valid_test_tmpdir(basename):
+ fullpath = join_tmp(basename)
+ return (
+ os.path.isdir(fullpath)
+ and basename.startswith(TMPDIR_PREFIX)
+ and os.access(fullpath, os.R_OK)
+ )
+
+ testdir_paths = [
+ join_tmp(name) for name in os.listdir(tmpdir) if is_valid_test_tmpdir(name)
+ ]
+
+ return max(testdir_paths, key=os.path.getmtime) if testdir_paths else None
+
+
def get_log_events(source, logfile):
"""Generator function that returns individual log events.
@@ -75,11 +111,17 @@ def get_log_events(source, logfile):
if time_match:
if event:
yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
- event = line
timestamp = time_match.group()
+ if time_match.group(1) is None:
+ # timestamp does not have microseconds. Add zeroes.
+ timestamp_micro = timestamp.replace("Z", ".000000Z")
+ line = line.replace(timestamp, timestamp_micro)
+ timestamp = timestamp_micro
+ event = line
# if it doesn't have a timestamp, it's a continuation line of the previous log.
else:
- event += "\n" + line
+ # Add the line. Prefix with space equivalent to the source + timestamp so log lines are aligned
+ event += " " + line
# Flush the final event
yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
except FileNotFoundError:
@@ -98,7 +140,11 @@ def print_logs(log_events, color=False, html=False):
colors["reset"] = "\033[0m" # Reset font color
for event in log_events:
- print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, event.event, colors["reset"]))
+ lines = event.event.splitlines()
+ print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, lines[0], colors["reset"]))
+ if len(lines) > 1:
+ for line in lines[1:]:
+ print("{0}{1}{2}".format(colors[event.source.rstrip()], line, colors["reset"]))
else:
try:
diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json
index 9f970b4961..57f2608ee9 100644
--- a/test/functional/data/rpc_psbt.json
+++ b/test/functional/data/rpc_psbt.json
@@ -17,7 +17,8 @@
"cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
"cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A",
"cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A",
- "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"
+ "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A",
+ "cHNidP8BAHMCAAAAAbiWoY6pOQepFsEGhUPXaulX9rvye2NH+NrdlAHg+WgpAQAAAAD/////AkBLTAAAAAAAF6kUqWwXCcLM5BN2zoNqMNT5qMlIi7+HQEtMAAAAAAAXqRSVF/in2XNxAlN1OSxkyp0z+Wtg2YcAAAAAAAEBIBNssgAAAAAAF6kUamsvautR8hRlMRY6OKNTx03DK96HAQcXFgAUo8u1LWpHprjt/uENAwBpGZD0UH0BCGsCRzBEAiAONfH3DYiw67ZbylrsxCF/XXpVwyWBRgofyRbPslzvwgIgIKCsWw5sHSIPh1icNvcVLZLHWj6NA7Dk+4Os2pOnMbQBIQPGStfYHPtyhpV7zIWtn0Q4GXv5gK1zy/tnJ+cBXu4iiwABABYAFMwmJQEz+HDpBEEabxJ5PogPsqZRAAEAFgAUyCrGc3h3FYCmiIspbv2pSTKZ5jU"
],
"valid" : [
"cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA",
@@ -69,14 +70,6 @@
},
{
"privkeys" : [
- "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au",
- "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
- ],
- "psbt" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAQMEAQAAAAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAAQMEAQAAAAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
- "result" : "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210cwRAIgYxqYn+c4qSrQGYYCMxLBkhT+KAKznly8GsNniAbGksMCIDnbbDh70mdxbf2z1NjaULjoXSEzJrp8faqkwM5B65IjAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgICOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
- },
- {
- "privkeys" : [
"cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
],
"psbt" : "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=",
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index a8c1474876..be3544ee74 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -67,16 +67,17 @@ def custom_function():
# self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework
pass
+
class ExampleTest(BitcoinTestFramework):
# Each functional test is a subclass of the BitcoinTestFramework class.
- # Override the set_test_params(), add_options(), setup_chain(), setup_network()
+ # Override the set_test_params(), skip_test_if_missing_module(), add_options(), setup_chain(), setup_network()
# and setup_nodes() methods to customize the test setup as required.
def set_test_params(self):
"""Override test parameters for your individual test.
- This method must be overridden and num_nodes must be exlicitly set."""
+ This method must be overridden and num_nodes must be explicitly set."""
self.setup_clean_chain = True
self.num_nodes = 3
# Use self.extra_args to change command-line arguments for the nodes
@@ -84,6 +85,11 @@ class ExampleTest(BitcoinTestFramework):
# self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test()
+ # Use skip_test_if_missing_module() to skip the test if your test requires certain modules to be present.
+ # This test uses generate which requires wallet to be compiled
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
# Use add_options() to add specific command-line options for your test.
# In practice this is not used very much, since the tests are mostly written
# to be run in automated environments without command-line options.
@@ -111,7 +117,7 @@ class ExampleTest(BitcoinTestFramework):
# sync_all() should not include node2, since we're not expecting it to
# sync.
connect_nodes(self.nodes[0], 1)
- self.sync_all([self.nodes[0:1]])
+ self.sync_all([self.nodes[0:2]])
# Use setup_nodes() to customize the node start behaviour (for example if
# you don't want to start all nodes at the start of the test).
@@ -135,7 +141,7 @@ class ExampleTest(BitcoinTestFramework):
# Generating a block on one of the nodes will get us out of IBD
blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
- self.sync_all([self.nodes[0:1]])
+ self.sync_all([self.nodes[0:2]])
# Notice above how we called an RPC by calling a method with the same
# name on the node object. Notice also how we used a keyword argument
@@ -158,13 +164,13 @@ class ExampleTest(BitcoinTestFramework):
self.tip = int(self.nodes[0].getbestblockhash(), 16)
self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
- height = 1
+ height = self.nodes[0].getblockcount()
for i in range(10):
# Use the mininode and blocktools functionality to manually build a block
# Calling the generate() rpc is easier, but this allows us to exactly
# control the blocks and transactions.
- block = create_block(self.tip, create_coinbase(height), self.block_time)
+ block = create_block(self.tip, create_coinbase(height+1), self.block_time)
block.solve()
block_message = msg_block(block)
# Send message is used to send a P2P message to the node over our P2PInterface
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index 4a9445f503..8466f851ca 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -25,6 +25,9 @@ class BIP68Test(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [[], ["-acceptnonstdtxn=0"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 79ed902871..e50f67a345 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -169,7 +169,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block where the miner creates too much coinbase reward")
self.move_tip(6)
b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b9], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b9], success=False, reject_reason='bad-cb-amount', reconnect=True)
# Create a fork that ends in a block with too much fee (the one that causes the reorg)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -181,7 +181,7 @@ class FullBlockTest(BitcoinTestFramework):
self.sync_blocks([b10], False)
b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b11], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b11], success=False, reject_reason='bad-cb-amount', reconnect=True)
# Try again, but with a valid fork first
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -194,7 +194,7 @@ class FullBlockTest(BitcoinTestFramework):
b13 = self.next_block(13, spend=out[4])
self.save_spendable_output()
b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)
- self.sync_blocks([b12, b13, b14], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b12, b13, b14], success=False, reject_reason='bad-cb-amount', reconnect=True)
# New tip should be b13.
assert_equal(node.getbestblockhash(), b13.hash)
@@ -213,7 +213,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with too many checksigs")
too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)
- self.sync_blocks([b16], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b16], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# Attempt to spend a transaction created on a different fork
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -222,7 +222,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with a spend from a re-org'ed out tx")
self.move_tip(15)
b17 = self.next_block(17, spend=txout_b3)
- self.sync_blocks([b17], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b17], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a transaction created on a different fork (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -235,7 +235,7 @@ class FullBlockTest(BitcoinTestFramework):
self.sync_blocks([b18], False)
b19 = self.next_block(19, spend=out[6])
- self.sync_blocks([b19], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b19], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a coinbase at depth too low
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -244,7 +244,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block spending an immature coinbase.")
self.move_tip(15)
b20 = self.next_block(20, spend=out[7])
- self.sync_blocks([b20], False, 16, b'bad-txns-premature-spend-of-coinbase')
+ self.sync_blocks([b20], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
# Attempt to spend a coinbase at depth too low (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -257,7 +257,7 @@ class FullBlockTest(BitcoinTestFramework):
self.sync_blocks([b21], False)
b22 = self.next_block(22, spend=out[5])
- self.sync_blocks([b22], False, 16, b'bad-txns-premature-spend-of-coinbase')
+ self.sync_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
# Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -286,7 +286,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vout = [CTxOut(0, script_output)]
b24 = self.update_block(24, [tx])
assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1)
- self.sync_blocks([b24], False, 16, b'bad-blk-length', reconnect=True)
+ self.sync_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)
b25 = self.next_block(25, spend=out[7])
self.sync_blocks([b25], False)
@@ -304,7 +304,7 @@ class FullBlockTest(BitcoinTestFramework):
# update_block causes the merkle root to get updated, even with no new
# transactions, and updates the required state.
b26 = self.update_block(26, [])
- self.sync_blocks([b26], False, 16, b'bad-cb-length', reconnect=True)
+ self.sync_blocks([b26], success=False, reject_reason='bad-cb-length', reconnect=True)
# Extend the b26 chain to make sure bitcoind isn't accepting b26
b27 = self.next_block(27, spend=out[7])
@@ -316,7 +316,7 @@ class FullBlockTest(BitcoinTestFramework):
b28.vtx[0].vin[0].scriptSig = b'\x00' * 101
b28.vtx[0].rehash()
b28 = self.update_block(28, [])
- self.sync_blocks([b28], False, 16, b'bad-cb-length', reconnect=True)
+ self.sync_blocks([b28], success=False, reject_reason='bad-cb-length', reconnect=True)
# Extend the b28 chain to make sure bitcoind isn't accepting b28
b29 = self.next_block(29, spend=out[7])
@@ -352,7 +352,7 @@ class FullBlockTest(BitcoinTestFramework):
too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))
b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)
assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b32], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b32], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# CHECKMULTISIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops")
@@ -365,7 +365,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")
too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))
b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)
- self.sync_blocks([b34], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b34], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# CHECKSIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops")
@@ -378,7 +378,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")
too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))
b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)
- self.sync_blocks([b36], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b36], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# Check spending of a transaction in a block which failed to connect
#
@@ -395,12 +395,12 @@ class FullBlockTest(BitcoinTestFramework):
txout_b37 = b37.vtx[1]
tx = self.create_and_sign_transaction(out[11], 0)
b37 = self.update_block(37, [tx])
- self.sync_blocks([b37], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b37], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid
self.move_tip(35)
b38 = self.next_block(38, spend=txout_b37)
- self.sync_blocks([b38], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b38], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Check P2SH SigOp counting
#
@@ -492,7 +492,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.rehash()
new_txs.append(tx)
self.update_block(40, new_txs)
- self.sync_blocks([b40], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b40], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# same as b40, but one less sigop
self.log.info("Accept a block with the max number of P2SH sigops")
@@ -555,7 +555,7 @@ class FullBlockTest(BitcoinTestFramework):
self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1
self.tip = b45
self.blocks[45] = b45
- self.sync_blocks([b45], False, 16, b'bad-cb-missing', reconnect=True)
+ self.sync_blocks([b45], success=False, reject_reason='bad-cb-missing', reconnect=True)
self.log.info("Reject a block with no transactions")
self.move_tip(44)
@@ -570,7 +570,7 @@ class FullBlockTest(BitcoinTestFramework):
self.tip = b46
assert 46 not in self.blocks
self.blocks[46] = b46
- self.sync_blocks([b46], False, 16, b'bad-blk-length', reconnect=True)
+ self.sync_blocks([b46], success=False, reject_reason='bad-blk-length', reconnect=True)
self.log.info("Reject a block with invalid work")
self.move_tip(44)
@@ -579,35 +579,35 @@ class FullBlockTest(BitcoinTestFramework):
while b47.sha256 < target:
b47.nNonce += 1
b47.rehash()
- self.sync_blocks([b47], False, request_block=False)
+ self.sync_blocks([b47], False, force_send=True, reject_reason='high-hash')
self.log.info("Reject a block with a timestamp >2 hours in the future")
self.move_tip(44)
b48 = self.next_block(48, solve=False)
b48.nTime = int(time.time()) + 60 * 60 * 3
b48.solve()
- self.sync_blocks([b48], False, request_block=False)
+ self.sync_blocks([b48], False, force_send=True, reject_reason='time-too-new')
self.log.info("Reject a block with invalid merkle hash")
self.move_tip(44)
b49 = self.next_block(49)
b49.hashMerkleRoot += 1
b49.solve()
- self.sync_blocks([b49], False, 16, b'bad-txnmrklroot', reconnect=True)
+ self.sync_blocks([b49], success=False, reject_reason='bad-txnmrklroot', reconnect=True)
self.log.info("Reject a block with incorrect POW limit")
self.move_tip(44)
b50 = self.next_block(50)
b50.nBits = b50.nBits - 1
b50.solve()
- self.sync_blocks([b50], False, request_block=False, reconnect=True)
+ self.sync_blocks([b50], False, force_send=True, reject_reason='bad-diffbits', reconnect=True)
self.log.info("Reject a block with two coinbase transactions")
self.move_tip(44)
b51 = self.next_block(51)
cb2 = create_coinbase(51, self.coinbase_pubkey)
b51 = self.update_block(51, [cb2])
- self.sync_blocks([b51], False, 16, b'bad-cb-multiple', reconnect=True)
+ self.sync_blocks([b51], success=False, reject_reason='bad-cb-multiple', reconnect=True)
self.log.info("Reject a block with duplicate transactions")
# Note: txns have to be in the right position in the merkle tree to trigger this error
@@ -615,7 +615,7 @@ class FullBlockTest(BitcoinTestFramework):
b52 = self.next_block(52, spend=out[15])
tx = self.create_tx(b52.vtx[1], 0, 1)
b52 = self.update_block(52, [tx, tx])
- self.sync_blocks([b52], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b52], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
# Test block timestamps
# -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)
@@ -630,7 +630,7 @@ class FullBlockTest(BitcoinTestFramework):
b54 = self.next_block(54, spend=out[15])
b54.nTime = b35.nTime - 1
b54.solve()
- self.sync_blocks([b54], False, request_block=False)
+ self.sync_blocks([b54], False, force_send=True, reject_reason='time-too-old')
# valid timestamp
self.move_tip(53)
@@ -682,7 +682,7 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(len(b56.vtx), 3)
b56 = self.update_block(56, [tx1])
assert_equal(b56.hash, b57.hash)
- self.sync_blocks([b56], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b56], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
# b57p2 - a good block with 6 tx'es, don't submit until end
self.move_tip(55)
@@ -702,7 +702,7 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(b56p2.hash, b57p2.hash)
assert_equal(len(b56p2.vtx), 6)
b56p2 = self.update_block("b56p2", [tx3, tx4])
- self.sync_blocks([b56p2], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b56p2], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
self.move_tip("57p2")
self.sync_blocks([b57p2], True)
@@ -727,7 +727,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vout.append(CTxOut(0, b""))
tx.calc_sha256()
b58 = self.update_block(58, [tx])
- self.sync_blocks([b58], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b58], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# tx with output value > input value
self.log.info("Reject a block with a transaction with outputs > inputs")
@@ -735,7 +735,7 @@ class FullBlockTest(BitcoinTestFramework):
b59 = self.next_block(59)
tx = self.create_and_sign_transaction(out[17], 51 * COIN)
b59 = self.update_block(59, [tx])
- self.sync_blocks([b59], False, 16, b'bad-txns-in-belowout', reconnect=True)
+ self.sync_blocks([b59], success=False, reject_reason='bad-txns-in-belowout', reconnect=True)
# reset to good chain
self.move_tip(57)
@@ -759,7 +759,7 @@ class FullBlockTest(BitcoinTestFramework):
b61.vtx[0].rehash()
b61 = self.update_block(61, [])
assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())
- self.sync_blocks([b61], False, 16, b'bad-txns-BIP30', reconnect=True)
+ self.sync_blocks([b61], success=False, reject_reason='bad-txns-BIP30', reconnect=True)
# Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)
#
@@ -776,7 +776,7 @@ class FullBlockTest(BitcoinTestFramework):
assert(tx.vin[0].nSequence < 0xffffffff)
tx.calc_sha256()
b62 = self.update_block(62, [tx])
- self.sync_blocks([b62], False, 16, b'bad-txns-nonfinal')
+ self.sync_blocks([b62], success=False, reject_reason='bad-txns-nonfinal')
# Test a non-final coinbase is also rejected
#
@@ -790,7 +790,7 @@ class FullBlockTest(BitcoinTestFramework):
b63.vtx[0].vin[0].nSequence = 0xDEADBEEF
b63.vtx[0].rehash()
b63 = self.update_block(63, [])
- self.sync_blocks([b63], False, 16, b'bad-txns-nonfinal')
+ self.sync_blocks([b63], success=False, reject_reason='bad-txns-nonfinal')
# This checks that a block with a bloated VARINT between the block_header and the array of tx such that
# the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,
@@ -824,7 +824,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
b64a = self.update_block("64a", [tx])
assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
- self.sync_blocks([b64a], False, 1, b'error parsing message')
+ self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()')
# bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
# resend the header message, it won't send us the getdata message again. Just
@@ -866,7 +866,7 @@ class FullBlockTest(BitcoinTestFramework):
tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 1)
b66 = self.update_block(66, [tx2, tx1])
- self.sync_blocks([b66], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b66], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to double-spend a transaction created in a block
#
@@ -881,7 +881,7 @@ class FullBlockTest(BitcoinTestFramework):
tx2 = self.create_and_sign_transaction(tx1, 1)
tx3 = self.create_and_sign_transaction(tx1, 2)
b67 = self.update_block(67, [tx1, tx2, tx3])
- self.sync_blocks([b67], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b67], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# More tests of block subsidy
#
@@ -900,7 +900,7 @@ class FullBlockTest(BitcoinTestFramework):
b68 = self.next_block(68, additional_coinbase_value=10)
tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)
b68 = self.update_block(68, [tx])
- self.sync_blocks([b68], False, 16, b'bad-cb-amount', reconnect=True)
+ self.sync_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)
self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction")
self.move_tip(65)
@@ -924,7 +924,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
tx.vout.append(CTxOut(1, b""))
b70 = self.update_block(70, [tx])
- self.sync_blocks([b70], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)
#
@@ -949,7 +949,7 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(b72.sha256, b71.sha256)
self.move_tip(71)
- self.sync_blocks([b71], False, 16, b'bad-txns-duplicate', reconnect=True)
+ self.sync_blocks([b71], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
self.move_tip(72)
self.sync_blocks([b72], True)
@@ -987,9 +987,9 @@ class FullBlockTest(BitcoinTestFramework):
tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b73 = self.update_block(73, [tx])
assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b73], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b73], success=False, reject_reason='bad-blk-sigops', reconnect=True)
- # b74/75 - if we push an invalid script element, all prevous sigops are counted,
+ # b74/75 - if we push an invalid script element, all previous sigops are counted,
# but sigops after the element are not counted.
#
# The invalid script element is that the push_data indicates that
@@ -1011,7 +1011,7 @@ class FullBlockTest(BitcoinTestFramework):
a[MAX_BLOCK_SIGOPS + 4] = 0xff
tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b74 = self.update_block(74, [tx])
- self.sync_blocks([b74], False, 16, b'bad-blk-sigops', reconnect=True)
+ self.sync_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)
self.move_tip(72)
b75 = self.next_block(75)
@@ -1078,11 +1078,11 @@ class FullBlockTest(BitcoinTestFramework):
self.move_tip(77)
b80 = self.next_block(80, spend=out[25])
- self.sync_blocks([b80], False, request_block=False)
+ self.sync_blocks([b80], False, force_send=True)
self.save_spendable_output()
b81 = self.next_block(81, spend=out[26])
- self.sync_blocks([b81], False, request_block=False) # other chain is same length
+ self.sync_blocks([b81], False, force_send=True) # other chain is same length
self.save_spendable_output()
b82 = self.next_block(82, spend=out[27])
@@ -1160,7 +1160,7 @@ class FullBlockTest(BitcoinTestFramework):
b89a = self.next_block("89a", spend=out[32])
tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
b89a = self.update_block("89a", [tx])
- self.sync_blocks([b89a], False, 16, b'bad-txns-inputs-missingorspent', reconnect=True)
+ self.sync_blocks([b89a], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
self.log.info("Test a re-org of one week's worth of blocks (1088 blocks)")
@@ -1189,7 +1189,7 @@ class FullBlockTest(BitcoinTestFramework):
blocks2 = []
for i in range(89, LARGE_REORG_SIZE + 89):
blocks2.append(self.next_block("alt" + str(i)))
- self.sync_blocks(blocks2, False, request_block=False)
+ self.sync_blocks(blocks2, False, force_send=True)
# extend alt chain to trigger re-org
block = self.next_block("alt" + str(chain1_tip + 1))
@@ -1198,7 +1198,7 @@ class FullBlockTest(BitcoinTestFramework):
# ... and re-org back to the first chain
self.move_tip(chain1_tip)
block = self.next_block(chain1_tip + 1)
- self.sync_blocks([block], False, request_block=False)
+ self.sync_blocks([block], False, force_send=True)
block = self.next_block(chain1_tip + 2)
self.sync_blocks([block], True, timeout=180)
@@ -1309,14 +1309,15 @@ class FullBlockTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
self.bootstrap_p2p()
- def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None, request_block=True, reconnect=False, timeout=60):
+ def sync_blocks(self, blocks, success=True, reject_reason=None, force_send=False, reconnect=False, timeout=60):
"""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, reject_code=reject_code, reject_reason=reject_reason, request_block=request_block, timeout=timeout)
+ self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason, force_send=force_send, timeout=timeout, expect_disconnect=reconnect)
if reconnect:
self.reconnect_p2p()
+
if __name__ == '__main__':
FullBlockTest().main()
diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py
index 784dc2865f..c170f510c8 100755
--- a/test/functional/feature_blocksdir.py
+++ b/test/functional/feature_blocksdir.py
@@ -27,7 +27,7 @@ class BlocksdirTest(BitcoinTestFramework):
self.log.info("Starting with existing blocksdir ...")
self.start_node(0, ["-blocksdir=" + blocksdir_path])
self.log.info("mining blocks..")
- self.nodes[0].generate(10)
+ self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
assert os.path.isfile(os.path.join(blocksdir_path, "regtest", "blocks", "blk00000.dat"))
assert os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest", "blocks", "index"))
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 8460291831..302a5ec1cb 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -10,10 +10,14 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height
from test_framework.blocktools import create_coinbase, create_block, create_transaction
from test_framework.messages import CTransaction, msg_block, ToHex
-from test_framework.mininode import mininode_lock, P2PInterface
+from test_framework.mininode import P2PInterface
from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, bytes_to_hex_str, hex_str_to_bytes, wait_until
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ hex_str_to_bytes,
+)
from io import BytesIO
@@ -21,7 +25,6 @@ CLTV_HEIGHT = 1351
# Reject codes that we might receive in this test
REJECT_INVALID = 16
-REJECT_OBSOLETE = 17
REJECT_NONSTANDARD = 64
def cltv_invalidate(tx):
@@ -51,12 +54,16 @@ def cltv_validate(node, tx, height):
list(CScript(new_tx.vin[0].scriptSig)))
return new_tx
+
class BIP65Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-whitelist=127.0.0.1']]
+ self.extra_args = [['-whitelist=127.0.0.1', '-par=1']] # Use only one script thread to get the exact reject reason for testing
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
@@ -88,15 +95,11 @@ class BIP65Test(BitcoinTestFramework):
block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
block.nVersion = 3
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
- with mininode_lock:
- assert_equal(self.nodes[0].p2p.last_message["reject"].code, REJECT_OBSOLETE)
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'bad-version(0x00000003)')
- assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- del self.nodes[0].p2p.last_message["reject"]
+ with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000003)'.format(block.hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block")
block.nVersion = 4
@@ -118,18 +121,10 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
-
- wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
- with mininode_lock:
- assert self.nodes[0].p2p.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
- assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- if self.nodes[0].p2p.last_message["reject"].code == REJECT_INVALID:
- # Generic rejection when a block is invalid
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'block-validation-failed')
- else:
- assert b'Negative locktime' in self.nodes[0].p2p.last_message["reject"].reason
+ with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 62091048f9..d87eabaa6d 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -14,8 +14,38 @@ class ConfArgsTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
+ def test_config_file_parser(self):
+ # Assume node is stopped
+
+ inc_conf_file_path = os.path.join(self.nodes[0].datadir, 'include.conf')
+ with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf:
+ conf.write('includeconf={}\n'.format(inc_conf_file_path))
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('-dash=1\n')
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('nono\n')
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('server=1\nrpcuser=someuser\nrpcpassword=some#pass')
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('testnot.datadir=1\n[testnet]\n')
+ self.restart_node(0)
+ self.nodes[0].stop_node(expected_stderr='Warning: Section [testnet] is not recognized.' + os.linesep + 'Warning: Section [testnot] is not recognized.')
+
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('') # clear
+
def run_test(self):
self.stop_node(0)
+
+ self.test_config_file_parser()
+
# Remove the -datadir argument so it doesn't override the config file
self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith("-datadir")]
@@ -44,13 +74,18 @@ class ConfArgsTest(BitcoinTestFramework):
# Temporarily disabled, because this test would access the user's home dir (~/.bitcoin)
#self.start_node(0, ['-conf='+conf_file, '-wallet=w1'])
#self.stop_node(0)
+ #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'blocks'))
+ #if self.is_wallet_compiled():
#assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'wallets', 'w1'))
# Ensure command line argument overrides datadir in conf
os.mkdir(new_data_dir_2)
self.nodes[0].datadir = new_data_dir_2
self.start_node(0, ['-datadir='+new_data_dir_2, '-conf='+conf_file, '-wallet=w2'])
- assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'wallets', 'w2'))
+ assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'blocks'))
+ if self.is_wallet_compiled():
+ assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'wallets', 'w2'))
+
if __name__ == '__main__':
ConfArgsTest().main()
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index af14feb471..df79c4312c 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -145,6 +145,9 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.setup_clean_chain = True
self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4', '-addresstype=legacy']]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def generate_blocks(self, number, version, test_blocks=None):
if test_blocks is None:
test_blocks = []
@@ -165,11 +168,11 @@ class BIP68_112_113Test(BitcoinTestFramework):
block.solve()
return block
- def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None, request_block=True):
+ def sync_blocks(self, blocks, success=True):
"""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, reject_code=reject_code, reject_reason=reject_reason, request_block=request_block)
+ self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success)
def run_test(self):
self.nodes[0].add_p2p_connection(P2PDataStore())
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index d612dbe2bc..70d67aa53a 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -63,9 +63,13 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.node3_args = ["-blockmaxweight=4000000"]
self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.add_nodes(self.num_nodes, extra_args=self.extra_args)
self.start_nodes()
+ self.import_deterministic_coinbase_privkeys()
# Leave them unconnected, we'll use submitblock directly in this test
def restart_node(self, node_index, expected_tip):
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 53e94c436a..9cbc1b39bd 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -12,13 +12,16 @@ from test_framework.messages import msg_block
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, bytes_to_hex_str, wait_until
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ wait_until,
+)
DERSIG_HEIGHT = 1251
# Reject codes that we might receive in this test
REJECT_INVALID = 16
-REJECT_OBSOLETE = 17
REJECT_NONSTANDARD = 64
# A canonical signature consists of:
@@ -42,9 +45,12 @@ def unDERify(tx):
class BIP66Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-whitelist=127.0.0.1']]
+ self.extra_args = [['-whitelist=127.0.0.1', '-par=1', '-enablebip61']] # Use only one script thread to get the exact reject reason for testing
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
@@ -78,15 +84,11 @@ class BIP66Test(BitcoinTestFramework):
block.nVersion = 2
block.rehash()
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
- with mininode_lock:
- assert_equal(self.nodes[0].p2p.last_message["reject"].code, REJECT_OBSOLETE)
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'bad-version(0x00000002)')
- assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- del self.nodes[0].p2p.last_message["reject"]
+ with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000002)'.format(block.hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
self.log.info("Test that transactions with non-DER signatures cannot appear in a block")
block.nVersion = 3
@@ -109,23 +111,16 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
- self.nodes[0].p2p.send_and_ping(msg_block(block))
- assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Non-canonical DER signature)'.format(block.vtx[-1].hash)]):
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
+ self.nodes[0].p2p.sync_with_ping()
wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
with mininode_lock:
- # We can receive different reject messages depending on whether
- # bitcoind is running with multiple script check threads. If script
- # check threads are not in use, then transaction script validation
- # happens sequentially, and bitcoind produces more specific reject
- # reasons.
assert self.nodes[0].p2p.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
- if self.nodes[0].p2p.last_message["reject"].code == REJECT_INVALID:
- # Generic rejection when a block is invalid
- assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'block-validation-failed')
- else:
- assert b'Non-canonical DER signature' in self.nodes[0].p2p.last_message["reject"].reason
+ assert b'Non-canonical DER signature' in self.nodes[0].p2p.last_message["reject"].reason
self.log.info("Test that a version 3 block with a DERSIG-compliant transaction is accepted")
block.vtx[1] = create_transaction(self.nodes[0], self.coinbase_txids[1], self.nodeaddress, amount=1.0)
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 709910f2e4..b68e46adbc 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -126,6 +126,9 @@ class EstimateFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
"""
We'll setup the network to have 3 nodes that all mine with different parameters.
@@ -141,6 +144,9 @@ class EstimateFeeTest(BitcoinTestFramework):
# (68k weight is room enough for 120 or so transactions)
# Node2 is a stingy miner, that
# produces too small blocks (room for only 55 or so transactions)
+ self.start_nodes()
+ self.import_deterministic_coinbase_privkeys()
+ self.stop_nodes()
def transact_and_mine(self, numblocks, mining_node):
min_fee = Decimal("0.00001")
diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py
new file mode 100755
index 0000000000..9fb0d35a68
--- /dev/null
+++ b/test/functional/feature_filelock.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Check that it's not possible to start a second bitcoind instance using the same datadir or wallet."""
+import os
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.test_node import ErrorMatch
+
+class FilelockTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+
+ def setup_network(self):
+ self.add_nodes(self.num_nodes, extra_args=None)
+ self.nodes[0].start([])
+ self.nodes[0].wait_for_rpc_connection()
+
+ def run_test(self):
+ datadir = os.path.join(self.nodes[0].datadir, 'regtest')
+ self.log.info("Using datadir {}".format(datadir))
+
+ self.log.info("Check that we can't start a second bitcoind instance using the same datadir")
+ expected_msg = "Error: Cannot obtain a lock on data directory {}. Bitcoin Core is probably already running.".format(datadir)
+ self.nodes[1].assert_start_raises_init_error(extra_args=['-datadir={}'.format(self.nodes[0].datadir), '-noserver'], expected_msg=expected_msg)
+
+ if self.is_wallet_compiled():
+ wallet_dir = os.path.join(datadir, 'wallets')
+ self.log.info("Check that we can't start a second bitcoind instance using the same wallet")
+ expected_msg = "Error: Error initializing wallet database environment"
+ self.nodes[1].assert_start_raises_init_error(extra_args=['-walletdir={}'.format(wallet_dir), '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_REGEX)
+
+if __name__ == '__main__':
+ FilelockTest().main()
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index a81ebb4220..87c318de9a 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -40,6 +40,9 @@ class MaxUploadTest(BitcoinTestFramework):
# Cache for utxos, as the listunspent may take a long time later in the test
self.utxo_cache = []
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Before we connect anything, we first set the time on the node
# to be in the past, otherwise things break because the CNode
diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py
index a1cced0bc7..dbff6f15f2 100755
--- a/test/functional/feature_minchainwork.py
+++ b/test/functional/feature_minchainwork.py
@@ -51,7 +51,8 @@ class MinimumChainWorkTest(BitcoinTestFramework):
num_blocks_to_generate = int((self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK)
self.log.info("Generating %d blocks on node0", num_blocks_to_generate)
- hashes = self.nodes[0].generate(num_blocks_to_generate)
+ hashes = self.nodes[0].generatetoaddress(num_blocks_to_generate,
+ self.nodes[0].get_deterministic_priv_key().address)
self.log.info("Node0 current chain work: %s", self.nodes[0].getblockheader(hashes[-1])['chainwork'])
@@ -72,7 +73,7 @@ class MinimumChainWorkTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getblockcount(), starting_blockcount)
self.log.info("Generating one more block")
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
self.log.info("Verifying nodes are all synced")
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 71e5e493aa..d8083b2840 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -5,82 +5,84 @@
"""Test the -alertnotify, -blocknotify and -walletnotify options."""
import os
+from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, wait_until, connect_nodes_bi
+
class NotificationsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
def setup_network(self):
- self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
- self.block_filename = os.path.join(self.options.tmpdir, "blocks.txt")
- self.tx_filename = os.path.join(self.options.tmpdir, "transactions.txt")
+ self.alertnotify_dir = os.path.join(self.options.tmpdir, "alertnotify")
+ self.blocknotify_dir = os.path.join(self.options.tmpdir, "blocknotify")
+ self.walletnotify_dir = os.path.join(self.options.tmpdir, "walletnotify")
+ os.mkdir(self.alertnotify_dir)
+ os.mkdir(self.blocknotify_dir)
+ os.mkdir(self.walletnotify_dir)
# -alertnotify and -blocknotify on node0, walletnotify on node1
- self.extra_args = [["-blockversion=2",
- "-alertnotify=echo %%s >> %s" % self.alert_filename,
- "-blocknotify=echo %%s >> %s" % self.block_filename],
+ self.extra_args = [[
+ "-alertnotify=echo > {}".format(os.path.join(self.alertnotify_dir, '%s')),
+ "-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s'))],
["-blockversion=211",
"-rescan",
- "-walletnotify=echo %%s >> %s" % self.tx_filename]]
+ "-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, '%s'))]]
super().setup_network()
def run_test(self):
self.log.info("test -blocknotify")
block_count = 10
- blocks = self.nodes[1].generate(block_count)
+ blocks = self.nodes[1].generatetoaddress(block_count, self.nodes[1].getnewaddress() if self.is_wallet_compiled() else ADDRESS_BCRT1_UNSPENDABLE)
- # wait at most 10 seconds for expected file size before reading the content
- wait_until(lambda: os.path.isfile(self.block_filename) and os.stat(self.block_filename).st_size >= (block_count * 65), timeout=10)
+ # wait at most 10 seconds for expected number of files before reading the content
+ wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10)
- # file content should equal the generated blocks hashes
- with open(self.block_filename, 'r', encoding="utf-8") as f:
- assert_equal(sorted(blocks), sorted(l.strip() for l in f.read().splitlines()))
+ # directory content should equal the generated blocks hashes
+ assert_equal(sorted(blocks), sorted(os.listdir(self.blocknotify_dir)))
- self.log.info("test -walletnotify")
- # wait at most 10 seconds for expected file size before reading the content
- wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat(self.tx_filename).st_size >= (block_count * 65), timeout=10)
+ if self.is_wallet_compiled():
+ self.log.info("test -walletnotify")
+ # wait at most 10 seconds for expected number of files before reading the content
+ wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)
- # file content should equal the generated transaction hashes
- txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
- with open(self.tx_filename, 'r', encoding="ascii") as f:
- assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines()))
- os.remove(self.tx_filename)
+ # directory content should equal the generated transaction hashes
+ txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
+ assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
+ self.stop_node(1)
+ for tx_file in os.listdir(self.walletnotify_dir):
+ os.remove(os.path.join(self.walletnotify_dir, tx_file))
- self.log.info("test -walletnotify after rescan")
- # restart node to rescan to force wallet notifications
- self.restart_node(1)
- connect_nodes_bi(self.nodes, 0, 1)
+ self.log.info("test -walletnotify after rescan")
+ # restart node to rescan to force wallet notifications
+ self.start_node(1)
+ connect_nodes_bi(self.nodes, 0, 1)
- wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat(self.tx_filename).st_size >= (block_count * 65), timeout=10)
+ wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10)
- # file content should equal the generated transaction hashes
- txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
- with open(self.tx_filename, 'r', encoding="ascii") as f:
- assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines()))
+ # directory content should equal the generated transaction hashes
+ txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count)))
+ assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir)))
# Mine another 41 up-version blocks. -alertnotify should trigger on the 51st.
self.log.info("test -alertnotify")
- self.nodes[1].generate(41)
+ self.nodes[1].generatetoaddress(41, ADDRESS_BCRT1_UNSPENDABLE)
self.sync_all()
# Give bitcoind 10 seconds to write the alert notification
- wait_until(lambda: os.path.isfile(self.alert_filename) and os.path.getsize(self.alert_filename), timeout=10)
+ wait_until(lambda: len(os.listdir(self.alertnotify_dir)), timeout=10)
- with open(self.alert_filename, 'r', encoding='utf8') as f:
- alert_text = f.read()
+ for notify_file in os.listdir(self.alertnotify_dir):
+ os.remove(os.path.join(self.alertnotify_dir, notify_file))
# Mine more up-version blocks, should not get more alerts:
- self.nodes[1].generate(2)
+ self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_UNSPENDABLE)
self.sync_all()
- with open(self.alert_filename, 'r', encoding='utf8') as f:
- alert_text2 = f.read()
-
self.log.info("-alertnotify should not continue notifying for more unknown version blocks")
- assert_equal(alert_text, alert_text2)
+ assert_equal(len(os.listdir(self.alertnotify_dir)), 0)
if __name__ == '__main__':
NotificationsTest().main()
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index 9d1805ec2d..eb76089d9c 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -12,6 +12,7 @@ Generate 427 more blocks.
[Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block.
[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block.
"""
+import time
from test_framework.blocktools import create_coinbase, create_block, create_transaction, add_witness_commitment
from test_framework.messages import CTransaction
@@ -19,8 +20,6 @@ from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str
-import time
-
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)"
def trueDummy(tx):
@@ -42,19 +41,22 @@ 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', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy']]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
self.address = self.nodes[0].getnewaddress()
- self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address])['address']
- self.wit_address = self.nodes[0].addwitnessaddress(self.address)
+ self.ms_address = self.nodes[0].addmultisigaddress(1, [self.address])['address']
+ self.wit_address = self.nodes[0].getnewaddress(address_type='p2sh-segwit')
self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address']
- self.coinbase_blocks = self.nodes[0].generate(2) # Block 2
+ self.coinbase_blocks = self.nodes[0].generate(2) # Block 2
coinbase_txid = []
for i in self.coinbase_blocks:
coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])
- self.nodes[0].generate(427) # Block 429
+ self.nodes[0].generate(427) # Block 429
self.lastblockhash = self.nodes[0].getbestblockhash()
self.tip = int("0x" + self.lastblockhash, 0)
self.lastblockheight = 429
@@ -79,7 +81,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
test4tx = create_transaction(self.nodes[0], test2tx.hash, self.address, amount=46)
- test6txs=[CTransaction(test4tx)]
+ test6txs = [CTransaction(test4tx)]
trueDummy(test4tx)
assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True)
self.block_submit(self.nodes[0], [test4tx])
@@ -96,8 +98,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.nodes[0].sendrawtransaction(bytes_to_hex_str(i.serialize_with_witness()), True)
self.block_submit(self.nodes[0], test6txs, True, True)
-
- def block_submit(self, node, txs, witness = False, accept = False):
+ def block_submit(self, node, txs, witness=False, accept=False):
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1)
block.nVersion = 4
for tx in txs:
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index c8f4b7f8b5..c162f46d63 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -33,15 +33,20 @@ class PruneTest(BitcoinTestFramework):
# Create nodes 0 and 1 to mine.
# Create node 2 to test pruning.
- self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000" ]
+ self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000"]
# Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
# Create nodes 5 to test wallet in prune mode, but do not connect
- self.extra_args = [self.full_node_default_args,
- self.full_node_default_args,
- ["-maxreceivebuffer=20000", "-prune=550"],
- ["-maxreceivebuffer=20000"],
- ["-maxreceivebuffer=20000"],
- ["-prune=550"]]
+ self.extra_args = [
+ self.full_node_default_args,
+ self.full_node_default_args,
+ ["-maxreceivebuffer=20000", "-prune=550"],
+ ["-maxreceivebuffer=20000"],
+ ["-maxreceivebuffer=20000"],
+ ["-prune=550"],
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def setup_network(self):
self.setup_nodes()
@@ -58,6 +63,8 @@ class PruneTest(BitcoinTestFramework):
def setup_nodes(self):
self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
+ for n in self.nodes:
+ n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase', rescan=False)
def create_big_chain(self):
# Start by creating some coinbases we can spend later
@@ -242,7 +249,7 @@ class PruneTest(BitcoinTestFramework):
return index
def prune(index, expected_ret=None):
- ret = node.pruneblockchain(height(index))
+ ret = node.pruneblockchain(height=height(index))
# Check the return value. When use_timestamp is True, just check
# that the return value is less than or equal to the expected
# value, because when more than one block is generated per second,
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 7e84ba43b5..ff7c2b23bf 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -61,17 +61,26 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
return COutPoint(int(txid, 16), 0)
-class ReplaceByFeeTest(BitcoinTestFramework):
+class ReplaceByFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.extra_args= [["-maxorphantx=1000",
- "-whitelist=127.0.0.1",
- "-limitancestorcount=50",
- "-limitancestorsize=101",
- "-limitdescendantcount=200",
- "-limitdescendantsize=101"],
- ["-mempoolreplacement=0"]]
+ self.extra_args = [
+ [
+ "-maxorphantx=1000",
+ "-whitelist=127.0.0.1",
+ "-limitancestorcount=50",
+ "-limitancestorsize=101",
+ "-limitdescendantcount=200",
+ "-limitdescendantsize=101",
+ ],
+ [
+ "-mempoolreplacement=0",
+ ],
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
# Leave IBD
diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py
index f30e1191e3..940b403f9c 100755
--- a/test/functional/feature_reindex.py
+++ b/test/functional/feature_reindex.py
@@ -19,7 +19,7 @@ class ReindexTest(BitcoinTestFramework):
self.num_nodes = 1
def reindex(self, justchainstate=False):
- self.nodes[0].generate(3)
+ self.nodes[0].generatetoaddress(3, self.nodes[0].get_deterministic_priv_key().address)
blockcount = self.nodes[0].getblockcount()
self.stop_nodes()
extra_args = [["-reindex-chainstate" if justchainstate else "-reindex"]]
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 13d7758e13..7098a03f1e 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -5,11 +5,10 @@
"""Test the SegWit changeover logic."""
from decimal import Decimal
+from io import BytesIO
from test_framework.address import (
key_to_p2pkh,
- key_to_p2sh_p2wpkh,
- key_to_p2wpkh,
program_to_witness,
script_to_p2sh,
script_to_p2sh_p2wsh,
@@ -21,8 +20,6 @@ from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash16
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes, hex_str_to_bytes, sync_blocks, try_rpc
-from io import BytesIO
-
NODE_0 = 0
NODE_2 = 2
WIT_V0 = 0
@@ -46,9 +43,27 @@ class SegWitTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 3
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
- self.extra_args = [["-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
- ["-blockversion=4", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"],
- ["-blockversion=536870915", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [
+ [
+ "-rpcserialversion=0",
+ "-vbparams=segwit:0:999999999999",
+ "-addresstype=legacy",
+ ],
+ [
+ "-blockversion=4",
+ "-rpcserialversion=1",
+ "-vbparams=segwit:0:999999999999",
+ "-addresstype=legacy",
+ ],
+ [
+ "-blockversion=536870915",
+ "-vbparams=segwit:0:999999999999",
+ "-addresstype=legacy",
+ ],
+ ]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def setup_network(self):
super().setup_network()
@@ -70,9 +85,8 @@ class SegWitTest(BitcoinTestFramework):
def fail_accept(self, node, error_msg, txid, sign, redeem_script=""):
assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=sign, insert_redeem_script=redeem_script)
-
def run_test(self):
- self.nodes[0].generate(161) #block 161
+ self.nodes[0].generate(161) # block 161
self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
@@ -82,28 +96,24 @@ class SegWitTest(BitcoinTestFramework):
assert(tmpl['sigoplimit'] == 20000)
assert(tmpl['transactions'][0]['hash'] == txid)
assert(tmpl['transactions'][0]['sigops'] == 2)
- tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
+ tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
assert(tmpl['sizelimit'] == 1000000)
assert('weightlimit' not in tmpl)
assert(tmpl['sigoplimit'] == 20000)
assert(tmpl['transactions'][0]['hash'] == txid)
assert(tmpl['transactions'][0]['sigops'] == 2)
- self.nodes[0].generate(1) #block 162
+ self.nodes[0].generate(1) # block 162
balance_presetup = self.nodes[0].getbalance()
self.pubkey = []
- p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh
- wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness
+ p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh
+ wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness
for i in range(3):
newaddress = self.nodes[i].getnewaddress()
self.pubkey.append(self.nodes[i].getaddressinfo(newaddress)["pubkey"])
multiscript = CScript([OP_1, hex_str_to_bytes(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG])
- p2sh_addr = self.nodes[i].addwitnessaddress(newaddress)
- bip173_addr = self.nodes[i].addwitnessaddress(newaddress, False)
p2sh_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'p2sh-segwit')['address']
bip173_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'bech32')['address']
- assert_equal(p2sh_addr, key_to_p2sh_p2wpkh(self.pubkey[-1]))
- assert_equal(bip173_addr, key_to_p2wpkh(self.pubkey[-1]))
assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))
assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))
p2sh_ids.append([])
@@ -118,32 +128,32 @@ class SegWitTest(BitcoinTestFramework):
wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], False, Decimal("49.999")))
p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999")))
- self.nodes[0].generate(1) #block 163
+ self.nodes[0].generate(1) # block 163
sync_blocks(self.nodes)
# Make sure all nodes recognize the transactions as theirs
- assert_equal(self.nodes[0].getbalance(), balance_presetup - 60*50 + 20*Decimal("49.999") + 50)
- assert_equal(self.nodes[1].getbalance(), 20*Decimal("49.999"))
- assert_equal(self.nodes[2].getbalance(), 20*Decimal("49.999"))
+ assert_equal(self.nodes[0].getbalance(), balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50)
+ assert_equal(self.nodes[1].getbalance(), 20 * Decimal("49.999"))
+ assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999"))
- self.nodes[0].generate(260) #block 423
+ self.nodes[0].generate(260) # block 423
sync_blocks(self.nodes)
self.log.info("Verify witness txs are skipped for mining before the fork")
- self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424
- self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425
- self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426
- self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427
+ self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) # block 424
+ self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) # block 425
+ self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) # block 426
+ self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) # block 427
self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid")
self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False)
self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False)
- self.nodes[2].generate(4) # blocks 428-431
+ self.nodes[2].generate(4) # blocks 428-431
self.log.info("Verify previous witness txs skipped for mining can now be mined")
assert_equal(len(self.nodes[2].getrawmempool()), 4)
- block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3)
+ block = self.nodes[2].generate(1) # block 432 (first block with new rules; 432 = 144 * 3)
sync_blocks(self.nodes)
assert_equal(len(self.nodes[2].getrawmempool()), 0)
segwit_tx_list = self.nodes[2].getblock(block[0])["tx"]
@@ -160,8 +170,8 @@ class SegWitTest(BitcoinTestFramework):
self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
- assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
- assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
+ assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
+ assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
for i in range(len(segwit_tx_list)):
tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i]))
@@ -177,21 +187,21 @@ class SegWitTest(BitcoinTestFramework):
self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)', p2sh_ids[NODE_2][WIT_V1][2], sign=False, redeem_script=witness_script(True, self.pubkey[2]))
self.log.info("Verify default node can now use witness txs")
- self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432
- self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433
- self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434
- self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435
+ self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) # block 432
+ self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) # block 433
+ self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) # block 434
+ self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) # block 435
self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
+ tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
assert(tmpl['sizelimit'] >= 3999577) # actual maximum size is lower due to minimum mandatory non-witness data
assert(tmpl['weightlimit'] == 4000000)
assert(tmpl['sigoplimit'] == 80000)
assert(tmpl['transactions'][0]['txid'] == txid)
assert(tmpl['transactions'][0]['sigops'] == 8)
- self.nodes[0].generate(1) # Mine a block to clear the gbt cache
+ self.nodes[0].generate(1) # Mine a block to clear the gbt cache
self.log.info("Non-segwit miners are able to use GBT response after activation.")
# Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->
@@ -201,7 +211,7 @@ class SegWitTest(BitcoinTestFramework):
txid1 = send_to_witness(1, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996"))
hex_tx = self.nodes[0].gettransaction(txid)['hex']
tx = FromHex(CTransaction(), hex_tx)
- assert(tx.wit.is_null()) # This should not be a segwit input
+ assert(tx.wit.is_null()) # This should not be a segwit input
assert(txid1 in self.nodes[0].getrawmempool())
# Now create tx2, which will spend from txid1.
@@ -226,13 +236,13 @@ class SegWitTest(BitcoinTestFramework):
template = self.nodes[0].getblocktemplate()
# Check that tx1 is the only transaction of the 3 in the template.
- template_txids = [ t['txid'] for t in template['transactions'] ]
+ template_txids = [t['txid'] for t in template['transactions']]
assert(txid2 not in template_txids and txid3 not in template_txids)
assert(txid1 in template_txids)
# Check that running with segwit support results in all 3 being included.
template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
- template_txids = [ t['txid'] for t in template['transactions'] ]
+ template_txids = [t['txid'] for t in template['transactions']]
assert(txid1 in template_txids)
assert(txid2 in template_txids)
assert(txid3 in template_txids)
@@ -243,17 +253,17 @@ class SegWitTest(BitcoinTestFramework):
# Mine a block to clear the gbt cache again.
self.nodes[0].generate(1)
- self.log.info("Verify behaviour of importaddress, addwitnessaddress and listunspent")
+ self.log.info("Verify behaviour of importaddress and listunspent")
# Some public keys to be used later
pubkeys = [
- "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
- "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
- "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
- "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
- "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
- "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
- "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
+ "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
+ "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
+ "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
+ "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
+ "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
+ "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
+ "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
]
# Import a compressed key and an uncompressed key, generate some multisig addresses
@@ -261,8 +271,8 @@ class SegWitTest(BitcoinTestFramework):
uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"]
self.nodes[0].importprivkey("cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"]
- assert ((self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed'] == False))
- assert ((self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed'] == True))
+ assert not self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed']
+ assert self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed']
self.nodes[0].importpubkey(pubkeys[0])
compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
@@ -284,7 +294,6 @@ class SegWitTest(BitcoinTestFramework):
uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]])['address'])
compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])
compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]])['address'])
- unknown_address = ["mtKKyoHabkk6e4ppT7NaM7THqPUt7AzPrT", "2NDP3jLWAFT8NDAiUa9qiE6oBt2awmMq7Dx"]
# Test multisig_without_privkey
# We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
@@ -365,7 +374,6 @@ class SegWitTest(BitcoinTestFramework):
op1 = CScript([OP_1])
op0 = CScript([OP_0])
# 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
- unsolvable_address = ["mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V", "2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe", script_to_p2sh(op1), script_to_p2sh(op0)]
unsolvable_address_key = hex_str_to_bytes("02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D")
unsolvablep2pkh = CScript([OP_DUP, OP_HASH160, hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG])
unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)])
@@ -373,9 +381,9 @@ class SegWitTest(BitcoinTestFramework):
p2wshop1 = CScript([OP_0, sha256(op1)])
unsolvable_after_importaddress.append(unsolvablep2pkh)
unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
- unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script
+ unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script
unsolvable_after_importaddress.append(p2wshop1)
- unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided
+ unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided
unsolvable_after_importaddress.append(p2shop0)
spendable_txid = []
@@ -411,27 +419,14 @@ class SegWitTest(BitcoinTestFramework):
# exceptions and continue.
try_rpc(-4, "The wallet already contains the private key for this address or script", self.nodes[0].importaddress, i, "", False, True)
- self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only
- self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey
+ self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only
+ self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey
spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
self.mine_and_test_listunspent(unseen_anytime, 0)
- # addwitnessaddress should refuse to return a witness address if an uncompressed key is used
- # note that no witness address should be returned by unsolvable addresses
- for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address:
- assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i)
-
- # addwitnessaddress should return a witness addresses even if keys are not in the wallet
- self.nodes[0].addwitnessaddress(multisig_without_privkey_address)
-
- for i in compressed_spendable_address + compressed_solvable_address:
- witaddress = self.nodes[0].addwitnessaddress(i)
- # addwitnessaddress should return the same address if it is a known P2SH-witness address
- assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress))
-
spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
@@ -449,8 +444,6 @@ class SegWitTest(BitcoinTestFramework):
self.nodes[0].importpubkey(pubkeys[6])
uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]
- spendable_after_addwitnessaddress = [] # These outputs should be seen after importaddress
- solvable_after_addwitnessaddress=[] # These outputs should be seen after importaddress but not spendable
unseen_anytime = [] # These outputs should never be seen
solvable_anytime = [] # These outputs should be solvable after importpubkey
unseen_anytime = [] # These outputs should never be seen
@@ -467,8 +460,6 @@ class SegWitTest(BitcoinTestFramework):
v = self.nodes[0].getaddressinfo(i)
if (v['isscript']):
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after addwitnessaddress
- spendable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh])
premature_witaddress.append(script_to_p2sh(p2wsh))
else:
[p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
@@ -489,9 +480,7 @@ class SegWitTest(BitcoinTestFramework):
for i in compressed_solvable_address:
v = self.nodes[0].getaddressinfo(i)
if (v['isscript']):
- # P2WSH multisig without private key are seen after addwitnessaddress
[bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
- solvable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh])
premature_witaddress.append(script_to_p2sh(p2wsh))
else:
[p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
@@ -500,29 +489,11 @@ class SegWitTest(BitcoinTestFramework):
self.mine_and_test_listunspent(spendable_anytime, 2)
self.mine_and_test_listunspent(solvable_anytime, 1)
- self.mine_and_test_listunspent(spendable_after_addwitnessaddress + solvable_after_addwitnessaddress + unseen_anytime, 0)
-
- # addwitnessaddress should refuse to return a witness address if an uncompressed key is used
- # note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress
- # premature_witaddress are not accepted until the script is added with addwitnessaddress first
- for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress:
- # This will raise an exception
- assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i)
-
- # after importaddress it should pass addwitnessaddress
- v = self.nodes[0].getaddressinfo(compressed_solvable_address[1])
- self.nodes[0].importaddress(v['hex'],"",False,True)
- for i in compressed_spendable_address + compressed_solvable_address + premature_witaddress:
- witaddress = self.nodes[0].addwitnessaddress(i)
- assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress))
-
- spendable_txid.append(self.mine_and_test_listunspent(spendable_after_addwitnessaddress + spendable_anytime, 2))
- solvable_txid.append(self.mine_and_test_listunspent(solvable_after_addwitnessaddress + solvable_anytime, 1))
self.mine_and_test_listunspent(unseen_anytime, 0)
# Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works
- v1_addr = program_to_witness(1, [3,5])
- v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])],{v1_addr: 1})
+ v1_addr = program_to_witness(1, [3, 5])
+ v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])], {v1_addr: 1})
v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
assert_equal(v1_decoded['vout'][0]['scriptPubKey']['addresses'][0], v1_addr)
assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305")
@@ -565,7 +536,7 @@ class SegWitTest(BitcoinTestFramework):
def mine_and_test_listunspent(self, script_list, ismine):
utxo = find_spendable_utxo(self.nodes[0], 50)
tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(int('0x'+utxo['txid'],0), utxo['vout'])))
+ tx.vin.append(CTxIn(COutPoint(int('0x' + utxo['txid'], 0), utxo['vout'])))
for i in script_list:
tx.vout.append(CTxOut(10000000, i))
tx.rehash()
@@ -578,7 +549,7 @@ class SegWitTest(BitcoinTestFramework):
for i in self.nodes[0].listunspent():
if (i['txid'] == txid):
watchcount += 1
- if (i['spendable'] == True):
+ if i['spendable']:
spendcount += 1
if (ismine == 2):
assert_equal(spendcount, len(script_list))
@@ -589,14 +560,14 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(watchcount, 0)
return txid
- def p2sh_address_to_script(self,v):
+ def p2sh_address_to_script(self, v):
bare = CScript(hex_str_to_bytes(v['hex']))
p2sh = CScript(hex_str_to_bytes(v['scriptPubKey']))
p2wsh = CScript([OP_0, sha256(bare)])
p2sh_p2wsh = CScript([OP_HASH160, hash160(p2wsh), OP_EQUAL])
return([bare, p2sh, p2wsh, p2sh_p2wsh])
- def p2pkh_address_to_script(self,v):
+ def p2pkh_address_to_script(self, v):
pubkey = hex_str_to_bytes(v['pubkey'])
p2wpkh = CScript([OP_0, hash160(pubkey)])
p2sh_p2wpkh = CScript([OP_HASH160, hash160(p2wpkh), OP_EQUAL])
@@ -610,7 +581,7 @@ class SegWitTest(BitcoinTestFramework):
p2sh_p2wsh_p2pkh = CScript([OP_HASH160, hash160(p2wsh_p2pkh), OP_EQUAL])
return [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh]
- def create_and_mine_tx_from_txids(self, txids, success = True):
+ def create_and_mine_tx_from_txids(self, txids, success=True):
tx = CTransaction()
for i in txids:
txtmp = CTransaction()
@@ -618,7 +589,7 @@ class SegWitTest(BitcoinTestFramework):
f = BytesIO(hex_str_to_bytes(txraw))
txtmp.deserialize(f)
for j in range(len(txtmp.vout)):
- tx.vin.append(CTxIn(COutPoint(int('0x'+i,0), j)))
+ tx.vin.append(CTxIn(COutPoint(int('0x' + i, 0), j)))
tx.vout.append(CTxOut(0, CScript()))
tx.rehash()
signresults = self.nodes[0].signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize_without_witness()))['hex']
diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py
index 691a39b825..fb4ad21359 100755
--- a/test/functional/feature_uacomment.py
+++ b/test/functional/feature_uacomment.py
@@ -31,7 +31,7 @@ class UacommentTest(BitcoinTestFramework):
self.nodes[0].assert_start_raises_init_error(["-uacomment=" + 'a' * 256], expected, match=ErrorMatch.FULL_REGEX)
self.log.info("test -uacomment unsafe characters")
- for unsafe_char in ['/', ':', '(', ')']:
+ for unsafe_char in ['/', ':', '(', ')', '₿', '🏃']:
expected = "Error: User Agent comment \(" + re.escape(unsafe_char) + "\) contains unsafe characters."
self.nodes[0].assert_start_raises_init_error(["-uacomment=" + unsafe_char], expected, match=ErrorMatch.FULL_REGEX)
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index 896c36fa53..88df61cabc 100755
--- a/test/functional/feature_versionbits_warning.py
+++ b/test/functional/feature_versionbits_warning.py
@@ -65,13 +65,14 @@ class VersionBitsWarningTest(BitcoinTestFramework):
node = self.nodes[0]
node.add_p2p_connection(P2PInterface())
+ node_deterministic_address = node.get_deterministic_priv_key().address
# Mine one period worth of blocks
- node.generate(VB_PERIOD)
+ node.generatetoaddress(VB_PERIOD, node_deterministic_address)
self.log.info("Check that there is no warning if previous VB_BLOCKS have <VB_THRESHOLD blocks with unknown versionbits version.")
# Build one period of blocks with < VB_THRESHOLD blocks signaling some unknown bit
self.send_blocks_with_version(node.p2p, VB_THRESHOLD - 1, VB_UNKNOWN_VERSION)
- node.generate(VB_PERIOD - VB_THRESHOLD + 1)
+ node.generatetoaddress(VB_PERIOD - VB_THRESHOLD + 1, node_deterministic_address)
# Check that we're not getting any versionbit-related errors in get*info()
assert(not VB_PATTERN.match(node.getmininginfo()["warnings"]))
@@ -80,7 +81,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
self.log.info("Check that there is a warning if >50 blocks in the last 100 were an unknown version")
# Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit
self.send_blocks_with_version(node.p2p, VB_THRESHOLD, VB_UNKNOWN_VERSION)
- node.generate(VB_PERIOD - VB_THRESHOLD)
+ node.generatetoaddress(VB_PERIOD - VB_THRESHOLD, node_deterministic_address)
# Check that get*info() shows the 51/100 unknown block version error.
assert(WARN_UNKNOWN_RULES_MINED in node.getmininginfo()["warnings"])
@@ -89,16 +90,16 @@ class VersionBitsWarningTest(BitcoinTestFramework):
self.log.info("Check that there is a warning if previous VB_BLOCKS have >=VB_THRESHOLD blocks with unknown versionbits version.")
# Mine a period worth of expected blocks so the generic block-version warning
# is cleared. This will move the versionbit state to ACTIVE.
- node.generate(VB_PERIOD)
+ node.generatetoaddress(VB_PERIOD, node_deterministic_address)
# Stop-start the node. This is required because bitcoind will only warn once about unknown versions or unknown rules activating.
self.restart_node(0)
# Generating one block guarantees that we'll get out of IBD
- node.generate(1)
+ node.generatetoaddress(1, node_deterministic_address)
wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock)
# Generating one more block will be enough to generate an error.
- node.generate(1)
+ node.generatetoaddress(1, node_deterministic_address)
# Check that get*info() shows the versionbits unknown rules warning
assert(WARN_UNKNOWN_RULES_ACTIVE in node.getmininginfo()["warnings"])
assert(WARN_UNKNOWN_RULES_ACTIVE in node.getnetworkinfo()["warnings"])
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index d3b85ce948..aed439339f 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -18,10 +18,11 @@ class TestBitcoinCli(BitcoinTestFramework):
cli_response = self.nodes[0].cli("-version").send_cli()
assert("Bitcoin Core RPC client version" in cli_response)
- self.log.info("Compare responses from gewalletinfo RPC and `bitcoin-cli getwalletinfo`")
- cli_response = self.nodes[0].cli.getwalletinfo()
- rpc_response = self.nodes[0].getwalletinfo()
- assert_equal(cli_response, rpc_response)
+ self.log.info("Compare responses from getwalletinfo RPC and `bitcoin-cli getwalletinfo`")
+ if self.is_wallet_compiled():
+ cli_response = self.nodes[0].cli.getwalletinfo()
+ rpc_response = self.nodes[0].getwalletinfo()
+ assert_equal(cli_response, rpc_response)
self.log.info("Compare responses from getblockchaininfo RPC and `bitcoin-cli getblockchaininfo`")
cli_response = self.nodes[0].cli.getblockchaininfo()
@@ -49,26 +50,30 @@ class TestBitcoinCli(BitcoinTestFramework):
self.log.info("Compare responses from `bitcoin-cli -getinfo` and the RPCs data is retrieved from.")
cli_get_info = self.nodes[0].cli('-getinfo').send_cli()
- wallet_info = self.nodes[0].getwalletinfo()
+ if self.is_wallet_compiled():
+ wallet_info = self.nodes[0].getwalletinfo()
network_info = self.nodes[0].getnetworkinfo()
blockchain_info = self.nodes[0].getblockchaininfo()
assert_equal(cli_get_info['version'], network_info['version'])
assert_equal(cli_get_info['protocolversion'], network_info['protocolversion'])
- assert_equal(cli_get_info['walletversion'], wallet_info['walletversion'])
- assert_equal(cli_get_info['balance'], wallet_info['balance'])
+ if self.is_wallet_compiled():
+ assert_equal(cli_get_info['walletversion'], wallet_info['walletversion'])
+ assert_equal(cli_get_info['balance'], wallet_info['balance'])
assert_equal(cli_get_info['blocks'], blockchain_info['blocks'])
assert_equal(cli_get_info['timeoffset'], network_info['timeoffset'])
assert_equal(cli_get_info['connections'], network_info['connections'])
assert_equal(cli_get_info['proxy'], network_info['networks'][0]['proxy'])
assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty'])
assert_equal(cli_get_info['testnet'], blockchain_info['chain'] == "test")
- assert_equal(cli_get_info['balance'], wallet_info['balance'])
- assert_equal(cli_get_info['keypoololdest'], wallet_info['keypoololdest'])
- assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])
- assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee'])
- assert_equal(cli_get_info['relayfee'], network_info['relayfee'])
- # unlocked_until is not tested because the wallet is not encrypted
+ if self.is_wallet_compiled():
+ assert_equal(cli_get_info['balance'], wallet_info['balance'])
+ assert_equal(cli_get_info['keypoololdest'], wallet_info['keypoololdest'])
+ assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])
+ assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee'])
+ assert_equal(cli_get_info['relayfee'], network_info['relayfee'])
+ # unlocked_until is not tested because the wallet is not encrypted
+
if __name__ == '__main__':
TestBitcoinCli().main()
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index 41a1b4a35d..afa9de580f 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -43,6 +43,9 @@ class RESTTest (BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [["-rest"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def test_rest_request(self, uri, http_method='GET', req_type=ReqType.JSON, body='', status=200, ret_type=RetType.JSON):
rest_uri = '/rest' + uri
if req_type == ReqType.JSON:
diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py
new file mode 100755
index 0000000000..e3d7b0655d
--- /dev/null
+++ b/test/functional/interface_rpc.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 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 some generic aspects of the RPC interface."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class RPCInterfaceTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def test_batch_request(self):
+ self.log.info("Testing basic JSON-RPC batch request...")
+
+ results = self.nodes[0].batch([
+ # A basic request that will work fine.
+ {"method": "getblockcount", "id": 1},
+ # Request that will fail. The whole batch request should still
+ # work fine.
+ {"method": "invalidmethod", "id": 2},
+ # Another call that should succeed.
+ {"method": "getbestblockhash", "id": 3},
+ ])
+
+ result_by_id = {}
+ for res in results:
+ result_by_id[res["id"]] = res
+
+ assert_equal(result_by_id[1]['error'], None)
+ assert_equal(result_by_id[1]['result'], 0)
+
+ assert_equal(result_by_id[2]['error']['code'], -32601)
+ assert_equal(result_by_id[2]['result'], None)
+
+ assert_equal(result_by_id[3]['error'], None)
+ assert result_by_id[3]['result'] is not None
+
+ def run_test(self):
+ self.test_batch_request()
+
+
+if __name__ == '__main__':
+ RPCInterfaceTest().main()
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 72de696259..94fea37090 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -5,15 +5,18 @@
"""Test the ZMQ notification interface."""
import struct
-from test_framework.test_framework import (
- BitcoinTestFramework, skip_if_no_bitcoind_zmq, skip_if_no_py3_zmq)
+from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
+from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import CTransaction
-from test_framework.util import (assert_equal,
- bytes_to_hex_str,
- hash256,
- )
+from test_framework.util import (
+ assert_equal,
+ bytes_to_hex_str,
+ hash256,
+)
from io import BytesIO
+ADDRESS = "tcp://127.0.0.1:28332"
+
class ZMQSubscriber:
def __init__(self, socket, topic):
self.sequence = 0
@@ -37,9 +40,11 @@ class ZMQTest (BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_py3_zmq()
+ self.skip_if_no_bitcoind_zmq()
+
def setup_nodes(self):
- skip_if_no_py3_zmq()
- skip_if_no_bitcoind_zmq(self)
import zmq
# Initialize ZMQ context and socket.
@@ -47,11 +52,10 @@ class ZMQTest (BitcoinTestFramework):
# that this test fails if the publishing order changes.
# Note that the publishing order is not defined in the documentation and
# is subject to change.
- address = "tcp://127.0.0.1:28332"
self.zmq_context = zmq.Context()
socket = self.zmq_context.socket(zmq.SUB)
socket.set(zmq.RCVTIMEO, 60000)
- socket.connect(address)
+ socket.connect(ADDRESS)
# Subscribe to all available topics.
self.hashblock = ZMQSubscriber(socket, b"hashblock")
@@ -59,9 +63,13 @@ class ZMQTest (BitcoinTestFramework):
self.rawblock = ZMQSubscriber(socket, b"rawblock")
self.rawtx = ZMQSubscriber(socket, b"rawtx")
- self.extra_args = [["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]], []]
+ self.extra_args = [
+ ["-zmqpub%s=%s" % (sub.topic.decode(), ADDRESS) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]],
+ [],
+ ]
self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
+ self.import_deterministic_coinbase_privkeys()
def run_test(self):
try:
@@ -74,7 +82,7 @@ class ZMQTest (BitcoinTestFramework):
def _zmq_test(self):
num_blocks = 5
self.log.info("Generate %(n)d blocks (and %(n)d coinbase txes)" % {"n": num_blocks})
- genhashes = self.nodes[0].generate(num_blocks)
+ genhashes = self.nodes[0].generatetoaddress(num_blocks, ADDRESS_BCRT1_UNSPENDABLE)
self.sync_all()
for x in range(num_blocks):
@@ -98,17 +106,29 @@ class ZMQTest (BitcoinTestFramework):
block = self.rawblock.receive()
assert_equal(genhashes[x], bytes_to_hex_str(hash256(block[:80])))
- self.log.info("Wait for tx from second node")
- payment_txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)
- self.sync_all()
+ if self.is_wallet_compiled():
+ self.log.info("Wait for tx from second node")
+ payment_txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)
+ self.sync_all()
+
+ # Should receive the broadcasted txid.
+ txid = self.hashtx.receive()
+ assert_equal(payment_txid, bytes_to_hex_str(txid))
+
+ # Should receive the broadcasted raw transaction.
+ hex = self.rawtx.receive()
+ assert_equal(payment_txid, bytes_to_hex_str(hash256(hex)))
+
- # Should receive the broadcasted txid.
- txid = self.hashtx.receive()
- assert_equal(payment_txid, bytes_to_hex_str(txid))
+ self.log.info("Test the getzmqnotifications RPC")
+ assert_equal(self.nodes[0].getzmqnotifications(), [
+ {"type": "pubhashblock", "address": ADDRESS, "hwm": 1000},
+ {"type": "pubhashtx", "address": ADDRESS, "hwm": 1000},
+ {"type": "pubrawblock", "address": ADDRESS, "hwm": 1000},
+ {"type": "pubrawtx", "address": ADDRESS, "hwm": 1000},
+ ])
- # Should receive the broadcasted raw transaction.
- hex = self.rawtx.receive()
- assert_equal(payment_txid, bytes_to_hex_str(hash256(hex)))
+ assert_equal(self.nodes[1].getzmqnotifications(), [])
if __name__ == '__main__':
ZMQTest().main()
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 44426a0ff7..bec6a0050a 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -5,6 +5,7 @@
"""Test mempool acceptance of raw transactions."""
from io import BytesIO
+import math
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
BIP125_SEQUENCE_NUMBER,
@@ -40,6 +41,9 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
'-acceptnonstdtxn=0', # Try to mimic main-net
]] * self.num_nodes
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def check_mempool_result(self, result_expected, *args, **kwargs):
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
@@ -178,7 +182,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A really large transaction')
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
- tx.vin = [tx.vin[0]] * (MAX_BLOCK_BASE_SIZE // len(tx.vin[0].serialize()))
+ tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_BASE_SIZE / len(tx.vin[0].serialize()))
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}],
rawtxs=[bytes_to_hex_str(tx.serialize())],
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index 55422b67df..c0918893cd 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -15,6 +15,9 @@ class MempoolLimitTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
txouts = gen_return_txouts()
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index da254181fe..9336547a6b 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -18,6 +18,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
# Build a transaction that spends parent_txid:vout
# Return amount sent
def chain_transaction(self, node, parent_txid, vout, value, fee, num_outputs):
@@ -34,7 +37,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
return (txid, send_value)
def run_test(self):
- ''' Mine some blocks and have them mature. '''
+ # Mine some blocks and have them mature.
self.nodes[0].generate(101)
utxo = self.nodes[0].listunspent(10)
txid = utxo[0]['txid']
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index 6e5f89efb8..b4e9d967fd 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -47,6 +47,9 @@ class MempoolPersistTest(BitcoinTestFramework):
self.num_nodes = 3
self.extra_args = [[], ["-persistmempool=0"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
chain_height = self.nodes[0].getblockcount()
assert_equal(chain_height, 200)
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index faa00d56cf..123f0b4c28 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -17,6 +17,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
alert_filename = None # Set by setup_network
def run_test(self):
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 23939f0be5..845beb551e 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -13,6 +13,9 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
node0_address = self.nodes[0].getnewaddress()
# Spend block 1/2/3's coinbase transactions
@@ -44,12 +47,11 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
tx = self.nodes[0].gettransaction(txid)
assert(tx["confirmations"] > 0)
- # Use invalidateblock to re-org back; all transactions should
- # end up unconfirmed and back in the mempool
+ # Use invalidateblock to re-org back
for node in self.nodes:
node.invalidateblock(blocks[0])
- # mempool should be empty, all txns confirmed
+ # All txns should be back in mempool with 0 confirmations
assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id))
for txid in spends1_id+spends2_id:
tx = self.nodes[0].gettransaction(txid)
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index ce3bc3b7e0..854d506f0d 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -21,6 +21,9 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
chain_height = self.nodes[0].getblockcount()
assert_equal(chain_height, 200)
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index 15b2d7f757..9f01be0646 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -30,9 +30,10 @@ from test_framework.util import (
def assert_template(node, block, expect, rehash=True):
if rehash:
block.hashMerkleRoot = block.calc_merkle_root()
- rsp = node.getblocktemplate({'data': b2x(block.serialize()), 'mode': 'proposal'})
+ rsp = node.getblocktemplate(template_request={'data': b2x(block.serialize()), 'mode': 'proposal'})
assert_equal(rsp, expect)
+
class MiningTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
@@ -41,6 +42,12 @@ class MiningTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0]
+ def assert_submitblock(block, result_str_1, result_str_2=None):
+ block.solve()
+ result_str_2 = result_str_2 or 'duplicate-invalid'
+ assert_equal(result_str_1, node.submitblock(hexdata=b2x(block.serialize())))
+ assert_equal(result_str_2, node.submitblock(hexdata=b2x(block.serialize())))
+
self.log.info('getmininginfo')
mining_info = node.getmininginfo()
assert_equal(mining_info['blocks'], 200)
@@ -52,7 +59,7 @@ class MiningTest(BitcoinTestFramework):
assert_equal(mining_info['pooledtx'], 0)
# Mine a block to leave initial block download
- node.generate(1)
+ node.generatetoaddress(1, node.get_deterministic_priv_key().address)
tmpl = node.getblocktemplate()
self.log.info("getblocktemplate: Test capability advertised")
assert 'proposal' in tmpl['capabilities']
@@ -93,6 +100,7 @@ class MiningTest(BitcoinTestFramework):
bad_block = copy.deepcopy(block)
bad_block.vtx.append(bad_block.vtx[0])
assert_template(node, bad_block, 'bad-txns-duplicate')
+ assert_submitblock(bad_block, 'bad-txns-duplicate', 'bad-txns-duplicate')
self.log.info("getblocktemplate: Test invalid transaction")
bad_block = copy.deepcopy(block)
@@ -101,12 +109,14 @@ class MiningTest(BitcoinTestFramework):
bad_tx.rehash()
bad_block.vtx.append(bad_tx)
assert_template(node, bad_block, 'bad-txns-inputs-missingorspent')
+ assert_submitblock(bad_block, 'bad-txns-inputs-missingorspent')
self.log.info("getblocktemplate: Test nonfinal transaction")
bad_block = copy.deepcopy(block)
bad_block.vtx[0].nLockTime = 2 ** 32 - 1
bad_block.vtx[0].rehash()
assert_template(node, bad_block, 'bad-txns-nonfinal')
+ assert_submitblock(bad_block, 'bad-txns-nonfinal')
self.log.info("getblocktemplate: Test bad tx count")
# The tx count is immediately after the block header
@@ -125,24 +135,29 @@ class MiningTest(BitcoinTestFramework):
bad_block = copy.deepcopy(block)
bad_block.hashMerkleRoot += 1
assert_template(node, bad_block, 'bad-txnmrklroot', False)
+ assert_submitblock(bad_block, 'bad-txnmrklroot', 'bad-txnmrklroot')
self.log.info("getblocktemplate: Test bad timestamps")
bad_block = copy.deepcopy(block)
bad_block.nTime = 2 ** 31 - 1
assert_template(node, bad_block, 'time-too-new')
+ assert_submitblock(bad_block, 'time-too-new', 'time-too-new')
bad_block.nTime = 0
assert_template(node, bad_block, 'time-too-old')
+ assert_submitblock(bad_block, 'time-too-old', 'time-too-old')
self.log.info("getblocktemplate: Test not best block")
bad_block = copy.deepcopy(block)
bad_block.hashPrevBlock = 123
assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
+ assert_submitblock(bad_block, 'prev-blk-not-found', 'prev-blk-not-found')
self.log.info('submitheader tests')
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * 80))
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * 78))
assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata='ff' * 80))
+ block.nTime += 1
block.solve()
def chain_tip(b_hash, *, status='headers-only', branchlen=1):
@@ -161,7 +176,8 @@ class MiningTest(BitcoinTestFramework):
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
assert chain_tip(bad_block_root.hash) in node.getchaintips()
# Should still reject invalid blocks, even if we have the header:
- assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'invalid')
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot')
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot')
assert chain_tip(bad_block_root.hash) in node.getchaintips()
# We know the header for this invalid block, so should just return early without error:
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
@@ -172,7 +188,8 @@ class MiningTest(BitcoinTestFramework):
bad_block_lock.vtx[0].rehash()
bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()
bad_block_lock.solve()
- assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'invalid')
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'bad-txns-nonfinal')
+ assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'duplicate-invalid')
# Build a "good" block on top of the submitted bad block
bad_block2 = copy.deepcopy(block)
bad_block2.hashPrevBlock = bad_block_lock.sha256
@@ -188,16 +205,17 @@ class MiningTest(BitcoinTestFramework):
# Should ask for the block from a p2p node, if they announce the header as well:
node.add_p2p_connection(P2PDataStore())
node.p2p.wait_for_getheaders(timeout=5) # Drop the first getheaders
- node.p2p.send_blocks_and_test(blocks=[block], rpc=node)
+ node.p2p.send_blocks_and_test(blocks=[block], node=node)
# Must be active now:
assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips()
# Building a few blocks should give the same results
- node.generate(10)
+ node.generatetoaddress(10, node.get_deterministic_priv_key().address)
assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
node.submitheader(hexdata=b2x(CBlockHeader(block).serialize()))
node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
+ assert_equal(node.submitblock(hexdata=b2x(block.serialize())), 'duplicate') # valid
if __name__ == '__main__':
diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py
index 2bcbe8db7b..9a3c15a4a7 100755
--- a/test/functional/mining_getblocktemplate_longpoll.py
+++ b/test/functional/mining_getblocktemplate_longpoll.py
@@ -15,8 +15,8 @@ class LongpollThread(threading.Thread):
def __init__(self, node):
threading.Thread.__init__(self)
# query current longpollid
- templat = node.getblocktemplate()
- self.longpollid = templat['longpollid']
+ template = node.getblocktemplate()
+ self.longpollid = template['longpollid']
# create a new connection to the node, we can't use the same
# connection from two threads
self.node = get_rpc_proxy(node.url, 1, timeout=600, coveragedir=node.coverage_dir)
@@ -28,14 +28,17 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.")
self.nodes[0].generate(10)
- templat = self.nodes[0].getblocktemplate()
- longpollid = templat['longpollid']
+ template = self.nodes[0].getblocktemplate()
+ longpollid = template['longpollid']
# longpollid should not change between successive invocations if nothing else happens
- templat2 = self.nodes[0].getblocktemplate()
- assert(templat2['longpollid'] == longpollid)
+ template2 = self.nodes[0].getblocktemplate()
+ assert(template2['longpollid'] == longpollid)
# Test 1: test that the longpolling wait if we do nothing
thr = LongpollThread(self.nodes[0])
@@ -70,4 +73,3 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
if __name__ == '__main__':
GetBlockTemplateLPTest().main()
-
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index bb0cc082ab..c5ddee56f1 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -16,6 +16,9 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [["-printpriority=1"], ["-printpriority=1"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Test `prioritisetransaction` required parameters
assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction)
@@ -26,7 +29,8 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction, '', 0, 0, 0)
# Test `prioritisetransaction` invalid `txid`
- assert_raises_rpc_error(-1, "txid must be hexadecimal string", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0)
+ assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0)
+ assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000')", self.nodes[0].prioritisetransaction, txid='Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000', fee_delta=0)
# Test `prioritisetransaction` invalid `dummy`
txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 5cec5dc6f0..f0dee59b5c 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -7,7 +7,6 @@
Version 1 compact blocks are pre-segwit (txids)
Version 2 compact blocks are post-segwit (wtxids)
"""
-
from decimal import Decimal
import random
@@ -99,9 +98,12 @@ class CompactBlocksTest(BitcoinTestFramework):
self.num_nodes = 2
# This test was written assuming SegWit is activated using BIP9 at height 432 (3x confirmation window).
# TODO: Rewrite this test to support SegWit being always active.
- self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex", "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex"]]
self.utxos = []
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def build_block_on_tip(self, node, segwit=False):
height = node.getblockcount()
tip = node.getbestblockhash()
@@ -186,7 +188,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Now try a SENDCMPCT message with too-high version
sendcmpct = msg_sendcmpct()
- sendcmpct.version = preferred_version+1
+ sendcmpct.version = preferred_version + 1
sendcmpct.announce = True
test_node.send_and_ping(sendcmpct)
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
@@ -217,7 +219,7 @@ class CompactBlocksTest(BitcoinTestFramework):
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
# Try one more time, after sending a version-1, announce=false message.
- sendcmpct.version = preferred_version-1
+ sendcmpct.version = preferred_version - 1
sendcmpct.announce = False
test_node.send_and_ping(sendcmpct)
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
@@ -231,7 +233,7 @@ class CompactBlocksTest(BitcoinTestFramework):
if old_node is not None:
# Verify that a peer using an older protocol version can receive
# announcements from this node.
- sendcmpct.version = preferred_version-1
+ sendcmpct.version = preferred_version - 1
sendcmpct.announce = True
old_node.send_and_ping(sendcmpct)
# Header sync
@@ -262,9 +264,9 @@ class CompactBlocksTest(BitcoinTestFramework):
if use_witness_address:
# Want at least one segwit spend, so move all funds to
# a witness address.
- address = node.addwitnessaddress(address)
+ address = node.getnewaddress(address_type='bech32')
value_to_send = node.getbalance()
- node.sendtoaddress(address, satoshi_round(value_to_send-Decimal(0.1)))
+ node.sendtoaddress(address, satoshi_round(value_to_send - Decimal(0.1)))
node.generate(1)
segwit_tx_generated = False
@@ -276,7 +278,7 @@ class CompactBlocksTest(BitcoinTestFramework):
segwit_tx_generated = True
if use_witness_address:
- assert(segwit_tx_generated) # check that our test is not broken
+ assert segwit_tx_generated # check that our test is not broken
# Wait until we've seen the block announcement for the resulting tip
tip = int(node.getbestblockhash(), 16)
@@ -290,7 +292,7 @@ class CompactBlocksTest(BitcoinTestFramework):
block_hash = int(node.generate(1)[0], 16)
# Store the raw block in our internal format.
- block = FromHex(CBlock(), node.getblock("%02x" % block_hash, False))
+ block = FromHex(CBlock(), node.getblock("%064x" % block_hash, False))
for tx in block.vtx:
tx.calc_sha256()
block.rehash()
@@ -400,8 +402,7 @@ class CompactBlocksTest(BitcoinTestFramework):
coinbase_hash = block.vtx[0].sha256
if version == 2:
coinbase_hash = block.vtx[0].calc_sha256(True)
- comp_block.shortids = [
- calculate_shortid(k0, k1, coinbase_hash) ]
+ comp_block.shortids = [calculate_shortid(k0, k1, coinbase_hash)]
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
# Expect a getblocktxn message.
@@ -440,7 +441,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# node needs, and that responding to them causes the block to be
# reconstructed.
def test_getblocktxn_requests(self, node, test_node, version):
- with_witness = (version==2)
+ with_witness = (version == 2)
def test_getblocktxn_response(compact_block, peer, expected_result):
msg = msg_cmpctblock(compact_block.to_p2p())
@@ -467,7 +468,7 @@ class CompactBlocksTest(BitcoinTestFramework):
msg_bt = msg_blocktxn()
if with_witness:
- msg_bt = msg_witness_blocktxn() # serialize with witnesses
+ msg_bt = msg_witness_blocktxn() # serialize with witnesses
msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[1:])
test_tip_after_message(node, test_node, msg_bt, block.sha256)
@@ -557,7 +558,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# verifying that the block isn't marked bad permanently. This is good
# enough for now.
msg = msg_blocktxn()
- if version==2:
+ if version == 2:
msg = msg_witness_blocktxn()
msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]] + block.vtx[7:])
test_node.send_and_ping(msg)
@@ -568,11 +569,11 @@ class CompactBlocksTest(BitcoinTestFramework):
# We should receive a getdata request
wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock)
assert_equal(len(test_node.last_message["getdata"].inv), 1)
- assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2|MSG_WITNESS_FLAG)
+ assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2 | MSG_WITNESS_FLAG)
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
# Deliver the block
- if version==2:
+ if version == 2:
test_node.send_and_ping(msg_witness_block(block))
else:
test_node.send_and_ping(msg_block(block))
@@ -652,7 +653,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Generate an old compactblock, and verify that it's not accepted.
cur_height = node.getblockcount()
- hashPrevBlock = int(node.getblockhash(cur_height-5), 16)
+ hashPrevBlock = int(node.getblockhash(cur_height - 5), 16)
block = self.build_block_on_tip(node)
block.hashPrevBlock = hashPrevBlock
block.solve()
@@ -681,7 +682,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert "blocktxn" not in test_node.last_message
def activate_segwit(self, node):
- node.generate(144*3)
+ node.generate(144 * 3)
assert_equal(get_bip9_status(node, "segwit")["status"], 'active')
def test_end_to_end_block_relay(self, node, listeners):
@@ -777,7 +778,7 @@ class CompactBlocksTest(BitcoinTestFramework):
delivery_peer.send_message(msg_tx(tx))
delivery_peer.sync_with_ping()
- cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [ CTxInWitness() ]
+ cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [CTxInWitness()]
cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
cmpct_block.use_witness = True
@@ -883,7 +884,7 @@ class CompactBlocksTest(BitcoinTestFramework):
self.log.info("Syncing nodes...")
assert(self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash())
while (self.nodes[0].getblockcount() > self.nodes[1].getblockcount()):
- block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount()+1)
+ block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount() + 1)
self.nodes[1].submitblock(self.nodes[0].getblock(block_hash, False))
assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())
diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py
index 67f24d6bff..1b11a2a294 100755
--- a/test/functional/p2p_disconnect_ban.py
+++ b/test/functional/p2p_disconnect_ban.py
@@ -22,7 +22,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("setban: successfully ban single IP address")
assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point
- self.nodes[1].setban("127.0.0.1", "add")
+ self.nodes[1].setban(subnet="127.0.0.1", command="add")
wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10)
assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point
assert_equal(len(self.nodes[1].listbanned()), 1)
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index 3bc7734e75..d589519e45 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -42,6 +42,9 @@ class FeeFilterTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
node1 = self.nodes[1]
node0 = self.nodes[0]
diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py
index 4a6ffced93..fab0887197 100755
--- a/test/functional/p2p_fingerprint.py
+++ b/test/functional/p2p_fingerprint.py
@@ -80,7 +80,7 @@ class P2PFingerprintTest(BitcoinTestFramework):
self.nodes[0].setmocktime(int(time.time()) - 60 * 24 * 60 * 60)
# Generating a chain of 10 blocks
- block_hashes = self.nodes[0].generate(nblocks=10)
+ block_hashes = self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
# Create longer chain starting 2 blocks before current tip
height = len(block_hashes) - 2
@@ -111,7 +111,7 @@ class P2PFingerprintTest(BitcoinTestFramework):
# Longest chain is extended so stale is much older than chain tip
self.nodes[0].setmocktime(0)
- tip = self.nodes[0].generate(nblocks=1)[0]
+ tip = self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0]
assert_equal(self.nodes[0].getblockcount(), 14)
# Send getdata & getheaders to refresh last received getheader message
diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py
index e910bedd09..1e0b876593 100755
--- a/test/functional/p2p_invalid_block.py
+++ b/test/functional/p2p_invalid_block.py
@@ -42,10 +42,10 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
# Save the coinbase for later
block1 = block
tip = block.sha256
- node.p2p.send_blocks_and_test([block1], node, True)
+ node.p2p.send_blocks_and_test([block1], node, success=True)
self.log.info("Mature the block.")
- node.generate(100)
+ node.generatetoaddress(100, node.get_deterministic_priv_key().address)
best_block = node.getblock(node.getbestblockhash())
tip = int(node.getbestblockhash(), 16)
@@ -77,9 +77,19 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
block2.vtx.append(tx2)
assert_equal(block2.hashMerkleRoot, block2.calc_merkle_root())
assert_equal(orig_hash, block2.rehash())
- assert(block2_orig.vtx != block2.vtx)
+ assert block2_orig.vtx != block2.vtx
- node.p2p.send_blocks_and_test([block2], node, False, False, 16, b'bad-txns-duplicate')
+ node.p2p.send_blocks_and_test([block2], node, success=False, reject_reason='bad-txns-duplicate')
+
+ # Check transactions for duplicate inputs
+ self.log.info("Test duplicate input block.")
+
+ block2_orig.vtx[2].vin.append(block2_orig.vtx[2].vin[0])
+ block2_orig.vtx[2].rehash()
+ block2_orig.hashMerkleRoot = block2_orig.calc_merkle_root()
+ block2_orig.rehash()
+ block2_orig.solve()
+ node.p2p.send_blocks_and_test([block2_orig], node, success=False, reject_reason='bad-txns-inputs-duplicate')
self.log.info("Test very broken block.")
@@ -92,7 +102,8 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
block3.rehash()
block3.solve()
- node.p2p.send_blocks_and_test([block3], node, False, False, 16, b'bad-cb-amount')
+ node.p2p.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount')
+
if __name__ == '__main__':
InvalidBlockRequestTest().main()
diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py
index 3b1654f920..c8c752d1f7 100755
--- a/test/functional/p2p_invalid_locator.py
+++ b/test/functional/p2p_invalid_locator.py
@@ -17,7 +17,7 @@ class InvalidLocatorTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0] # convenience reference to the node
- node.generate(1) # Get node out of IBD
+ node.generatetoaddress(1, node.get_deterministic_priv_key().address) # Get node out of IBD
self.log.info('Test max locator size')
block_count = node.getblockcount()
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
new file mode 100755
index 0000000000..65997a5f9d
--- /dev/null
+++ b/test/functional/p2p_invalid_messages.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+# Copyright (c) 2015-2018 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 node responses to invalid network messages."""
+import os
+import struct
+
+from test_framework import messages
+from test_framework.mininode import P2PDataStore
+from test_framework.test_framework import BitcoinTestFramework
+
+
+class msg_unrecognized:
+ """Nonsensical message. Modeled after similar types in test_framework.messages."""
+
+ command = b'badmsg'
+
+ def __init__(self, str_data):
+ self.str_data = str_data.encode() if not isinstance(str_data, bytes) else str_data
+
+ def serialize(self):
+ return messages.ser_string(self.str_data)
+
+ def __repr__(self):
+ return "{}(data={})".format(self.command, self.str_data)
+
+
+class msg_nametoolong(msg_unrecognized):
+
+ command = b'thisnameiswayyyyyyyyytoolong'
+
+
+class InvalidMessagesTest(BitcoinTestFramework):
+
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def run_test(self):
+ """
+ 0. Send a bunch of large (4MB) messages of an unrecognized type. Check to see
+ that it isn't an effective DoS against the node.
+
+ 1. Send an oversized (4MB+) message and check that we're disconnected.
+
+ 2. Send a few messages with an incorrect data size in the header, ensure the
+ messages are ignored.
+
+ 3. Send an unrecognized message with a command name longer than 12 characters.
+
+ """
+ node = self.nodes[0]
+ self.node = node
+ node.add_p2p_connection(P2PDataStore())
+ conn2 = node.add_p2p_connection(P2PDataStore())
+
+ msg_limit = 4 * 1000 * 1000 # 4MB, per MAX_PROTOCOL_MESSAGE_LENGTH
+ valid_data_limit = msg_limit - 5 # Account for the 4-byte length prefix
+
+ #
+ # 0.
+ #
+ # Send as large a message as is valid, ensure we aren't disconnected but
+ # also can't exhaust resources.
+ #
+ msg_at_size = msg_unrecognized("b" * valid_data_limit)
+ assert len(msg_at_size.serialize()) == msg_limit
+
+ increase_allowed = 0.5
+ if [s for s in os.environ.get("BITCOIN_CONFIG", "").split(" ") if "--with-sanitizers" in s and "address" in s]:
+ increase_allowed = 3.5
+ with node.assert_memory_usage_stable(increase_allowed=increase_allowed):
+ self.log.info(
+ "Sending a bunch of large, junk messages to test "
+ "memory exhaustion. May take a bit...")
+
+ # Run a bunch of times to test for memory exhaustion.
+ for _ in range(80):
+ node.p2p.send_message(msg_at_size)
+
+ # Check that, even though the node is being hammered by nonsense from one
+ # connection, it can still service other peers in a timely way.
+ for _ in range(20):
+ conn2.sync_with_ping(timeout=2)
+
+ # Peer 1, despite serving up a bunch of nonsense, should still be connected.
+ self.log.info("Waiting for node to drop junk messages.")
+ node.p2p.sync_with_ping(timeout=30)
+ assert node.p2p.is_connected
+
+ #
+ # 1.
+ #
+ # Send an oversized message, ensure we're disconnected.
+ #
+ msg_over_size = msg_unrecognized("b" * (valid_data_limit + 1))
+ assert len(msg_over_size.serialize()) == (msg_limit + 1)
+
+ with node.assert_debug_log(["Oversized message from peer=0, disconnecting"]):
+ # An unknown message type (or *any* message type) over
+ # MAX_PROTOCOL_MESSAGE_LENGTH should result in a disconnect.
+ node.p2p.send_message(msg_over_size)
+ node.p2p.wait_for_disconnect(timeout=4)
+
+ node.disconnect_p2ps()
+ conn = node.add_p2p_connection(P2PDataStore())
+ conn.wait_for_verack()
+
+ #
+ # 2.
+ #
+ # Send messages with an incorrect data size in the header.
+ #
+ actual_size = 100
+ msg = msg_unrecognized("b" * actual_size)
+
+ # TODO: handle larger-than cases. I haven't been able to pin down what behavior to expect.
+ for wrong_size in (2, 77, 78, 79):
+ self.log.info("Sending a message with incorrect size of {}".format(wrong_size))
+
+ # Unmodified message should submit okay.
+ node.p2p.send_and_ping(msg)
+
+ # A message lying about its data size results in a disconnect when the incorrect
+ # data size is less than the actual size.
+ #
+ # TODO: why does behavior change at 78 bytes?
+ #
+ node.p2p.send_raw_message(self._tweak_msg_data_size(msg, wrong_size))
+
+ # For some reason unknown to me, we sometimes have to push additional data to the
+ # peer in order for it to realize a disconnect.
+ try:
+ node.p2p.send_message(messages.msg_ping(nonce=123123))
+ except IOError:
+ pass
+
+ node.p2p.wait_for_disconnect(timeout=10)
+ node.disconnect_p2ps()
+ node.add_p2p_connection(P2PDataStore())
+
+ #
+ # 3.
+ #
+ # Send a message with a too-long command name.
+ #
+ node.p2p.send_message(msg_nametoolong("foobar"))
+ node.p2p.wait_for_disconnect(timeout=4)
+
+ # Node is still up.
+ conn = node.add_p2p_connection(P2PDataStore())
+ conn.sync_with_ping()
+
+
+ def _tweak_msg_data_size(self, message, wrong_size):
+ """
+ Return a raw message based on another message but with an incorrect data size in
+ the message header.
+ """
+ raw_msg = self.node.p2p.build_message(message)
+
+ bad_size_bytes = struct.pack("<I", wrong_size)
+ num_header_bytes_before_size = 4 + 12
+
+ # Replace the correct data size in the message with an incorrect one.
+ raw_msg_with_wrong_size = (
+ raw_msg[:num_header_bytes_before_size] +
+ bad_size_bytes +
+ raw_msg[(num_header_bytes_before_size + len(bad_size_bytes)):]
+ )
+ assert len(raw_msg) == len(raw_msg_with_wrong_size)
+
+ return raw_msg_with_wrong_size
+
+
+
+if __name__ == '__main__':
+ InvalidMessagesTest().main()
diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py
index 12bc62131f..58e129b57d 100755
--- a/test/functional/p2p_invalid_tx.py
+++ b/test/functional/p2p_invalid_tx.py
@@ -61,7 +61,7 @@ class InvalidTxRequestTest(BitcoinTestFramework):
node.p2p.send_blocks_and_test([block], node, success=True)
self.log.info("Mature the block.")
- self.nodes[0].generate(100)
+ self.nodes[0].generatetoaddress(100, self.nodes[0].get_deterministic_priv_key().address)
# b'\x64' is OP_NOTIF
# Transaction will be rejected with code 16 (REJECT_INVALID)
@@ -76,7 +76,7 @@ class InvalidTxRequestTest(BitcoinTestFramework):
self.reconnect_p2p(num_connections=2)
self.log.info('Test orphan transaction handling ... ')
- # Create a root transaction that we withhold until all dependend transactions
+ # Create a root transaction that we withhold until all dependent transactions
# are sent out and in the orphan cache
SCRIPT_PUB_KEY_OP_TRUE = b'\x51\x75' * 15 + b'\x51'
tx_withhold = CTransaction()
@@ -116,7 +116,8 @@ class InvalidTxRequestTest(BitcoinTestFramework):
assert_equal(2, len(node.getpeerinfo())) # p2ps[1] is still connected
self.log.info('Send the withhold tx ... ')
- node.p2p.send_txs_and_test([tx_withhold], node, success=True)
+ with node.assert_debug_log(expected_msgs=["bad-txns-in-belowout"]):
+ node.p2p.send_txs_and_test([tx_withhold], node, success=True)
# Transactions that should end up in the mempool
expected_mempool = {
@@ -134,18 +135,6 @@ class InvalidTxRequestTest(BitcoinTestFramework):
wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12) # p2ps[1] is no longer connected
assert_equal(expected_mempool, set(node.getrawmempool()))
- # restart node with sending BIP61 messages disabled, check that it disconnects without sending the reject message
- self.log.info('Test a transaction that is rejected, with BIP61 disabled')
- self.restart_node(0, ['-enablebip61=0', '-persistmempool=0'])
- self.reconnect_p2p(num_connections=1)
- with node.assert_debug_log(expected_msgs=[
- "{} from peer=0 was not accepted: mandatory-script-verify-flag-failed (Invalid OP_IF construction) (code 16)".format(tx1.hash),
- "disconnecting peer=0",
- ]):
- node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
- # send_txs_and_test will have waited for disconnect, so we can safely check that no reject has been received
- assert_equal(node.p2p.reject_code_received, None)
-
if __name__ == '__main__':
InvalidTxRequestTest().main()
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index dcbf833e7c..336d34a81d 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -103,7 +103,7 @@ class P2PLeakTest(BitcoinTestFramework):
wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)
# Mine a block and make sure that it's not sent to the connected nodes
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
#Give the node enough time to possibly leak out a message
time.sleep(5)
diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py
new file mode 100755
index 0000000000..dc4d475b2d
--- /dev/null
+++ b/test/functional/p2p_leak_tx.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017-2018 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 that we don't leak txs to inbound peers that we haven't yet announced to"""
+
+from test_framework.messages import msg_getdata, CInv
+from test_framework.mininode import P2PDataStore
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+
+
+class P2PNode(P2PDataStore):
+ def on_inv(self, msg):
+ pass
+
+
+class P2PLeakTxTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ gen_node = self.nodes[0] # The block and tx generating node
+ gen_node.generate(1)
+
+ inbound_peer = self.nodes[0].add_p2p_connection(P2PNode()) # An "attacking" inbound peer
+
+ MAX_REPEATS = 100
+ self.log.info("Running test up to {} times.".format(MAX_REPEATS))
+ for i in range(MAX_REPEATS):
+ self.log.info('Run repeat {}'.format(i + 1))
+ txid = gen_node.sendtoaddress(gen_node.getnewaddress(), 0.01)
+
+ want_tx = msg_getdata()
+ want_tx.inv.append(CInv(t=1, h=int(txid, 16)))
+ inbound_peer.last_message.pop('notfound', None)
+ inbound_peer.send_message(want_tx)
+ inbound_peer.sync_with_ping()
+
+ if inbound_peer.last_message.get('notfound'):
+ self.log.debug('tx {} was not yet announced to us.'.format(txid))
+ self.log.debug("node has responded with a notfound message. End test.")
+ assert_equal(inbound_peer.last_message['notfound'].vec[0].hash, int(txid, 16))
+ inbound_peer.last_message.pop('notfound')
+ break
+ else:
+ self.log.debug('tx {} was already announced to us. Try test again.'.format(txid))
+ assert int(txid, 16) in [inv.hash for inv in inbound_peer.last_message['inv'].inv]
+
+
+if __name__ == '__main__':
+ P2PLeakTxTest().main()
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index c987bf4b05..359880506e 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -43,8 +43,8 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
disconnect_nodes(self.nodes[1], 2)
def setup_network(self):
- super(NodeNetworkLimitedTest, self).setup_network()
- self.disconnect_all()
+ self.add_nodes(self.num_nodes, self.extra_args)
+ self.start_nodes()
def run_test(self):
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
@@ -59,7 +59,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.log.info("Mine enough blocks to reach the NODE_NETWORK_LIMITED range.")
connect_nodes_bi(self.nodes, 0, 1)
- blocks = self.nodes[1].generate(292)
+ blocks = self.nodes[1].generatetoaddress(292, self.nodes[1].get_deterministic_priv_key().address)
sync_blocks([self.nodes[0], self.nodes[1]])
self.log.info("Make sure we can max retrieve block at tip-288.")
@@ -89,7 +89,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)
except:
pass
- # node2 must remain at heigh 0
+ # node2 must remain at height 0
assert_equal(self.nodes[2].getblockheader(self.nodes[2].getbestblockhash())['height'], 0)
# now connect also to node 1 (non pruned)
@@ -102,7 +102,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.disconnect_all()
# mine 10 blocks on node 0 (pruned node)
- self.nodes[0].generate(10)
+ self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
# connect node1 (non pruned) with node0 (pruned) and check if the can sync
connect_nodes_bi(self.nodes, 0, 1)
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index be79a13237..afbbfa8992 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -41,7 +41,6 @@ from test_framework.messages import (
from test_framework.mininode import (
P2PInterface,
mininode_lock,
- wait_until,
)
from test_framework.script import (
CScript,
@@ -119,37 +118,28 @@ def get_virtual_size(witness_block):
vsize = int((3 * base_size + total_size + 3) / 4)
return vsize
-def test_transaction_acceptance(rpc, p2p, tx, with_witness, accepted, reason=None):
+def test_transaction_acceptance(node, p2p, tx, with_witness, accepted, reason=None):
"""Send a transaction to the node and check that it's accepted to the mempool
- Submit the transaction over the p2p interface
- use the getrawmempool rpc to check for acceptance."""
- tx_message = msg_tx(tx)
- if with_witness:
- tx_message = msg_witness_tx(tx)
- p2p.send_message(tx_message)
- p2p.sync_with_ping()
- assert_equal(tx.hash in rpc.getrawmempool(), accepted)
- if (reason is not None and not accepted):
- # Check the rejection reason as well.
- with mininode_lock:
- assert_equal(p2p.last_message["reject"].reason, reason)
+ reason = [reason] if reason else []
+ with node.assert_debug_log(expected_msgs=reason):
+ p2p.send_message(msg_witness_tx(tx) if with_witness else msg_tx(tx))
+ p2p.sync_with_ping()
+ assert_equal(tx.hash in node.getrawmempool(), accepted)
-def test_witness_block(rpc, p2p, block, accepted, with_witness=True, reason=None):
+def test_witness_block(node, p2p, block, accepted, with_witness=True, reason=None):
"""Send a block to the node and check that it's accepted
- Submit the block over the p2p interface
- use the getbestblockhash rpc to check for acceptance."""
- if with_witness:
- p2p.send_message(msg_witness_block(block))
- else:
- p2p.send_message(msg_block(block))
- p2p.sync_with_ping()
- assert_equal(rpc.getbestblockhash() == block.hash, accepted)
- if (reason is not None and not accepted):
- # Check the rejection reason as well.
- with mininode_lock:
- assert_equal(p2p.last_message["reject"].reason, reason)
+ reason = [reason] if reason else []
+ with node.assert_debug_log(expected_msgs=reason):
+ p2p.send_message(msg_witness_block(block) if with_witness else msg_block(block))
+ p2p.sync_with_ping()
+ assert_equal(node.getbestblockhash() == block.hash, accepted)
+
class TestP2PConn(P2PInterface):
def __init__(self):
@@ -198,6 +188,9 @@ class SegWitTest(BitcoinTestFramework):
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
self.extra_args = [["-whitelist=127.0.0.1", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
connect_nodes(self.nodes[0], 1)
@@ -212,7 +205,7 @@ class SegWitTest(BitcoinTestFramework):
height = self.nodes[0].getblockcount() + 1
block_time = self.nodes[0].getblockheader(tip)["mediantime"] + 1
block = create_block(int(tip, 16), create_coinbase(height), block_time)
- block.version = version
+ block.nVersion = version
block.rehash()
return block
@@ -349,8 +342,7 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx])
# Sending witness data before activation is not allowed (anti-spam
# rule).
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
- wait_until(lambda: 'reject' in self.test_node.last_message and self.test_node.last_message["reject"].reason == b"unexpected-witness")
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='unexpected-witness')
# But it should not be permanently marked bad...
# Resend without witness information.
@@ -380,20 +372,20 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)
assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block1, True)
+ test_witness_block(self.nodes[0], self.test_node, block1, True)
block2 = self.build_next_block(version=4)
block2.solve()
self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block2, True)
+ test_witness_block(self.nodes[0], self.test_node, block2, True)
block3 = self.build_next_block(version=(VB_TOP_BITS | (1 << 15)))
block3.solve()
self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
- test_witness_block(self.nodes[0].rpc, self.test_node, block3, True)
+ test_witness_block(self.nodes[0], self.test_node, block3, True)
# Check that we can getdata for witness blocks or regular blocks,
# and the right thing happens.
@@ -423,7 +415,7 @@ class SegWitTest(BitcoinTestFramework):
# This gives us a witness commitment.
assert(len(block.vtx[0].wit.vtxinwit) == 1)
assert(len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1)
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Now try to retrieve it...
rpc_block = self.nodes[0].getblock(block.hash, False)
non_wit_block = self.test_node.request_block(block.sha256, 2)
@@ -471,7 +463,7 @@ class SegWitTest(BitcoinTestFramework):
blocks are permitted to contain witnesses)."""
# node2 doesn't need to be connected for this test.
- # (If it's connected, node0 may propogate an invalid block to it over
+ # (If it's connected, node0 may propagate an invalid block to it over
# compact blocks and the nodes would have inconsistent tips.)
disconnect_nodes(self.nodes[0], 2)
@@ -497,7 +489,7 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx])
# Verify that segwit isn't activated. A block serialized with witness
# should be rejected prior to activation.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason=b'unexpected-witness')
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason='unexpected-witness')
# Now send the block without witness. It should be accepted
test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=False)
@@ -523,7 +515,7 @@ class SegWitTest(BitcoinTestFramework):
# When the block is serialized with a witness, the block will be rejected because witness
# data isn't allowed in blocks that don't commit to witness data.
- test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason=b'unexpected-witness')
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason='unexpected-witness')
# When the block is serialized without witness, validation fails because the transaction is
# invalid (transactions are always validated with SCRIPT_VERIFY_WITNESS so a segwit v0 transaction
@@ -640,11 +632,11 @@ class SegWitTest(BitcoinTestFramework):
# its from)
assert_equal(len(self.nodes[0].getrawmempool()), 0)
assert_equal(len(self.nodes[1].getrawmempool()), 0)
- test_transaction_acceptance(self.nodes[0].rpc, self.old_node, tx, with_witness=True, accepted=False)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.old_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=False)
# But eliminating the witness should fix it
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
# Cleanup: mine the first transaction and update utxo
self.nodes[0].generate(1)
@@ -674,7 +666,7 @@ class SegWitTest(BitcoinTestFramework):
p2sh_tx.rehash()
# Mine it on test_node to create the confirmed output.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_tx, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_tx, with_witness=True, accepted=True)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
@@ -689,7 +681,7 @@ class SegWitTest(BitcoinTestFramework):
# This is always accepted, since the mempool policy is to consider segwit as always active
# and thus allow segwit outputs
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx, with_witness=True, accepted=True)
# Now create something that looks like a P2PKH output. This won't be spendable.
script_pubkey = CScript([OP_0, hash160(witness_hash)])
@@ -701,7 +693,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx2.rehash()
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=True)
# Now update self.utxo for later tests.
tx3 = CTransaction()
@@ -723,7 +715,7 @@ class SegWitTest(BitcoinTestFramework):
tx3.vout = [tx3_out]
tx3.rehash()
assert_equal(self.nodes[0].testmempoolaccept([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
@@ -760,10 +752,10 @@ class SegWitTest(BitcoinTestFramework):
tx.rehash()
# Verify mempool acceptance and block validity
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True, with_witness=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=True)
sync_blocks(self.nodes)
# Now test attempts to spend the output.
@@ -777,12 +769,16 @@ class SegWitTest(BitcoinTestFramework):
# will require a witness to spend a witness program regardless of
# segwit activation. Note that older bitcoind's that are not
# segwit-aware would also reject this for failing CLEANSTACK.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
+ with self.nodes[0].assert_debug_log(
+ expected_msgs=(spend_tx.hash, 'was not accepted: non-mandatory-script-verify-flag (Witness program was passed an empty witness)')):
+ test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False)
- # Try to put the witness script in the script_sig, should also fail.
- spend_tx.vin[0].script_sig = CScript([p2wsh_pubkey, b'a'])
+ # Try to put the witness script in the scriptSig, should also fail.
+ spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a'])
spend_tx.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=False, accepted=False)
+ with self.nodes[0].assert_debug_log(
+ expected_msgs=('Not relaying invalid transaction {}'.format(spend_tx.hash), 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')):
+ test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False)
# Now put the witness script in the witness, should succeed after
# segwit activates.
@@ -792,7 +788,7 @@ class SegWitTest(BitcoinTestFramework):
spend_tx.wit.vtxinwit[0].scriptWitness.stack = [b'a', witness_program]
# Verify mempool acceptance
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, spend_tx, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=True, accepted=True)
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [spend_tx])
@@ -800,7 +796,7 @@ class SegWitTest(BitcoinTestFramework):
# This no longer works before activation, because SCRIPT_VERIFY_WITNESS
# is always set.
# TODO: rewrite this test to make clear that it only works after activation.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Update self.utxo
self.utxo.pop(0)
@@ -821,7 +817,7 @@ class SegWitTest(BitcoinTestFramework):
assert(msg_witness_block(block).serialize() != msg_block(block).serialize())
# This empty block should be valid.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Try to tweak the nonce
block_2 = self.build_next_block()
@@ -832,7 +828,7 @@ class SegWitTest(BitcoinTestFramework):
assert(block_2.vtx[0].vout[-1] != block.vtx[0].vout[-1])
# This should also be valid.
- test_witness_block(self.nodes[0].rpc, self.test_node, block_2, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_2, accepted=True)
# Now test commitments with actual transactions
tx = CTransaction()
@@ -864,7 +860,7 @@ class SegWitTest(BitcoinTestFramework):
block_3.rehash()
block_3.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
# Add a different commitment with different nonce, but in the
# right location, and with some funds burned(!).
@@ -878,7 +874,7 @@ class SegWitTest(BitcoinTestFramework):
block_3.rehash()
assert(len(block_3.vtx[0].vout) == 4) # 3 OP_returns
block_3.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=True)
# Finally test that a block with no witness transactions can
# omit the commitment.
@@ -890,7 +886,7 @@ class SegWitTest(BitcoinTestFramework):
block_4.vtx.append(tx3)
block_4.hashMerkleRoot = block_4.calc_merkle_root()
block_4.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block_4, with_witness=False, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_4, with_witness=False, accepted=True)
# Update available utxo's for use in later test.
self.utxo.pop(0)
@@ -930,11 +926,11 @@ class SegWitTest(BitcoinTestFramework):
# Change the nonce -- should not cause the block to be permanently
# failed
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(1)]
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Changing the witness reserved value doesn't change the block hash
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
@subtest
def test_witness_block_size(self):
@@ -998,7 +994,7 @@ class SegWitTest(BitcoinTestFramework):
# limit
assert(len(block.serialize(True)) > 2 * 1024 * 1024)
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now resize the second transaction to make the block fit.
cur_length = len(block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0])
@@ -1008,7 +1004,7 @@ class SegWitTest(BitcoinTestFramework):
block.solve()
assert(get_virtual_size(block) == MAX_BLOCK_BASE_SIZE)
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Update available utxo's
self.utxo.pop(0)
@@ -1071,7 +1067,7 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx])
# Extra witness data should not be allowed.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Try extra signature data. Ok if we're not spending a witness output.
block.vtx[1].wit.vtxinwit = []
@@ -1080,7 +1076,7 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Now try extra witness/signature data on an input that DOES require a
# witness
@@ -1096,7 +1092,7 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx2])
# This has extra witness data, so it should fail.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now get rid of the extra witness, but add extra scriptSig data
tx2.vin[0].scriptSig = CScript([OP_TRUE])
@@ -1108,7 +1104,7 @@ class SegWitTest(BitcoinTestFramework):
block.solve()
# This has extra signature data for a witness input, so it should fail.
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now get rid of the extra scriptsig on the witness input, and verify
# success (even with extra scriptsig data in the non-witness input)
@@ -1117,7 +1113,7 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Update utxo for later tests
self.utxo.pop(0)
@@ -1147,14 +1143,14 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now reduce the length of the stack element
tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (MAX_SCRIPT_ELEMENT_SIZE)
add_witness_commitment(block)
block.solve()
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Update the utxo for later tests
self.utxo.pop()
@@ -1188,7 +1184,7 @@ class SegWitTest(BitcoinTestFramework):
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Try again with one less byte in the witness program
witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 62 + [OP_TRUE])
@@ -1203,7 +1199,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
@@ -1227,7 +1223,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Try various ways to spend tx that should all break.
# This "broken" transaction serializer will not normalize
@@ -1262,7 +1258,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now try using a too short vtxinwit
tx2.wit.vtxinwit.pop()
@@ -1270,7 +1266,7 @@ class SegWitTest(BitcoinTestFramework):
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now make one of the intermediate witnesses be incorrect
tx2.wit.vtxinwit.append(CTxInWitness())
@@ -1279,13 +1275,13 @@ class SegWitTest(BitcoinTestFramework):
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Fix the broken witness and the block should be accepted.
tx2.wit.vtxinwit[5].scriptWitness.stack = [b'a', witness_program]
block.vtx = [block.vtx[0]]
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
self.utxo.pop()
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
@@ -1314,11 +1310,11 @@ class SegWitTest(BitcoinTestFramework):
# Verify that unnecessary witnesses are rejected.
self.test_node.announce_tx_and_wait_for_getdata(tx)
assert_equal(len(self.nodes[0].getrawmempool()), 0)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=False)
# Verify that removing the witness succeeds.
self.test_node.announce_tx_and_wait_for_getdata(tx)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
# Now try to add extra witness data to a valid witness tx.
witness_program = CScript([OP_TRUE])
@@ -1343,24 +1339,24 @@ class SegWitTest(BitcoinTestFramework):
# Node will not be blinded to the transaction
self.std_node.announce_tx_and_wait_for_getdata(tx3)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, True, False, b'tx-size')
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False, 'tx-size')
self.std_node.announce_tx_and_wait_for_getdata(tx3)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx3, True, False, b'tx-size')
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False, 'tx-size')
# Remove witness stuffing, instead add extra witness push on stack
tx3.vout[0] = CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))
tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program]
tx3.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, with_witness=True, accepted=True)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False)
# Get rid of the extra witness, and verify acceptance.
tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
# Also check that old_node gets a tx announcement, even though this is
# a witness transaction.
self.old_node.wait_for_inv([CInv(1, tx2.sha256)]) # wait until tx2 was inv'ed
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
self.old_node.wait_for_inv([CInv(1, tx3.sha256)])
# Test that getrawtransaction returns correct witness information
@@ -1400,7 +1396,7 @@ class SegWitTest(BitcoinTestFramework):
tx.rehash()
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
self.utxo.pop(0)
for i in range(NUM_SEGWIT_VERSIONS):
self.utxo.append(UTXO(tx.sha256, i, split_value))
@@ -1417,8 +1413,8 @@ class SegWitTest(BitcoinTestFramework):
tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b"")]
tx.vout = [CTxOut(self.utxo[0].nValue - 1000, script_pubkey)]
tx.rehash()
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx, with_witness=True, accepted=False)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=True)
self.utxo.pop(0)
temp_utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
@@ -1437,8 +1433,8 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
# Gets accepted to test_node, because standardness of outputs isn't
# checked with fRequireStandard
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, with_witness=True, accepted=True)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=False)
temp_utxo.pop() # last entry in temp_utxo was the output we just spent
temp_utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
@@ -1454,15 +1450,12 @@ class SegWitTest(BitcoinTestFramework):
tx3.rehash()
# Spending a higher version witness output is not allowed by policy,
# even with fRequireStandard=false.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, with_witness=True, accepted=False)
- self.test_node.sync_with_ping()
- with mininode_lock:
- assert(b"reserved for soft-fork upgrades" in self.test_node.last_message["reject"].reason)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=False, reason="reserved for soft-fork upgrades")
# Building a block with the transaction must be valid, however.
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2, tx3])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
sync_blocks(self.nodes)
# Add utxo to our list
@@ -1480,7 +1473,7 @@ class SegWitTest(BitcoinTestFramework):
# This next line will rehash the coinbase and update the merkle
# root, and solve.
self.update_witness_block_with_transactions(block, [])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
spend_tx = CTransaction()
spend_tx.vin = [CTxIn(COutPoint(block.vtx[0].sha256, 0), b"")]
@@ -1494,13 +1487,13 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block2, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block2, accepted=False)
# Advancing one more block should allow the spend.
self.nodes[0].generate(1)
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block2, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block2, accepted=True)
sync_blocks(self.nodes)
@subtest
@@ -1532,7 +1525,7 @@ class SegWitTest(BitcoinTestFramework):
# Confirm it in a block.
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Now try to spend it. Send it to a P2WSH output, which we'll
# use in the next test.
@@ -1551,11 +1544,11 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
# Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
# But passes consensus.
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Test 2: P2WSH
# Try to spend the P2WSH output created in last test.
@@ -1571,11 +1564,11 @@ class SegWitTest(BitcoinTestFramework):
sign_p2pk_witness_input(witness_program, tx3, 0, SIGHASH_ALL, tx2.vout[0].nValue, key)
# Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
# But passes consensus.
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx3])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Test 3: P2SH(P2WSH)
# Try to spend the P2SH output created in the last test.
@@ -1588,10 +1581,10 @@ class SegWitTest(BitcoinTestFramework):
sign_p2pk_witness_input(witness_program, tx4, 0, SIGHASH_ALL, tx3.vout[0].nValue, key)
# Should fail policy test.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx4, True, False, b'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx4, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)')
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx4])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Test 4: Uncompressed pubkeys should still be valid in non-segwit
# transactions.
@@ -1603,10 +1596,10 @@ class SegWitTest(BitcoinTestFramework):
tx5.vin[0].scriptSig = CScript([signature, pubkey])
tx5.rehash()
# Should pass policy and consensus.
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx5, True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx5, True, True)
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx5])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
@subtest
@@ -1626,11 +1619,11 @@ class SegWitTest(BitcoinTestFramework):
tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=True, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=True)
# Mine this transaction in preparation for following tests.
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
sync_blocks(self.nodes)
self.utxo.pop(0)
@@ -1647,19 +1640,19 @@ class SegWitTest(BitcoinTestFramework):
# Too-large input value
sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue + 1, key)
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Too-small input value
sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue - 1, key)
block.vtx.pop() # remove last tx
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Now try correct value
sign_p2pk_witness_input(witness_program, tx, 0, hashtype, prev_utxo.nValue, key)
block.vtx.pop()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
prev_utxo = UTXO(tx.sha256, 0, tx.vout[0].nValue)
@@ -1683,7 +1676,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
block = self.build_next_block()
used_sighash_single_out_of_bounds = False
@@ -1725,7 +1718,7 @@ class SegWitTest(BitcoinTestFramework):
# Test the block periodically, if we're close to maxblocksize
if (get_virtual_size(block) > MAX_BLOCK_BASE_SIZE - 1000):
self.update_witness_block_with_transactions(block, [])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
block = self.build_next_block()
if (not used_sighash_single_out_of_bounds):
@@ -1733,7 +1726,7 @@ class SegWitTest(BitcoinTestFramework):
# Test the transactions we've added to the block
if (len(block.vtx) > 1):
self.update_witness_block_with_transactions(block, [])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Now test witness version 0 P2PKH transactions
pubkeyhash = hash160(pubkey)
@@ -1755,7 +1748,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.vin[0].scriptSig = CScript([signature, pubkey])
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx, tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
# Move the signature to the witness.
block.vtx.pop()
@@ -1765,7 +1758,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
self.update_witness_block_with_transactions(block, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
temp_utxos.pop(0)
@@ -1786,7 +1779,7 @@ class SegWitTest(BitcoinTestFramework):
index += 1
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
for i in range(len(tx.vout)):
self.utxo.append(UTXO(tx.sha256, i, tx.vout[i].nValue))
@@ -1808,7 +1801,7 @@ class SegWitTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
tx.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, False, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, False, True)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
@@ -1825,18 +1818,18 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
# This will be rejected due to a policy check:
# No witness is allowed, since it is not a witness program but a p2sh program
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, True, False, b'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, True, False, 'bad-witness-nonstandard')
# If we send without witness, it should be accepted.
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, tx2, False, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, False, True)
# Now create a new anyone-can-spend utxo for the next test.
tx3 = CTransaction()
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))
tx3.vout.append(CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
tx3.rehash()
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx2, False, True)
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx3, False, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx2, False, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx3, False, True)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
@@ -1872,7 +1865,7 @@ class SegWitTest(BitcoinTestFramework):
tx.vout.append(CTxOut(outputvalue, CScript([OP_HASH160, p2sh, OP_EQUAL])))
tx.rehash()
txid = tx.sha256
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, tx, with_witness=False, accepted=True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
@@ -1897,45 +1890,45 @@ class SegWitTest(BitcoinTestFramework):
# Testing native P2WSH
# Witness stack size, excluding witnessScript, over 100 is non-standard
p2wsh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[0], True, False, b'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[0], True, False, 'bad-witness-nonstandard')
# Non-standard nodes should accept
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[0], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[0], True, True)
# Stack element size over 80 bytes is non-standard
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[1], True, False, b'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, False, 'bad-witness-nonstandard')
# Non-standard nodes should accept
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[1], True, True)
# Standard nodes should accept if element size is not over 80 bytes
p2wsh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[1], True, True)
# witnessScript size at 3600 bytes is standard
p2wsh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[2], True, True)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[2], True, True)
# witnessScript size at 3601 bytes is non-standard
p2wsh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2wsh_txs[3], True, False, b'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2wsh_txs[3], True, False, 'bad-witness-nonstandard')
# Non-standard nodes should accept
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2wsh_txs[3], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2wsh_txs[3], True, True)
# Repeating the same tests with P2SH-P2WSH
p2sh_txs[0].wit.vtxinwit[0].scriptWitness.stack = [pad] * 101 + [scripts[0]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[0], True, False, b'bad-witness-nonstandard')
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[0], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[0], True, False, 'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[0], True, True)
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 81] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[1], True, False, b'bad-witness-nonstandard')
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, False, 'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[1], True, True)
p2sh_txs[1].wit.vtxinwit[0].scriptWitness.stack = [pad * 80] * 100 + [scripts[1]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[1], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[1], True, True)
p2sh_txs[2].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, scripts[2]]
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[2], True, True)
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[2], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[2], True, True)
p2sh_txs[3].wit.vtxinwit[0].scriptWitness.stack = [pad, pad, pad, scripts[3]]
- test_transaction_acceptance(self.nodes[1].rpc, self.std_node, p2sh_txs[3], True, False, b'bad-witness-nonstandard')
- test_transaction_acceptance(self.nodes[0].rpc, self.test_node, p2sh_txs[3], True, True)
+ test_transaction_acceptance(self.nodes[1], self.std_node, p2sh_txs[3], True, False, 'bad-witness-nonstandard')
+ test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_txs[3], True, True)
self.nodes[0].generate(1) # Mine and clean up the mempool of non-standard node
# Valid but non-standard transactions in a block should be accepted by standard node
@@ -2011,7 +2004,7 @@ class SegWitTest(BitcoinTestFramework):
block_1 = self.build_next_block()
self.update_witness_block_with_transactions(block_1, [tx])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_1, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_1, accepted=True)
tx2 = CTransaction()
# If we try to spend the first n-1 outputs from tx, that should be
@@ -2028,7 +2021,7 @@ class SegWitTest(BitcoinTestFramework):
block_2 = self.build_next_block()
self.update_witness_block_with_transactions(block_2, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_2, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block_2, accepted=False)
# Try dropping the last input in tx2, and add an output that has
# too many sigops (contributing to legacy sigop count).
@@ -2041,14 +2034,14 @@ class SegWitTest(BitcoinTestFramework):
tx2.rehash()
block_3 = self.build_next_block()
self.update_witness_block_with_transactions(block_3, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_3, accepted=False)
+ test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
# If we drop the last checksig in this output, the tx should succeed.
block_4 = self.build_next_block()
tx2.vout[-1].scriptPubKey = CScript([OP_CHECKSIG] * (checksig_count - 1))
tx2.rehash()
self.update_witness_block_with_transactions(block_4, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_4, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_4, accepted=True)
# Reset the tip back down for the next test
sync_blocks(self.nodes)
@@ -2064,7 +2057,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.wit.vtxinwit[-1].scriptWitness.stack = [witness_program_justright]
tx2.rehash()
self.update_witness_block_with_transactions(block_5, [tx2])
- test_witness_block(self.nodes[0].rpc, self.test_node, block_5, accepted=True)
+ test_witness_block(self.nodes[0], self.test_node, block_5, accepted=True)
# TODO: test p2sh sigop counting
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index 9cc496d510..c7ae57de86 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -213,7 +213,7 @@ class SendHeadersTest(BitcoinTestFramework):
# Clear out block announcements from each p2p listener
[x.clear_block_announcements() for x in self.nodes[0].p2ps]
- self.nodes[0].generate(count)
+ self.nodes[0].generatetoaddress(count, self.nodes[0].get_deterministic_priv_key().address)
return int(self.nodes[0].getbestblockhash(), 16)
def mine_reorg(self, length):
@@ -223,7 +223,8 @@ class SendHeadersTest(BitcoinTestFramework):
to-be-reorged-out blocks are mined, so that we don't break later tests.
return the list of block hashes newly mined."""
- self.nodes[0].generate(length) # make sure all invalidated blocks are node0's
+ # make sure all invalidated blocks are node0's
+ self.nodes[0].generatetoaddress(length, self.nodes[0].get_deterministic_priv_key().address)
sync_blocks(self.nodes, wait=0.1)
for x in self.nodes[0].p2ps:
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
@@ -232,7 +233,7 @@ class SendHeadersTest(BitcoinTestFramework):
tip_height = self.nodes[1].getblockcount()
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
self.nodes[1].invalidateblock(hash_to_invalidate)
- all_hashes = self.nodes[1].generate(length + 1) # Must be longer than the orig chain
+ all_hashes = self.nodes[1].generatetoaddress(length + 1, self.nodes[1].get_deterministic_priv_key().address) # Must be longer than the orig chain
sync_blocks(self.nodes, wait=0.1)
return [int(x, 16) for x in all_hashes]
@@ -251,7 +252,7 @@ class SendHeadersTest(BitcoinTestFramework):
self.test_nonnull_locators(test_node, inv_node)
def test_null_locators(self, test_node, inv_node):
- tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0])
+ tip = self.nodes[0].getblockheader(self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0])
tip_hash = int(tip["hash"], 16)
inv_node.check_last_inv_announcement(inv=[tip_hash])
@@ -401,7 +402,7 @@ class SendHeadersTest(BitcoinTestFramework):
block_time += 9
- fork_point = self.nodes[0].getblock("%02x" % new_block_hashes[0])["previousblockhash"]
+ fork_point = self.nodes[0].getblock("%064x" % new_block_hashes[0])["previousblockhash"]
fork_point = int(fork_point, 16)
# Use getblocks/getdata
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index 2e86954aba..11299cbc00 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -82,8 +82,8 @@ class AcceptBlockTest(BitcoinTestFramework):
min_work_node = self.nodes[1].add_p2p_connection(P2PInterface())
# 1. Have nodes mine a block (leave IBD)
- [ n.generate(1) for n in self.nodes ]
- tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ]
+ [n.generatetoaddress(1, n.get_deterministic_priv_key().address) for n in self.nodes]
+ tips = [int("0x" + n.getbestblockhash(), 0) for n in self.nodes]
# 2. Send one block that builds on each tip.
# This should be accepted by node0
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index d681cdc8ab..31e60f1cea 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -47,9 +47,10 @@ from test_framework.mininode import (
class BlockchainTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-stopatheight=207', '-prune=1']]
def run_test(self):
+ self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete
+
self._test_getblockchaininfo()
self._test_getchaintxstats()
self._test_gettxoutsetinfo()
@@ -124,13 +125,15 @@ class BlockchainTest(BitcoinTestFramework):
# Test `getchaintxstats` invalid `blockhash`
assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getchaintxstats, blockhash=0)
- assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0')
+ assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 1, for '0')", self.nodes[0].getchaintxstats, blockhash='0')
+ assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getchaintxstats, blockhash='ZZZ0000000000000000000000000000000000000000000000000000000000000')
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0000000000000000000000000000000000000000000000000000000000000000')
blockhash = self.nodes[0].getblockhash(200)
self.nodes[0].invalidateblock(blockhash)
assert_raises_rpc_error(-8, "Block is not in main chain", self.nodes[0].getchaintxstats, blockhash=blockhash)
self.nodes[0].reconsiderblock(blockhash)
- chaintxstats = self.nodes[0].getchaintxstats(1)
+ chaintxstats = self.nodes[0].getchaintxstats(nblocks=1)
# 200 txs plus genesis tx
assert_equal(chaintxstats['txcount'], 201)
# tx rate should be 1 per 10 minutes, or 1/600
@@ -169,7 +172,7 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res['transactions'], 200)
assert_equal(res['height'], 200)
assert_equal(res['txouts'], 200)
- assert_equal(res['bogosize'], 17000),
+ assert_equal(res['bogosize'], 15000),
assert_equal(res['bestblock'], node.getblockhash(200))
size = res['disk_size']
assert size > 6400
@@ -202,11 +205,13 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getblockheader(self):
node = self.nodes[0]
- assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "nonsense")
+ assert_raises_rpc_error(-8, "hash must be of length 64 (not 8, for 'nonsense')", node.getblockheader, "nonsense")
+ assert_raises_rpc_error(-8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", node.getblockheader, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
+ assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
besthash = node.getbestblockhash()
secondbesthash = node.getblockhash(199)
- header = node.getblockheader(besthash)
+ header = node.getblockheader(blockhash=besthash)
assert_equal(header['hash'], besthash)
assert_equal(header['height'], 200)
@@ -238,12 +243,12 @@ class BlockchainTest(BitcoinTestFramework):
def _test_stopatheight(self):
assert_equal(self.nodes[0].getblockcount(), 200)
- self.nodes[0].generate(6)
+ self.nodes[0].generatetoaddress(6, self.nodes[0].get_deterministic_priv_key().address)
assert_equal(self.nodes[0].getblockcount(), 206)
self.log.debug('Node should not stop at this height')
assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))
try:
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
except (ConnectionError, http.client.BadStatusLine):
pass # The node already shut down before response
self.log.debug('Node should stop at this height...')
@@ -282,7 +287,7 @@ class BlockchainTest(BitcoinTestFramework):
def assert_waitforheight(height, timeout=2):
assert_equal(
- node.waitforblockheight(height, timeout)['height'],
+ node.waitforblockheight(height=height, timeout=timeout)['height'],
current_height)
assert_waitforheight(0)
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index f346e1ebfc..3cc35a7b9a 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -12,8 +12,11 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 3
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def get_keys(self):
- node0,node1,node2 = self.nodes
+ node0, node1, node2 = self.nodes
self.add = [node1.getnewaddress() for _ in range(self.nkeys)]
self.pub = [node1.getaddressinfo(a)["pubkey"] for a in self.add]
self.priv = [node1.dumpprivkey(a) for a in self.add]
diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py
index 32088fe3e1..588bfbe083 100755
--- a/test/functional/rpc_deprecated.py
+++ b/test/functional/rpc_deprecated.py
@@ -4,12 +4,17 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test deprecation of RPC calls."""
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_raises_rpc_error
class DeprecatedRpcTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
- self.extra_args = [[], ["-deprecatedrpc=validateaddress"]]
+ self.extra_args = [[], ["-deprecatedrpc=generate"]]
+
+ def skip_test_if_missing_module(self):
+ # The generate RPC method requires the wallet to be compiled
+ self.skip_if_no_wallet()
def run_test(self):
# This test should be used to verify correct behaviour of deprecated
@@ -19,12 +24,9 @@ class DeprecatedRpcTest(BitcoinTestFramework):
# assert_raises_rpc_error(-5, "Invalid public key", self.nodes[0].createmultisig, 1, [self.nodes[0].getnewaddress()])
# self.nodes[1].createmultisig(1, [self.nodes[1].getnewaddress()])
- self.log.info("Test validateaddress deprecation")
- SOME_ADDRESS = "mnvGjUy3NMj67yJ6gkK5o9e5RS33Z2Vqcu" # This is just some random address to pass as a parameter to validateaddress
- dep_validate_address = self.nodes[0].validateaddress(SOME_ADDRESS)
- assert "ismine" not in dep_validate_address
- not_dep_val = self.nodes[1].validateaddress(SOME_ADDRESS)
- assert "ismine" in not_dep_val
+ self.log.info("Test generate RPC")
+ assert_raises_rpc_error(-32, 'The wallet generate rpc method is deprecated', self.nodes[0].rpc.generate, 1)
+ self.nodes[1].generate(1)
if __name__ == '__main__':
DeprecatedRpcTest().main()
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index a806de43b4..0c61e9ab62 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -29,6 +29,9 @@ class RawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self, split=False):
self.setup_nodes()
@@ -475,10 +478,8 @@ class RawTransactionsTest(BitcoinTestFramework):
############################################################
# locked wallet test
- self.stop_node(0)
- self.nodes[1].node_encrypt_wallet("test")
- self.stop_node(2)
- self.stop_node(3)
+ self.nodes[1].encryptwallet("test")
+ self.stop_nodes()
self.start_nodes()
# This test is not meant to test fee estimation and we'd like
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index b24bed6adf..ca9e24367a 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -170,6 +170,8 @@ class GetblockstatsTest(BitcoinTestFramework):
self.nodes[0].getblockstats, hash_or_height=1, stats=['minfee' , 'aaa%s' % inv_sel_stat])
assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled',
+ self.nodes[1].getblockstats, hash_or_height=1)
+ assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled',
self.nodes[1].getblockstats, hash_or_height=self.start_height + self.max_stat_pos)
# Mainchain's genesis block shouldn't be found on regtest
diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py
index 07929ca0a1..c869c7262f 100755
--- a/test/functional/rpc_getchaintips.py
+++ b/test/functional/rpc_getchaintips.py
@@ -17,17 +17,17 @@ class GetChainTipsTest (BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
- def run_test (self):
- tips = self.nodes[0].getchaintips ()
- assert_equal (len (tips), 1)
- assert_equal (tips[0]['branchlen'], 0)
- assert_equal (tips[0]['height'], 200)
- assert_equal (tips[0]['status'], 'active')
+ def run_test(self):
+ tips = self.nodes[0].getchaintips()
+ assert_equal(len(tips), 1)
+ assert_equal(tips[0]['branchlen'], 0)
+ assert_equal(tips[0]['height'], 200)
+ assert_equal(tips[0]['status'], 'active')
# Split the network and build two chains of different lengths.
- self.split_network ()
- self.nodes[0].generate(10)
- self.nodes[2].generate(20)
+ self.split_network()
+ self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
+ self.nodes[2].generatetoaddress(20, self.nodes[2].get_deterministic_priv_key().address)
self.sync_all([self.nodes[:2], self.nodes[2:]])
tips = self.nodes[1].getchaintips ()
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
new file mode 100755
index 0000000000..78d6e78aed
--- /dev/null
+++ b/test/functional/rpc_help.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 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 help output."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error
+
+import os
+
+
+class HelpRpcTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def run_test(self):
+ self.test_categories()
+ self.dump_help()
+
+ def test_categories(self):
+ node = self.nodes[0]
+
+ # wrong argument count
+ assert_raises_rpc_error(-1, 'help', node.help, 'foo', 'bar')
+
+ # invalid argument
+ assert_raises_rpc_error(-1, 'JSON value is not a string as expected', node.help, 0)
+
+ # help of unknown command
+ assert_equal(node.help('foo'), 'help: unknown command: foo')
+
+ # command titles
+ titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]
+
+ components = ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util']
+
+ if self.is_wallet_compiled():
+ components.append('Wallet')
+
+ if self.is_zmq_compiled():
+ components.append('Zmq')
+
+ assert_equal(titles, components)
+
+ def dump_help(self):
+ dump_dir = os.path.join(self.options.tmpdir, 'rpc_help_dump')
+ os.mkdir(dump_dir)
+ calls = [line.split(' ', 1)[0] for line in self.nodes[0].help().splitlines() if line and not line.startswith('==')]
+ for call in calls:
+ with open(os.path.join(dump_dir, call), 'w', encoding='utf-8') as f:
+ # Make sure the node can generate the help at runtime without crashing
+ f.write(self.nodes[0].help(call))
+
+
+if __name__ == '__main__':
+ HelpRpcTest().main()
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index f40710ef74..d8ecdd573a 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -20,12 +20,12 @@ class InvalidateTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:")
self.log.info("Mine 4 blocks on Node 0")
- self.nodes[0].generate(4)
+ self.nodes[0].generatetoaddress(4, self.nodes[0].get_deterministic_priv_key().address)
assert(self.nodes[0].getblockcount() == 4)
besthash = self.nodes[0].getbestblockhash()
self.log.info("Mine competing 6 blocks on Node 1")
- self.nodes[1].generate(6)
+ self.nodes[1].generatetoaddress(6, self.nodes[1].get_deterministic_priv_key().address)
assert(self.nodes[1].getblockcount() == 6)
self.log.info("Connect nodes to force a reorg")
@@ -53,7 +53,7 @@ class InvalidateTest(BitcoinTestFramework):
self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3))
assert(self.nodes[2].getblockcount() == 2)
self.log.info("..and then mine a block")
- self.nodes[2].generate(1)
+ self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address)
self.log.info("Verify all nodes are at the right height")
time.sleep(5)
assert_equal(self.nodes[2].getblockcount(), 3)
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index a46518200c..0affddcf05 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -13,11 +13,14 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_greater_than_or_equal,
+ assert_greater_than,
assert_raises_rpc_error,
connect_nodes_bi,
p2p_port,
wait_until,
)
+from test_framework.mininode import P2PInterface
+from test_framework.messages import CAddress, msg_addr, NODE_NETWORK, NODE_WITNESS
class NetTest(BitcoinTestFramework):
def set_test_params(self):
@@ -31,6 +34,7 @@ class NetTest(BitcoinTestFramework):
self._test_getnetworkinginfo()
self._test_getaddednodeinfo()
self._test_getpeerinfo()
+ self._test_getnodeaddresses()
def _test_connection_count(self):
# connect_nodes_bi connects each node to the other
@@ -70,12 +74,12 @@ class NetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
- self.nodes[0].setnetworkactive(False)
+ self.nodes[0].setnetworkactive(state=False)
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)
# Wait a bit for all sockets to close
wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3)
- self.nodes[0].setnetworkactive(True)
+ self.nodes[0].setnetworkactive(state=True)
connect_nodes_bi(self.nodes, 0, 1)
assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
@@ -84,7 +88,7 @@ class NetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getaddednodeinfo(), [])
# add a node (node2) to node0
ip_port = "127.0.0.1:{}".format(p2p_port(2))
- self.nodes[0].addnode(ip_port, 'add')
+ self.nodes[0].addnode(node=ip_port, command='add')
# check that the node has indeed been added
added_nodes = self.nodes[0].getaddednodeinfo(ip_port)
assert_equal(len(added_nodes), 1)
@@ -101,5 +105,40 @@ class NetTest(BitcoinTestFramework):
assert_equal(peer_info[0][0]['minfeefilter'], Decimal("0.00000500"))
assert_equal(peer_info[1][0]['minfeefilter'], Decimal("0.00001000"))
+ def _test_getnodeaddresses(self):
+ self.nodes[0].add_p2p_connection(P2PInterface())
+
+ # send some addresses to the node via the p2p message addr
+ msg = msg_addr()
+ imported_addrs = []
+ for i in range(256):
+ a = "123.123.123.{}".format(i)
+ imported_addrs.append(a)
+ addr = CAddress()
+ addr.time = 100000000
+ addr.nServices = NODE_NETWORK | NODE_WITNESS
+ addr.ip = a
+ addr.port = 8333
+ msg.addrs.append(addr)
+ self.nodes[0].p2p.send_and_ping(msg)
+
+ # obtain addresses via rpc call and check they were ones sent in before
+ REQUEST_COUNT = 10
+ node_addresses = self.nodes[0].getnodeaddresses(REQUEST_COUNT)
+ assert_equal(len(node_addresses), REQUEST_COUNT)
+ for a in node_addresses:
+ assert_greater_than(a["time"], 1527811200) # 1st June 2018
+ assert_equal(a["services"], NODE_NETWORK | NODE_WITNESS)
+ assert a["address"] in imported_addrs
+ assert_equal(a["port"], 8333)
+
+ assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1)
+
+ # addrman's size cannot be known reliably after insertion, as hash collisions may occur
+ # so only test that requesting a large number of addresses returns less than that
+ LARGE_REQUEST_COUNT = 10000
+ node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT)
+ assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses))
+
if __name__ == '__main__':
NetTest().main()
diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py
index 1e20d1a046..72e6e6329f 100755
--- a/test/functional/rpc_preciousblock.py
+++ b/test/functional/rpc_preciousblock.py
@@ -43,18 +43,19 @@ class PreciousTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Ensure submitblock can in principle reorg to a competing chain")
- self.nodes[0].generate(1)
+ gen_address = lambda i: self.nodes[i].get_deterministic_priv_key().address # A non-wallet address to mine to
+ self.nodes[0].generatetoaddress(1, gen_address(0))
assert_equal(self.nodes[0].getblockcount(), 1)
- hashZ = self.nodes[1].generate(2)[-1]
+ hashZ = self.nodes[1].generatetoaddress(2, gen_address(1))[-1]
assert_equal(self.nodes[1].getblockcount(), 2)
node_sync_via_rpc(self.nodes[0:3])
assert_equal(self.nodes[0].getbestblockhash(), hashZ)
self.log.info("Mine blocks A-B-C on Node 0")
- hashC = self.nodes[0].generate(3)[-1]
+ hashC = self.nodes[0].generatetoaddress(3, gen_address(0))[-1]
assert_equal(self.nodes[0].getblockcount(), 5)
self.log.info("Mine competing blocks E-F-G on Node 1")
- hashG = self.nodes[1].generate(3)[-1]
+ hashG = self.nodes[1].generatetoaddress(3, gen_address(1))[-1]
assert_equal(self.nodes[1].getblockcount(), 5)
assert(hashC != hashG)
self.log.info("Connect nodes and check no reorg occurs")
@@ -83,7 +84,7 @@ class PreciousTest(BitcoinTestFramework):
self.nodes[1].preciousblock(hashC)
assert_equal(self.nodes[1].getbestblockhash(), hashC)
self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
- self.nodes[0].generate(1)
+ self.nodes[0].generatetoaddress(1, gen_address(0))
assert_equal(self.nodes[0].getblockcount(), 6)
sync_blocks(self.nodes[0:2])
hashH = self.nodes[0].getbestblockhash()
@@ -92,7 +93,7 @@ class PreciousTest(BitcoinTestFramework):
self.nodes[1].preciousblock(hashC)
assert_equal(self.nodes[1].getbestblockhash(), hashH)
self.log.info("Mine competing blocks I-J-K-L on Node 2")
- self.nodes[2].generate(4)
+ self.nodes[2].generatetoaddress(4, gen_address(2))
assert_equal(self.nodes[2].getblockcount(), 6)
hashL = self.nodes[2].getbestblockhash()
self.log.info("Connect nodes and check no reorg occurs")
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index f847a01e59..272ebe65cb 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -6,7 +6,7 @@
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, find_output
+from test_framework.util import assert_equal, assert_raises_rpc_error, find_output, disconnect_nodes, connect_nodes_bi, sync_blocks
import json
import os
@@ -20,6 +20,48 @@ class PSBTTest(BitcoinTestFramework):
self.setup_clean_chain = False
self.num_nodes = 3
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def test_utxo_conversion(self):
+ mining_node = self.nodes[2]
+ offline_node = self.nodes[0]
+ online_node = self.nodes[1]
+
+ # Disconnect offline node from others
+ disconnect_nodes(offline_node, 1)
+ disconnect_nodes(online_node, 0)
+ disconnect_nodes(offline_node, 2)
+ disconnect_nodes(mining_node, 0)
+
+ # Mine a transaction that credits the offline address
+ offline_addr = offline_node.getnewaddress(address_type="p2sh-segwit")
+ online_addr = online_node.getnewaddress(address_type="p2sh-segwit")
+ online_node.importaddress(offline_addr, "", False)
+ mining_node.sendtoaddress(address=offline_addr, amount=1.0)
+ mining_node.generate(nblocks=1)
+ sync_blocks([mining_node, online_node])
+
+ # Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)
+ utxos = online_node.listunspent(addresses=[offline_addr])
+ raw = online_node.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
+ psbt = online_node.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
+ assert("non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0])
+
+ # Have the offline node sign the PSBT (which will update the UTXO to segwit)
+ signed_psbt = offline_node.walletprocesspsbt(psbt)["psbt"]
+ assert("witness_utxo" in mining_node.decodepsbt(signed_psbt)["inputs"][0])
+
+ # Make sure we can mine the resulting transaction
+ txid = mining_node.sendrawtransaction(mining_node.finalizepsbt(signed_psbt)["hex"])
+ mining_node.generate(1)
+ sync_blocks([mining_node, online_node])
+ assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)
+
+ # Reconnect
+ connect_nodes_bi(self.nodes, 0, 1)
+ connect_nodes_bi(self.nodes, 0, 2)
+
def run_test(self):
# Create and fund a raw tx for sending 10 BTC
psbtx1 = self.nodes[0].walletcreatefundedpsbt([], {self.nodes[2].getnewaddress():10})['psbt']
@@ -104,8 +146,11 @@ class PSBTTest(BitcoinTestFramework):
# Make sure that a psbt with signatures cannot be converted
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])
assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].converttopsbt, signedtx['hex'])
+ assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].converttopsbt, signedtx['hex'], False)
+ # Unless we allow it to convert and strip signatures
+ self.nodes[0].converttopsbt(signedtx['hex'], True)
- # Explicilty allow converting non-empty txs
+ # Explicitly allow converting non-empty txs
new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
self.nodes[0].decodepsbt(new_psbt)
@@ -143,17 +188,19 @@ class PSBTTest(BitcoinTestFramework):
# replaceable arg
block_height = self.nodes[0].getblockcount()
unspent = self.nodes[0].listunspent()[0]
- psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":True})
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":True}, False)
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" not in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], block_height+2)
# Same construction with only locktime set
- psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height)
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height, {}, True)
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 tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE
+ assert "bip32_derivs" in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], block_height)
# Same construction without optional arguments
@@ -163,6 +210,17 @@ class PSBTTest(BitcoinTestFramework):
assert tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE
assert_equal(decoded_psbt["tx"]["locktime"], 0)
+ # Make sure change address wallet does not have P2SH innerscript access to results in success
+ # when attempting BnB coin selection
+ self.nodes[0].walletcreatefundedpsbt([], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"changeAddress":self.nodes[1].getnewaddress()}, False)
+
+ # Regression test for 14473 (mishandling of already-signed witness transaction):
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}])
+ complete_psbt = self.nodes[0].walletprocesspsbt(psbtx_info["psbt"])
+ double_processed_psbt = self.nodes[0].walletprocesspsbt(complete_psbt["psbt"])
+ assert_equal(complete_psbt, double_processed_psbt)
+ # We don't care about the decode result, but decoding must succeed.
+ self.nodes[0].decodepsbt(double_processed_psbt["psbt"])
# BIP 174 Test Vectors
@@ -219,6 +277,16 @@ class PSBTTest(BitcoinTestFramework):
extracted = self.nodes[2].finalizepsbt(extractor['extract'], True)['hex']
assert_equal(extracted, extractor['result'])
+ # Unload extra wallets
+ for i, signer in enumerate(signers):
+ self.nodes[2].unloadwallet("wallet{}".format(i))
+
+ self.test_utxo_conversion()
+
+ # Test that psbts with p2pkh outputs are created properly
+ p2pkh = self.nodes[0].getnewaddress(address_type='legacy')
+ psbt = self.nodes[1].walletcreatefundedpsbt([], [{p2pkh : 1}], 0, {"includeWatching" : True}, True)
+ self.nodes[0].decodepsbt(psbt['psbt'])
if __name__ == '__main__':
PSBTTest().main()
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 1e3ada26f8..8ed490f552 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -44,6 +44,9 @@ class RawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 3
self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"], ["-addresstype=legacy"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self, split=False):
super().setup_network()
connect_nodes_bi(self.nodes, 0, 2)
@@ -77,8 +80,9 @@ class RawTransactionsTest(BitcoinTestFramework):
txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000'
assert_raises_rpc_error(-3, "Expected type array", self.nodes[0].createrawtransaction, 'foo', {})
assert_raises_rpc_error(-1, "JSON value is not an object as expected", self.nodes[0].createrawtransaction, ['foo'], {})
- assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{}], {})
- assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
+ assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].createrawtransaction, [{}], {})
+ assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
+ assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", self.nodes[0].createrawtransaction, [{'txid': 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'}], {})
assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid}], {})
assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 'foo'}], {})
assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': -1}], {})
@@ -221,9 +225,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# We should not get the tx if we provide an unrelated block
assert_raises_rpc_error(-5, "No such transaction found", self.nodes[0].getrawtransaction, tx, True, block2)
# An invalid block hash should raise the correct errors
- assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, True)
- assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, "foobar")
- assert_raises_rpc_error(-8, "parameter 3 must be of length 64", self.nodes[0].getrawtransaction, tx, True, "abcd1234")
+ assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getrawtransaction, tx, True, True)
+ assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 6, for 'foobar')", self.nodes[0].getrawtransaction, tx, True, "foobar")
+ assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')", self.nodes[0].getrawtransaction, tx, True, "abcd1234")
+ assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getrawtransaction, tx, True, "ZZZ0000000000000000000000000000000000000000000000000000000000000")
assert_raises_rpc_error(-5, "Block hash not found", self.nodes[0].getrawtransaction, tx, True, "0000000000000000000000000000000000000000000000000000000000000000")
# Undo the blocks and check in_active_chain
self.nodes[0].invalidateblock(block1)
@@ -358,7 +363,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# decoderawtransaction tests
# witness transaction
- encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000000000000"
+ encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
decrawtx = self.nodes[0].decoderawtransaction(encrawtx, True) # decode as witness transaction
assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # force decode as non-witness transaction
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
index ceb38e969a..11b4db6ec5 100755
--- a/test/functional/rpc_scantxoutset.py
+++ b/test/functional/rpc_scantxoutset.py
@@ -10,10 +10,17 @@ from decimal import Decimal
import shutil
import os
+def descriptors(out):
+ return sorted(u['desc'] for u in out['unspents'])
+
class ScantxoutsetTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.log.info("Mining blocks...")
self.nodes[0].generate(110)
@@ -61,6 +68,8 @@ class ScantxoutsetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "combo(" + pubk3 + ")"])['total_amount'], Decimal("0.007"))
self.log.info("Test extended key derivation.")
+ # Run various scans, and verify that the sum of the amounts of the matches corresponds to the expected subset.
+ # Note that all amounts in the UTXO set are powers of 2 multiplied by 0.001 BTC, so each amounts uniquely identifies a subset.
assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0h/0h)"])['total_amount'], Decimal("0.008"))
assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0'/0'/1h)"])['total_amount'], Decimal("0.016"))
assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/1500')"])['total_amount'], Decimal("0.032"))
@@ -78,7 +87,7 @@ class ScantxoutsetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1)"])['total_amount'], Decimal("8.192"))
assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/1500)"])['total_amount'], Decimal("16.384"))
assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)"])['total_amount'], Decimal("4.096"))
- assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"])['total_amount'], Decimal("8.192"))
+ assert_equal(self.nodes[0].scantxoutset("start", [ "combo([abcdef88/1/2'/3/4h]tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"])['total_amount'], Decimal("8.192"))
assert_equal(self.nodes[0].scantxoutset("start", [ "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1500)"])['total_amount'], Decimal("16.384"))
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1499}])['total_amount'], Decimal("1.536"))
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*')", "range": 1500}])['total_amount'], Decimal("3.584"))
@@ -87,5 +96,10 @@ class ScantxoutsetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1499}])['total_amount'], Decimal("12.288"))
assert_equal(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])['total_amount'], Decimal("28.672"))
+ # Test the reported descriptors for a few matches
+ assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])), ["pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)", "pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)"])
+ assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])), ["pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)"])
+ assert_equal(descriptors(self.nodes[0].scantxoutset("start", [ {"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])), ['pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)', 'pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)', 'pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)'])
+
if __name__ == '__main__':
ScantxoutsetTest().main()
diff --git a/test/functional/rpc_signmessage.py b/test/functional/rpc_signmessage.py
index 449c4075bd..ad0e29b451 100755
--- a/test/functional/rpc_signmessage.py
+++ b/test/functional/rpc_signmessage.py
@@ -13,6 +13,9 @@ class SignMessagesTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [["-addresstype=legacy"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
message = 'This is just a test message'
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index 32b099294f..291538df64 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -14,6 +14,9 @@ class SignRawTransactionsTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [["-deprecatedrpc=signrawtransaction"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def successful_signing_test(self):
"""Create and sign a valid raw transaction with one input.
@@ -42,9 +45,13 @@ class SignRawTransactionsTest(BitcoinTestFramework):
# 2) No script verification error occurred
assert 'errors' not in rawTxSigned
- # Perform the same test on signrawtransaction
- rawTxSigned2 = self.nodes[0].signrawtransaction(rawTx, inputs, privKeys)
- assert_equal(rawTxSigned, rawTxSigned2)
+ def test_with_lock_outputs(self):
+ """Test correct error reporting when trying to sign a locked output"""
+ self.nodes[0].encryptwallet("password")
+
+ rawTx = '020000000156b958f78e3f24e0b2f4e4db1255426b0902027cb37e3ddadb52e37c3557dddb0000000000ffffffff01c0a6b929010000001600149a2ee8c77140a053f36018ac8124a6ececc1668a00000000'
+
+ assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].signrawtransactionwithwallet, rawTx)
def script_verification_error_test(self):
"""Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script.
@@ -112,10 +119,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
assert_equal(rawTxSigned['errors'][1]['vout'], inputs[2]['vout'])
assert not rawTxSigned['errors'][0]['witness']
- # Perform same test with signrawtransaction
- rawTxSigned2 = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys)
- assert_equal(rawTxSigned, rawTxSigned2)
-
# Now test signing failure for transaction with input witnesses
p2wpkh_raw_tx = "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"
@@ -140,13 +143,10 @@ class SignRawTransactionsTest(BitcoinTestFramework):
assert_equal(rawTxSigned['errors'][1]['witness'], ["304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01", "025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"])
assert not rawTxSigned['errors'][0]['witness']
- # Perform same test with signrawtransaction
- rawTxSigned2 = self.nodes[0].signrawtransaction(p2wpkh_raw_tx)
- assert_equal(rawTxSigned, rawTxSigned2)
-
def run_test(self):
self.successful_signing_test()
self.script_verification_error_test()
+ self.test_with_lock_outputs()
if __name__ == '__main__':
diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py
index f9f8574646..8913b8698d 100755
--- a/test/functional/rpc_txoutproof.py
+++ b/test/functional/rpc_txoutproof.py
@@ -15,6 +15,9 @@ class MerkleBlockTest(BitcoinTestFramework):
# Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing
self.extra_args = [[], [], [], ["-txindex"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
connect_nodes(self.nodes[0], 1)
@@ -63,12 +66,18 @@ class MerkleBlockTest(BitcoinTestFramework):
txid_spent = txin_spent["txid"]
txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2
+ # Invalid txids
+ assert_raises_rpc_error(-8, "txid must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[2].gettxoutproof, ["00000000000000000000000000000000"], blockhash)
+ assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].gettxoutproof, ["ZZZ0000000000000000000000000000000000000000000000000000000000000"], blockhash)
+ # Invalid blockhashes
+ assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000")
+ assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].gettxoutproof, [txid_spent], "ZZZ0000000000000000000000000000000000000000000000000000000000000")
# We can't find the block from a fully-spent tx
assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[2].gettxoutproof, [txid_spent])
# We can get the proof if we specify the block
assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent])
# We can't get the proof if we specify a non-existent block
- assert_raises_rpc_error(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000")
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "0000000000000000000000000000000000000000000000000000000000000000")
# We can get the proof if the transaction is unspent
assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent])
# We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter.
diff --git a/test/functional/rpc_zmq.py b/test/functional/rpc_zmq.py
deleted file mode 100755
index 6dbc726d5e..0000000000
--- a/test/functional/rpc_zmq.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2018 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 the ZMQ RPC methods."""
-
-from test_framework.test_framework import (
- BitcoinTestFramework, skip_if_no_py3_zmq, skip_if_no_bitcoind_zmq)
-from test_framework.util import assert_equal
-
-
-class RPCZMQTest(BitcoinTestFramework):
-
- address = "tcp://127.0.0.1:28332"
-
- def set_test_params(self):
- self.num_nodes = 1
- self.setup_clean_chain = True
-
- def run_test(self):
- skip_if_no_py3_zmq()
- skip_if_no_bitcoind_zmq(self)
- self._test_getzmqnotifications()
-
- def _test_getzmqnotifications(self):
- self.restart_node(0, extra_args=[])
- assert_equal(self.nodes[0].getzmqnotifications(), [])
-
- self.restart_node(0, extra_args=["-zmqpubhashtx=%s" % self.address])
- assert_equal(self.nodes[0].getzmqnotifications(), [
- {"type": "pubhashtx", "address": self.address},
- ])
-
-
-if __name__ == '__main__':
- RPCZMQTest().main()
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index d1fb97b024..456d43aa2e 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -9,8 +9,11 @@ from .util import bytes_to_hex_str, hex_str_to_bytes
from . import segwit_addr
+ADDRESS_BCRT1_UNSPENDABLE = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj'
+
chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
+
def byte_to_base58(b, version):
result = ''
str = bytes_to_hex_str(b)
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index 900090bb66..1140fe9b3e 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -38,6 +38,7 @@ import decimal
import http.client
import json
import logging
+import os
import socket
import time
import urllib.parse
@@ -71,19 +72,12 @@ class AuthServiceProxy():
self._service_name = service_name
self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests
self.__url = urllib.parse.urlparse(service_url)
- port = 80 if self.__url.port is None else self.__url.port
user = None if self.__url.username is None else self.__url.username.encode('utf8')
passwd = None if self.__url.password is None else self.__url.password.encode('utf8')
authpair = user + b':' + passwd
self.__auth_header = b'Basic ' + base64.b64encode(authpair)
-
- if connection:
- # Callables re-use the connection of the original proxy
- self.__conn = connection
- elif self.__url.scheme == 'https':
- self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=timeout)
- else:
- self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=timeout)
+ self.timeout = timeout
+ self._set_conn(connection)
def __getattr__(self, name):
if name.startswith('__') and name.endswith('__'):
@@ -102,6 +96,10 @@ class AuthServiceProxy():
'User-Agent': USER_AGENT,
'Authorization': self.__auth_header,
'Content-type': 'application/json'}
+ if os.name == 'nt':
+ # Windows somehow does not like to re-use connections
+ # TODO: Find out why the connection would disconnect occasionally and make it reusable on Windows
+ self._set_conn()
try:
self.__conn.request(method, path, postdata, headers)
return self._get_response()
@@ -178,3 +176,13 @@ class AuthServiceProxy():
def __truediv__(self, relative_uri):
return AuthServiceProxy("{}/{}".format(self.__service_url, relative_uri), self._service_name, connection=self.__conn)
+
+ def _set_conn(self, connection=None):
+ port = 80 if self.__url.port is None else self.__url.port
+ if connection:
+ self.__conn = connection
+ self.timeout = connection.timeout
+ elif self.__url.scheme == 'https':
+ self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=self.timeout)
+ else:
+ self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=self.timeout)
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 987ade4044..81cce1167b 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -122,7 +122,7 @@ def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, script_pub_key=C
"""Return one-input, one-output transaction object
spending the prevtx's n-th output with the given amount.
- Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend ouput.
+ Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend output.
"""
tx = CTransaction()
assert(n < len(prevtx.vout))
@@ -169,7 +169,7 @@ def get_legacy_sigopcount_tx(tx, accurate=True):
return count
def witness_script(use_p2wsh, pubkey):
- """Create a scriptPubKey for a pay-to-wtiness TxOut.
+ """Create a scriptPubKey for a pay-to-witness TxOut.
This is 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
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 0a3907cba4..c72cb8835c 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -13,7 +13,11 @@ CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....:
msg_block, msg_tx, msg_headers, etc.:
data structures that represent network messages
-ser_*, deser_*: functions that handle serialization/deserialization."""
+ser_*, deser_*: functions that handle serialization/deserialization.
+
+Classes use __slots__ to ensure extraneous attributes aren't accidentally added
+by tests, compromising their intended effect.
+"""
from codecs import encode
import copy
import hashlib
@@ -31,7 +35,6 @@ MY_VERSION = 70014 # past bip-31 for ping/pong
MY_SUBVERSION = b"/python-mininode-tester:0.0.3/"
MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37)
-MAX_INV_SZ = 50000
MAX_LOCATOR_SZ = 101
MAX_BLOCK_BASE_SIZE = 1000000
@@ -54,9 +57,6 @@ MSG_TYPE_MASK = 0xffffffff >> 2
def sha256(s):
return hashlib.new('sha256', s).digest()
-def ripemd160(s):
- return hashlib.new('ripemd160', s).digest()
-
def hash256(s):
return sha256(sha256(s))
@@ -185,7 +185,10 @@ def ToHex(obj):
# Objects that map to bitcoind objects, which can be serialized/deserialized
-class CAddress():
+
+class CAddress:
+ __slots__ = ("ip", "nServices", "pchReserved", "port", "time")
+
def __init__(self):
self.time = 0
self.nServices = 1
@@ -215,7 +218,10 @@ class CAddress():
return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices,
self.ip, self.port)
-class CInv():
+
+class CInv:
+ __slots__ = ("hash", "type")
+
typemap = {
0: "Error",
1: "TX",
@@ -244,7 +250,9 @@ class CInv():
% (self.typemap[self.type], self.hash)
-class CBlockLocator():
+class CBlockLocator:
+ __slots__ = ("nVersion", "vHave")
+
def __init__(self):
self.nVersion = MY_VERSION
self.vHave = []
@@ -264,7 +272,9 @@ class CBlockLocator():
% (self.nVersion, repr(self.vHave))
-class COutPoint():
+class COutPoint:
+ __slots__ = ("hash", "n")
+
def __init__(self, hash=0, n=0):
self.hash = hash
self.n = n
@@ -283,7 +293,9 @@ class COutPoint():
return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n)
-class CTxIn():
+class CTxIn:
+ __slots__ = ("nSequence", "prevout", "scriptSig")
+
def __init__(self, outpoint=None, scriptSig=b"", nSequence=0):
if outpoint is None:
self.prevout = COutPoint()
@@ -311,7 +323,9 @@ class CTxIn():
self.nSequence)
-class CTxOut():
+class CTxOut:
+ __slots__ = ("nValue", "scriptPubKey")
+
def __init__(self, nValue=0, scriptPubKey=b""):
self.nValue = nValue
self.scriptPubKey = scriptPubKey
@@ -332,7 +346,9 @@ class CTxOut():
bytes_to_hex_str(self.scriptPubKey))
-class CScriptWitness():
+class CScriptWitness:
+ __slots__ = ("stack",)
+
def __init__(self):
# stack is a vector of strings
self.stack = []
@@ -347,7 +363,9 @@ class CScriptWitness():
return True
-class CTxInWitness():
+class CTxInWitness:
+ __slots__ = ("scriptWitness",)
+
def __init__(self):
self.scriptWitness = CScriptWitness()
@@ -364,7 +382,9 @@ class CTxInWitness():
return self.scriptWitness.is_null()
-class CTxWitness():
+class CTxWitness:
+ __slots__ = ("vtxinwit",)
+
def __init__(self):
self.vtxinwit = []
@@ -392,7 +412,10 @@ class CTxWitness():
return True
-class CTransaction():
+class CTransaction:
+ __slots__ = ("hash", "nLockTime", "nVersion", "sha256", "vin", "vout",
+ "wit")
+
def __init__(self, tx=None):
if tx is None:
self.nVersion = 1
@@ -496,7 +519,10 @@ class CTransaction():
% (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime)
-class CBlockHeader():
+class CBlockHeader:
+ __slots__ = ("hash", "hashMerkleRoot", "hashPrevBlock", "nBits", "nNonce",
+ "nTime", "nVersion", "sha256")
+
def __init__(self, header=None):
if header is None:
self.set_null()
@@ -565,6 +591,8 @@ class CBlockHeader():
class CBlock(CBlockHeader):
+ __slots__ = ("vtx",)
+
def __init__(self, header=None):
super(CBlock, self).__init__(header)
self.vtx = []
@@ -636,7 +664,9 @@ class CBlock(CBlockHeader):
time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx))
-class PrefilledTransaction():
+class PrefilledTransaction:
+ __slots__ = ("index", "tx")
+
def __init__(self, index=0, tx = None):
self.index = index
self.tx = tx
@@ -664,8 +694,12 @@ class PrefilledTransaction():
def __repr__(self):
return "PrefilledTransaction(index=%d, tx=%s)" % (self.index, repr(self.tx))
+
# This is what we send on the wire, in a cmpctblock message.
-class P2PHeaderAndShortIDs():
+class P2PHeaderAndShortIDs:
+ __slots__ = ("header", "nonce", "prefilled_txn", "prefilled_txn_length",
+ "shortids", "shortids_length")
+
def __init__(self):
self.header = CBlockHeader()
self.nonce = 0
@@ -703,9 +737,11 @@ class P2PHeaderAndShortIDs():
def __repr__(self):
return "P2PHeaderAndShortIDs(header=%s, nonce=%d, shortids_length=%d, shortids=%s, prefilled_txn_length=%d, prefilledtxn=%s" % (repr(self.header), self.nonce, self.shortids_length, repr(self.shortids), self.prefilled_txn_length, repr(self.prefilled_txn))
+
# P2P version of the above that will use witness serialization (for compact
# block version 2)
class P2PHeaderAndShortWitnessIDs(P2PHeaderAndShortIDs):
+ __slots__ = ()
def serialize(self):
return super(P2PHeaderAndShortWitnessIDs, self).serialize(with_witness=True)
@@ -715,9 +751,12 @@ def calculate_shortid(k0, k1, tx_hash):
expected_shortid &= 0x0000ffffffffffff
return expected_shortid
+
# This version gets rid of the array lengths, and reinterprets the differential
# encoding into indices that can be used for lookup.
-class HeaderAndShortIDs():
+class HeaderAndShortIDs:
+ __slots__ = ("header", "nonce", "prefilled_txn", "shortids", "use_witness")
+
def __init__(self, p2pheaders_and_shortids = None):
self.header = CBlockHeader()
self.nonce = 0
@@ -778,7 +817,8 @@ class HeaderAndShortIDs():
return "HeaderAndShortIDs(header=%s, nonce=%d, shortids=%s, prefilledtxn=%s" % (repr(self.header), self.nonce, repr(self.shortids), repr(self.prefilled_txn))
-class BlockTransactionsRequest():
+class BlockTransactionsRequest:
+ __slots__ = ("blockhash", "indexes")
def __init__(self, blockhash=0, indexes = None):
self.blockhash = blockhash
@@ -818,7 +858,8 @@ class BlockTransactionsRequest():
return "BlockTransactionsRequest(hash=%064x indexes=%s)" % (self.blockhash, repr(self.indexes))
-class BlockTransactions():
+class BlockTransactions:
+ __slots__ = ("blockhash", "transactions")
def __init__(self, blockhash=0, transactions = None):
self.blockhash = blockhash
@@ -840,12 +881,14 @@ class BlockTransactions():
def __repr__(self):
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))
-class CPartialMerkleTree():
+
+class CPartialMerkleTree:
+ __slots__ = ("nTransactions", "vBits", "vHash")
+
def __init__(self):
self.nTransactions = 0
self.vHash = []
self.vBits = []
- self.fBad = False
def deserialize(self, f):
self.nTransactions = struct.unpack("<i", f.read(4))[0]
@@ -868,7 +911,10 @@ class CPartialMerkleTree():
def __repr__(self):
return "CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)" % (self.nTransactions, repr(self.vHash), repr(self.vBits))
-class CMerkleBlock():
+
+class CMerkleBlock:
+ __slots__ = ("header", "txn")
+
def __init__(self):
self.header = CBlockHeader()
self.txn = CPartialMerkleTree()
@@ -888,7 +934,9 @@ class CMerkleBlock():
# Objects that correspond to messages on the wire
-class msg_version():
+class msg_version:
+ __slots__ = ("addrFrom", "addrTo", "nNonce", "nRelay", "nServices",
+ "nStartingHeight", "nTime", "nVersion", "strSubVer")
command = b"version"
def __init__(self):
@@ -945,7 +993,8 @@ class msg_version():
self.strSubVer, self.nStartingHeight, self.nRelay)
-class msg_verack():
+class msg_verack:
+ __slots__ = ()
command = b"verack"
def __init__(self):
@@ -961,7 +1010,8 @@ class msg_verack():
return "msg_verack()"
-class msg_addr():
+class msg_addr:
+ __slots__ = ("addrs",)
command = b"addr"
def __init__(self):
@@ -977,7 +1027,8 @@ class msg_addr():
return "msg_addr(addrs=%s)" % (repr(self.addrs))
-class msg_inv():
+class msg_inv:
+ __slots__ = ("inv",)
command = b"inv"
def __init__(self, inv=None):
@@ -996,7 +1047,8 @@ class msg_inv():
return "msg_inv(inv=%s)" % (repr(self.inv))
-class msg_getdata():
+class msg_getdata:
+ __slots__ = ("inv",)
command = b"getdata"
def __init__(self, inv=None):
@@ -1012,7 +1064,8 @@ class msg_getdata():
return "msg_getdata(inv=%s)" % (repr(self.inv))
-class msg_getblocks():
+class msg_getblocks:
+ __slots__ = ("locator", "hashstop")
command = b"getblocks"
def __init__(self):
@@ -1035,7 +1088,8 @@ class msg_getblocks():
% (repr(self.locator), self.hashstop)
-class msg_tx():
+class msg_tx:
+ __slots__ = ("tx",)
command = b"tx"
def __init__(self, tx=CTransaction()):
@@ -1050,13 +1104,16 @@ class msg_tx():
def __repr__(self):
return "msg_tx(tx=%s)" % (repr(self.tx))
+
class msg_witness_tx(msg_tx):
+ __slots__ = ()
def serialize(self):
return self.tx.serialize_with_witness()
-class msg_block():
+class msg_block:
+ __slots__ = ("block",)
command = b"block"
def __init__(self, block=None):
@@ -1074,9 +1131,12 @@ class msg_block():
def __repr__(self):
return "msg_block(block=%s)" % (repr(self.block))
+
# for cases where a user needs tighter control over what is sent over the wire
# note that the user must supply the name of the command, and the data
-class msg_generic():
+class msg_generic:
+ __slots__ = ("command", "data")
+
def __init__(self, command, data=None):
self.command = command
self.data = data
@@ -1087,13 +1147,16 @@ class msg_generic():
def __repr__(self):
return "msg_generic()"
-class msg_witness_block(msg_block):
+class msg_witness_block(msg_block):
+ __slots__ = ()
def serialize(self):
r = self.block.serialize(with_witness=True)
return r
-class msg_getaddr():
+
+class msg_getaddr:
+ __slots__ = ()
command = b"getaddr"
def __init__(self):
@@ -1109,7 +1172,8 @@ class msg_getaddr():
return "msg_getaddr()"
-class msg_ping():
+class msg_ping:
+ __slots__ = ("nonce",)
command = b"ping"
def __init__(self, nonce=0):
@@ -1127,7 +1191,8 @@ class msg_ping():
return "msg_ping(nonce=%08x)" % self.nonce
-class msg_pong():
+class msg_pong:
+ __slots__ = ("nonce",)
command = b"pong"
def __init__(self, nonce=0):
@@ -1145,7 +1210,8 @@ class msg_pong():
return "msg_pong(nonce=%08x)" % self.nonce
-class msg_mempool():
+class msg_mempool:
+ __slots__ = ()
command = b"mempool"
def __init__(self):
@@ -1160,7 +1226,26 @@ class msg_mempool():
def __repr__(self):
return "msg_mempool()"
-class msg_sendheaders():
+
+class msg_notfound:
+ __slots__ = ("vec", )
+ command = b"notfound"
+
+ def __init__(self, vec=None):
+ self.vec = vec or []
+
+ def deserialize(self, f):
+ self.vec = deser_vector(f, CInv)
+
+ def serialize(self):
+ return ser_vector(self.vec)
+
+ def __repr__(self):
+ return "msg_notfound(vec=%s)" % (repr(self.vec))
+
+
+class msg_sendheaders:
+ __slots__ = ()
command = b"sendheaders"
def __init__(self):
@@ -1180,7 +1265,8 @@ class msg_sendheaders():
# number of entries
# vector of hashes
# hash_stop (hash of last desired block header, 0 to get as many as possible)
-class msg_getheaders():
+class msg_getheaders:
+ __slots__ = ("hashstop", "locator",)
command = b"getheaders"
def __init__(self):
@@ -1205,7 +1291,8 @@ class msg_getheaders():
# headers message has
# <count> <vector of block headers>
-class msg_headers():
+class msg_headers:
+ __slots__ = ("headers",)
command = b"headers"
def __init__(self, headers=None):
@@ -1225,7 +1312,8 @@ class msg_headers():
return "msg_headers(headers=%s)" % repr(self.headers)
-class msg_reject():
+class msg_reject:
+ __slots__ = ("code", "data", "message", "reason")
command = b"reject"
REJECT_MALFORMED = 1
@@ -1256,7 +1344,9 @@ class msg_reject():
return "msg_reject: %s %d %s [%064x]" \
% (self.message, self.code, self.reason, self.data)
-class msg_feefilter():
+
+class msg_feefilter:
+ __slots__ = ("feerate",)
command = b"feefilter"
def __init__(self, feerate=0):
@@ -1273,7 +1363,9 @@ class msg_feefilter():
def __repr__(self):
return "msg_feefilter(feerate=%08x)" % self.feerate
-class msg_sendcmpct():
+
+class msg_sendcmpct:
+ __slots__ = ("announce", "version")
command = b"sendcmpct"
def __init__(self):
@@ -1293,7 +1385,9 @@ class msg_sendcmpct():
def __repr__(self):
return "msg_sendcmpct(announce=%s, version=%lu)" % (self.announce, self.version)
-class msg_cmpctblock():
+
+class msg_cmpctblock:
+ __slots__ = ("header_and_shortids",)
command = b"cmpctblock"
def __init__(self, header_and_shortids = None):
@@ -1311,7 +1405,9 @@ class msg_cmpctblock():
def __repr__(self):
return "msg_cmpctblock(HeaderAndShortIDs=%s)" % repr(self.header_and_shortids)
-class msg_getblocktxn():
+
+class msg_getblocktxn:
+ __slots__ = ("block_txn_request",)
command = b"getblocktxn"
def __init__(self):
@@ -1329,7 +1425,9 @@ class msg_getblocktxn():
def __repr__(self):
return "msg_getblocktxn(block_txn_request=%s)" % (repr(self.block_txn_request))
-class msg_blocktxn():
+
+class msg_blocktxn:
+ __slots__ = ("block_transactions",)
command = b"blocktxn"
def __init__(self):
@@ -1346,7 +1444,10 @@ class msg_blocktxn():
def __repr__(self):
return "msg_blocktxn(block_transactions=%s)" % (repr(self.block_transactions))
+
class msg_witness_blocktxn(msg_blocktxn):
+ __slots__ = ()
+
def serialize(self):
r = b""
r += self.block_transactions.serialize(with_witness=True)
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index d1ddbbe8ee..ca5734d67d 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -21,7 +21,38 @@ import struct
import sys
import threading
-from test_framework.messages import CBlockHeader, MIN_VERSION_SUPPORTED, msg_addr, msg_block, MSG_BLOCK, msg_blocktxn, msg_cmpctblock, msg_feefilter, msg_getaddr, msg_getblocks, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_mempool, msg_ping, msg_pong, msg_reject, msg_sendcmpct, msg_sendheaders, msg_tx, MSG_TX, MSG_TYPE_MASK, msg_verack, msg_version, NODE_NETWORK, NODE_WITNESS, sha256
+from test_framework.messages import (
+ CBlockHeader,
+ MIN_VERSION_SUPPORTED,
+ msg_addr,
+ msg_block,
+ MSG_BLOCK,
+ msg_blocktxn,
+ msg_cmpctblock,
+ msg_feefilter,
+ msg_getaddr,
+ msg_getblocks,
+ msg_getblocktxn,
+ msg_getdata,
+ msg_getheaders,
+ msg_headers,
+ msg_inv,
+ msg_mempool,
+ msg_notfound,
+ msg_ping,
+ msg_pong,
+ msg_reject,
+ msg_sendcmpct,
+ msg_sendheaders,
+ msg_tx,
+ MSG_TX,
+ MSG_TYPE_MASK,
+ msg_verack,
+ msg_version,
+ NODE_NETWORK,
+ NODE_WITNESS,
+ sha256,
+)
from test_framework.util import wait_until
logger = logging.getLogger("TestFramework.mininode")
@@ -40,6 +71,7 @@ MESSAGEMAP = {
b"headers": msg_headers,
b"inv": msg_inv,
b"mempool": msg_mempool,
+ b"notfound": msg_notfound,
b"ping": msg_ping,
b"pong": msg_pong,
b"reject": msg_reject,
@@ -175,10 +207,13 @@ class P2PConnection(asyncio.Protocol):
This method takes a P2P payload, builds the P2P header and adds
the message to the send buffer to be sent over the socket."""
+ tmsg = self.build_message(message)
+ self._log_message("send", message)
+ return self.send_raw_message(tmsg)
+
+ def send_raw_message(self, raw_message_bytes):
if not self.is_connected:
raise IOError('Not connected')
- self._log_message("send", message)
- tmsg = self._build_message(message)
def maybe_write():
if not self._transport:
@@ -188,12 +223,12 @@ class P2PConnection(asyncio.Protocol):
# Python 3.4 versions.
if hasattr(self._transport, 'is_closing') and self._transport.is_closing():
return
- self._transport.write(tmsg)
+ self._transport.write(raw_message_bytes)
NetworkThread.network_event_loop.call_soon_threadsafe(maybe_write)
# Class utility methods
- def _build_message(self, message):
+ def build_message(self, message):
"""Build a serialized P2P message"""
command = message.command
data = message.serialize()
@@ -295,6 +330,7 @@ class P2PInterface(P2PConnection):
def on_getheaders(self, message): pass
def on_headers(self, message): pass
def on_mempool(self, message): pass
+ def on_notfound(self, message): pass
def on_pong(self, message): pass
def on_reject(self, message): pass
def on_sendcmpct(self, message): pass
@@ -313,7 +349,7 @@ class P2PInterface(P2PConnection):
self.send_message(msg_pong(message.nonce))
def on_verack(self, message):
- self.verack_received = True
+ pass
def on_version(self, message):
assert message.nVersion >= MIN_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_VERSION_SUPPORTED)
@@ -376,9 +412,9 @@ class P2PInterface(P2PConnection):
# Message sending helper functions
- def send_and_ping(self, message):
+ def send_and_ping(self, message, timeout=60):
self.send_message(message)
- self.sync_with_ping()
+ self.sync_with_ping(timeout=timeout)
# Sync up with the node
def sync_with_ping(self, timeout=60):
@@ -425,8 +461,6 @@ class P2PDataStore(P2PInterface):
def __init__(self):
super().__init__()
- self.reject_code_received = None
- self.reject_reason_received = None
# store of blocks. key is block hash, value is a CBlock object
self.block_store = {}
self.last_block_hash = ''
@@ -477,81 +511,71 @@ class P2PDataStore(P2PInterface):
if response is not None:
self.send_message(response)
- def on_reject(self, message):
- """Store reject reason and code for testing."""
- self.reject_code_received = message.code
- self.reject_reason_received = message.reason
-
- def send_blocks_and_test(self, blocks, rpc, success=True, request_block=True, reject_code=None, reject_reason=None, timeout=60):
+ def send_blocks_and_test(self, blocks, node, *, success=True, force_send=False, reject_reason=None, expect_disconnect=False, timeout=60):
"""Send blocks to test node and test whether the tip advances.
- add all blocks to our block_store
- send a headers message for the final block
- the on_getheaders handler will ensure that any getheaders are responded to
- - if request_block is True: wait for getdata for each of the blocks. The on_getdata handler will
- ensure that any getdata messages are responded to
+ - if force_send is False: wait for getdata for each of the blocks. The on_getdata handler will
+ ensure that any getdata messages are responded to. Otherwise send the full block unsolicited.
- if success is True: assert that the node's tip advances to the most recent block
- if success is False: assert that the node's tip doesn't advance
- - if reject_code and reject_reason are set: assert that the correct reject message is received"""
+ - if reject_reason is set: assert that the correct reject message is logged"""
with mininode_lock:
- self.reject_code_received = None
- self.reject_reason_received = None
-
for block in blocks:
self.block_store[block.sha256] = block
self.last_block_hash = block.sha256
- self.send_message(msg_headers([CBlockHeader(blocks[-1])]))
-
- if request_block:
- wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)
+ reject_reason = [reject_reason] if reject_reason else []
+ with node.assert_debug_log(expected_msgs=reject_reason):
+ if force_send:
+ for b in blocks:
+ self.send_message(msg_block(block=b))
+ else:
+ self.send_message(msg_headers([CBlockHeader(blocks[-1])]))
+ wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)
- if success:
- wait_until(lambda: rpc.getbestblockhash() == blocks[-1].hash, timeout=timeout)
- else:
- assert rpc.getbestblockhash() != blocks[-1].hash
+ if expect_disconnect:
+ self.wait_for_disconnect(timeout=timeout)
+ else:
+ self.sync_with_ping(timeout=timeout)
- if reject_code is not None:
- wait_until(lambda: self.reject_code_received == reject_code, lock=mininode_lock)
- if reject_reason is not None:
- wait_until(lambda: self.reject_reason_received == reject_reason, lock=mininode_lock)
+ if success:
+ wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout)
+ else:
+ assert node.getbestblockhash() != blocks[-1].hash
- def send_txs_and_test(self, txs, rpc, success=True, expect_disconnect=False, reject_code=None, reject_reason=None):
+ def send_txs_and_test(self, txs, node, *, success=True, expect_disconnect=False, reject_reason=None):
"""Send txs to test node and test whether they're accepted to the mempool.
- add all txs to our tx_store
- send tx messages for all txs
- if success is True/False: assert that the txs are/are not accepted to the mempool
- if expect_disconnect is True: Skip the sync with ping
- - if reject_code and reject_reason are set: assert that the correct reject message is received."""
+ - if reject_reason is set: assert that the correct reject message is logged."""
with mininode_lock:
- self.reject_code_received = None
- self.reject_reason_received = None
-
for tx in txs:
self.tx_store[tx.sha256] = tx
- for tx in txs:
- self.send_message(msg_tx(tx))
-
- if expect_disconnect:
- self.wait_for_disconnect()
- else:
- self.sync_with_ping()
-
- raw_mempool = rpc.getrawmempool()
- if success:
- # Check that all txs are now in the mempool
+ reject_reason = [reject_reason] if reject_reason else []
+ with node.assert_debug_log(expected_msgs=reject_reason):
for tx in txs:
- assert tx.hash in raw_mempool, "{} not found in mempool".format(tx.hash)
- else:
- # Check that none of the txs are now in the mempool
- for tx in txs:
- assert tx.hash not in raw_mempool, "{} tx found in mempool".format(tx.hash)
+ self.send_message(msg_tx(tx))
- if reject_code is not None:
- wait_until(lambda: self.reject_code_received == reject_code, lock=mininode_lock)
- if reject_reason is not None:
- wait_until(lambda: self.reject_reason_received == reject_reason, lock=mininode_lock)
+ if expect_disconnect:
+ self.wait_for_disconnect()
+ else:
+ self.sync_with_ping()
+
+ raw_mempool = node.getrawmempool()
+ if success:
+ # Check that all txs are now in the mempool
+ for tx in txs:
+ assert tx.hash in raw_mempool, "{} not found in mempool".format(tx.hash)
+ else:
+ # Check that none of the txs are now in the mempool
+ for tx in txs:
+ assert tx.hash not in raw_mempool, "{} tx found in mempool".format(tx.hash)
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 375d6334f7..2fe44010ba 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -26,7 +26,7 @@ def hash160(s):
_opcode_instances = []
class CScriptOp(int):
"""A single script opcode"""
- __slots__ = []
+ __slots__ = ()
@staticmethod
def encode_op_pushdata(d):
@@ -361,8 +361,11 @@ class CScriptTruncatedPushDataError(CScriptInvalidError):
self.data = data
super(CScriptTruncatedPushDataError, self).__init__(msg)
+
# This is used, eg, for blockchain heights in coinbase scripts (bip34)
-class CScriptNum():
+class CScriptNum:
+ __slots__ = ("value",)
+
def __init__(self, d=0):
self.value = d
@@ -393,6 +396,8 @@ class CScript(bytes):
iter(script) however does iterate by opcode.
"""
+ __slots__ = ()
+
@classmethod
def __coerce_instance(cls, other):
# Coerce other into bytes
diff --git a/test/functional/test_framework/socks5.py b/test/functional/test_framework/socks5.py
index dd0f209268..a21c864e75 100644
--- a/test/functional/test_framework/socks5.py
+++ b/test/functional/test_framework/socks5.py
@@ -54,10 +54,9 @@ class Socks5Command():
return 'Socks5Command(%s,%s,%s,%s,%s,%s)' % (self.cmd, self.atyp, self.addr, self.port, self.username, self.password)
class Socks5Connection():
- def __init__(self, serv, conn, peer):
+ def __init__(self, serv, conn):
self.serv = serv
self.conn = conn
- self.peer = peer
def handle(self):
"""Handle socks5 request according to RFC192."""
@@ -137,9 +136,9 @@ class Socks5Server():
def run(self):
while self.running:
- (sockconn, peer) = self.s.accept()
+ (sockconn, _) = self.s.accept()
if self.running:
- conn = Socks5Connection(self, sockconn, peer)
+ conn = Socks5Connection(self, sockconn)
thread = threading.Thread(None, conn.handle)
thread.daemon = True
thread.start()
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index b876d9bd76..0dfa9e0d24 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -43,6 +43,15 @@ TEST_EXIT_PASSED = 0
TEST_EXIT_FAILED = 1
TEST_EXIT_SKIPPED = 77
+TMPDIR_PREFIX = "bitcoin_func_test_"
+
+
+class SkipTest(Exception):
+ """This exception is raised to skip a test"""
+
+ def __init__(self, message):
+ self.message = message
+
class BitcoinTestMetaClass(type):
"""Metaclass for BitcoinTestFramework.
@@ -144,7 +153,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.options.tmpdir = os.path.abspath(self.options.tmpdir)
os.makedirs(self.options.tmpdir, exist_ok=False)
else:
- self.options.tmpdir = tempfile.mkdtemp(prefix="test")
+ self.options.tmpdir = tempfile.mkdtemp(prefix=TMPDIR_PREFIX)
self._start_logging()
self.log.debug('Setting up network thread')
@@ -154,8 +163,11 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
success = TestStatus.FAILED
try:
- if self.options.usecli and not self.supports_cli:
- raise SkipTest("--usecli specified but test does not support using CLI")
+ if self.options.usecli:
+ if not self.supports_cli:
+ raise SkipTest("--usecli specified but test does not support using CLI")
+ self.skip_if_no_cli()
+ self.skip_test_if_missing_module()
self.setup_chain()
self.setup_network()
self.run_test()
@@ -220,6 +232,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"""Override this method to add command-line options to the test"""
pass
+ def skip_test_if_missing_module(self):
+ """Override this method to skip a test if a module is not compiled"""
+ pass
+
def setup_chain(self):
"""Override this method to customize blockchain setup"""
self.log.info("Initializing test directory " + self.options.tmpdir)
@@ -246,6 +262,17 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
extra_args = self.extra_args
self.add_nodes(self.num_nodes, extra_args)
self.start_nodes()
+ self.import_deterministic_coinbase_privkeys()
+
+ def import_deterministic_coinbase_privkeys(self):
+ for n in self.nodes:
+ try:
+ n.getwalletinfo()
+ except JSONRPCException as e:
+ assert str(e).startswith('Method not found')
+ continue
+
+ n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')
def run_test(self):
"""Tests must override this method to define test logic"""
@@ -415,7 +442,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Create cache directories, run bitcoinds:
for i in range(MAX_NODES):
datadir = initialize_datadir(self.options.cachedir, i)
- args = [self.options.bitcoind, "-datadir=" + datadir]
+ args = [self.options.bitcoind, "-datadir=" + datadir, '-disablewallet']
if i > 0:
args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
self.nodes.append(TestNode(i, get_datadir_path(self.options.cachedir, i), extra_conf=["bind=127.0.0.1"], extra_args=[], rpchost=None, timewait=self.rpc_timewait, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, mocktime=self.mocktime, coverage_dir=None))
@@ -439,7 +466,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
for peer in range(4):
for j in range(25):
set_node_times(self.nodes, block_time)
- self.nodes[peer].generate(1)
+ self.nodes[peer].generatetoaddress(1, self.nodes[peer].get_deterministic_priv_key().address)
block_time += 10 * 60
# Must sync before next peer starts generating blocks
sync_blocks(self.nodes)
@@ -453,8 +480,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths)
for i in range(MAX_NODES):
+ os.rmdir(cache_path(i, 'wallets')) # Remove empty wallets dir
for entry in os.listdir(cache_path(i)):
- if entry not in ['wallets', 'chainstate', 'blocks']:
+ if entry not in ['chainstate', 'blocks']:
os.remove(cache_path(i, entry))
for i in range(self.num_nodes):
@@ -471,25 +499,45 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
for i in range(self.num_nodes):
initialize_datadir(self.options.tmpdir, i)
+ def skip_if_no_py3_zmq(self):
+ """Attempt to import the zmq package and skip the test if the import fails."""
+ try:
+ import zmq # noqa
+ except ImportError:
+ raise SkipTest("python3-zmq module not available.")
+
+ def skip_if_no_bitcoind_zmq(self):
+ """Skip the running test if bitcoind has not been compiled with zmq support."""
+ if not self.is_zmq_compiled():
+ raise SkipTest("bitcoind has not been built with zmq enabled.")
+
+ def skip_if_no_wallet(self):
+ """Skip the running test if wallet has not been compiled."""
+ if not self.is_wallet_compiled():
+ raise SkipTest("wallet has not been compiled.")
+
+ def skip_if_no_cli(self):
+ """Skip the running test if bitcoin-cli has not been compiled."""
+ if not self.is_cli_compiled():
+ raise SkipTest("bitcoin-cli has not been compiled.")
+
+ def is_cli_compiled(self):
+ """Checks whether bitcoin-cli was compiled."""
+ config = configparser.ConfigParser()
+ config.read_file(open(self.options.configfile))
-class SkipTest(Exception):
- """This exception is raised to skip a test"""
- def __init__(self, message):
- self.message = message
-
+ return config["components"].getboolean("ENABLE_CLI")
-def skip_if_no_py3_zmq():
- """Attempt to import the zmq package and skip the test if the import fails."""
- try:
- import zmq # noqa
- except ImportError:
- raise SkipTest("python3-zmq module not available.")
+ def is_wallet_compiled(self):
+ """Checks whether the wallet module was compiled."""
+ config = configparser.ConfigParser()
+ config.read_file(open(self.options.configfile))
+ return config["components"].getboolean("ENABLE_WALLET")
-def skip_if_no_bitcoind_zmq(test_instance):
- """Skip the running test if bitcoind has not been compiled with zmq support."""
- config = configparser.ConfigParser()
- config.read_file(open(test_instance.options.configfile))
+ def is_zmq_compiled(self):
+ """Checks whether the zmq module was compiled."""
+ config = configparser.ConfigParser()
+ config.read_file(open(self.options.configfile))
- if not config["components"].getboolean("ENABLE_ZMQ"):
- raise SkipTest("bitcoind has not been built with zmq enabled.")
+ return config["components"].getboolean("ENABLE_ZMQ")
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index a831fdcd5d..27f99c259c 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -17,6 +17,7 @@ import subprocess
import tempfile
import time
import urllib.parse
+import collections
from .authproxy import JSONRPCException
from .util import (
@@ -97,6 +98,42 @@ class TestNode():
self.p2ps = []
+ def get_deterministic_priv_key(self):
+ """Return a deterministic priv key in base58, that only depends on the node's index"""
+ AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
+ PRIV_KEYS = [
+ # address , privkey
+ AddressKeyPair('mjTkW3DjgyZck4KbiRusZsqTgaYTxdSz6z', 'cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW'),
+ AddressKeyPair('msX6jQXvxiNhx3Q62PKeLPrhrqZQdSimTg', 'cUxsWyKyZ9MAQTaAhUQWJmBbSvHMwSmuv59KgxQV7oZQU3PXN3KE'),
+ AddressKeyPair('mnonCMyH9TmAsSj3M59DsbH8H63U3RKoFP', 'cTrh7dkEAeJd6b3MRX9bZK8eRmNqVCMH3LSUkE3dSFDyzjU38QxK'),
+ AddressKeyPair('mqJupas8Dt2uestQDvV2NH3RU8uZh2dqQR', 'cVuKKa7gbehEQvVq717hYcbE9Dqmq7KEBKqWgWrYBa2CKKrhtRim'),
+ AddressKeyPair('msYac7Rvd5ywm6pEmkjyxhbCDKqWsVeYws', 'cQDCBuKcjanpXDpCqacNSjYfxeQj8G6CAtH1Dsk3cXyqLNC4RPuh'),
+ AddressKeyPair('n2rnuUnwLgXqf9kk2kjvVm8R5BZK1yxQBi', 'cQakmfPSLSqKHyMFGwAqKHgWUiofJCagVGhiB4KCainaeCSxeyYq'),
+ AddressKeyPair('myzuPxRwsf3vvGzEuzPfK9Nf2RfwauwYe6', 'cQMpDLJwA8DBe9NcQbdoSb1BhmFxVjWD5gRyrLZCtpuF9Zi3a9RK'),
+ AddressKeyPair('mumwTaMtbxEPUswmLBBN3vM9oGRtGBrys8', 'cSXmRKXVcoouhNNVpcNKFfxsTsToY5pvB9DVsFksF1ENunTzRKsy'),
+ AddressKeyPair('mpV7aGShMkJCZgbW7F6iZgrvuPHjZjH9qg', 'cSoXt6tm3pqy43UMabY6eUTmR3eSUYFtB2iNQDGgb3VUnRsQys2k'),
+ ]
+ return PRIV_KEYS[self.index]
+
+ def get_mem_rss_kilobytes(self):
+ """Get the memory usage (RSS) per `ps`.
+
+ Returns None if `ps` is unavailable.
+ """
+ assert self.running
+
+ try:
+ return int(subprocess.check_output(
+ ["ps", "h", "-o", "rss", "{}".format(self.process.pid)],
+ stderr=subprocess.DEVNULL).split()[-1])
+
+ # Avoid failing on platforms where ps isn't installed.
+ #
+ # We could later use something like `psutils` to work across platforms.
+ except (FileNotFoundError, subprocess.SubprocessError):
+ self.log.exception("Unable to get memory usage")
+ return None
+
def _node_msg(self, msg: str) -> str:
"""Return a modified msg that identifies this node by its index as a debugging aid."""
return "[node %d] %s" % (self.index, msg)
@@ -169,7 +206,9 @@ class TestNode():
if e.errno != errno.ECONNREFUSED: # Port not yet open?
raise # unknown IO error
except JSONRPCException as e: # Initialization phase
- if e.error['code'] != -28: # RPC in warmup?
+ # -28 RPC in warmup
+ # -342 Service unavailable, RPC server started but is shutting down due to error
+ if e.error['code'] != -28 and e.error['code'] != -342:
raise # unknown JSON RPC exception
except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting
if "No RPC credentials" not in str(e):
@@ -177,6 +216,10 @@ class TestNode():
time.sleep(1.0 / poll_per_s)
self._raise_assertion_error("Unable to connect to bitcoind")
+ def generate(self, nblocks, maxtries=1000000):
+ self.log.debug("TestNode.generate() dispatches `generate` call to `generatetoaddress`")
+ return self.generatetoaddress(nblocks=nblocks, address=self.get_deterministic_priv_key().address, maxtries=maxtries)
+
def get_wallet_rpc(self, wallet_name):
if self.use_cli:
return self.cli("-rpcwallet={}".format(wallet_name))
@@ -247,6 +290,33 @@ class TestNode():
if re.search(re.escape(expected_msg), log, flags=re.MULTILINE) is None:
self._raise_assertion_error('Expected message "{}" does not partially match log:\n\n{}\n\n'.format(expected_msg, print_log))
+ @contextlib.contextmanager
+ def assert_memory_usage_stable(self, *, increase_allowed=0.03):
+ """Context manager that allows the user to assert that a node's memory usage (RSS)
+ hasn't increased beyond some threshold percentage.
+
+ Args:
+ increase_allowed (float): the fractional increase in memory allowed until failure;
+ e.g. `0.12` for up to 12% increase allowed.
+ """
+ before_memory_usage = self.get_mem_rss_kilobytes()
+
+ yield
+
+ after_memory_usage = self.get_mem_rss_kilobytes()
+
+ if not (before_memory_usage and after_memory_usage):
+ self.log.warning("Unable to detect memory usage (RSS) - skipping memory check.")
+ return
+
+ perc_increase_memory_usage = (after_memory_usage / before_memory_usage) - 1
+
+ if perc_increase_memory_usage > increase_allowed:
+ self._raise_assertion_error(
+ "Memory usage increased over threshold of {:.3f}% from {} to {} ({:.3f}%)".format(
+ increase_allowed * 100, before_memory_usage, after_memory_usage,
+ perc_increase_memory_usage * 100))
+
def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs):
"""Attempt to start the node and expect it to raise an error.
@@ -289,14 +359,6 @@ class TestNode():
assert_msg = "bitcoind should have exited with expected error " + expected_msg
self._raise_assertion_error(assert_msg)
- def node_encrypt_wallet(self, passphrase):
- """"Encrypts the wallet.
-
- This causes bitcoind to shutdown, so this method takes
- care of cleaning up resources."""
- self.encryptwallet(passphrase)
- self.wait_until_stopped()
-
def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs):
"""Add a p2p connection to the node.
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index feea2a327a..1167b4bba2 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -29,7 +29,7 @@ import re
import logging
# Formatting. Default colors to empty strings.
-BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
+BOLD, GREEN, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
try:
# Make sure python thinks it can write unicode to its stdout
"\u2713".encode("utf_8").decode(sys.stdout.encoding)
@@ -41,26 +41,42 @@ except UnicodeDecodeError:
CROSS = "x "
CIRCLE = "o "
-if os.name == 'posix':
+if os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393):
+ if os.name == 'nt':
+ import ctypes
+ kernel32 = ctypes.windll.kernel32
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
+ STD_OUTPUT_HANDLE = -11
+ STD_ERROR_HANDLE = -12
+ # Enable ascii color control to stdout
+ stdout = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
+ stdout_mode = ctypes.c_int32()
+ kernel32.GetConsoleMode(stdout, ctypes.byref(stdout_mode))
+ kernel32.SetConsoleMode(stdout, stdout_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ # Enable ascii color control to stderr
+ stderr = kernel32.GetStdHandle(STD_ERROR_HANDLE)
+ stderr_mode = ctypes.c_int32()
+ kernel32.GetConsoleMode(stderr, ctypes.byref(stderr_mode))
+ kernel32.SetConsoleMode(stderr, stderr_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
# primitive formatting on supported
# terminal via ANSI escape sequences:
BOLD = ('\033[0m', '\033[1m')
- BLUE = ('\033[0m', '\033[0;34m')
+ GREEN = ('\033[0m', '\033[0;32m')
RED = ('\033[0m', '\033[0;31m')
GREY = ('\033[0m', '\033[1;30m')
TEST_EXIT_PASSED = 0
TEST_EXIT_SKIPPED = 77
-# 20 minutes represented in seconds
-TRAVIS_TIMEOUT_DURATION = 20 * 60
-
BASE_SCRIPTS = [
# Scripts that are run by the travis build process.
# Longest test should go first, to favor running tests in parallel
+ 'feature_fee_estimation.py',
'wallet_hd.py',
'wallet_backup.py',
# vv Tests less than 5m vv
+ 'mining_getblocktemplate_longpoll.py',
+ 'feature_maxuploadtarget.py',
'feature_block.py',
'rpc_fundrawtransaction.py',
'p2p_compactblocks.py',
@@ -69,6 +85,7 @@ BASE_SCRIPTS = [
'wallet_basic.py',
'wallet_labels.py',
'p2p_segwit.py',
+ 'p2p_timeouts.py',
'wallet_dump.py',
'wallet_listtransactions.py',
# vv Tests less than 60s vv
@@ -82,6 +99,8 @@ BASE_SCRIPTS = [
'feature_csv_activation.py',
'rpc_rawtransaction.py',
'wallet_address_types.py',
+ 'feature_bip68_sequence.py',
+ 'p2p_feefilter.py',
'feature_reindex.py',
# vv Tests less than 30s vv
'wallet_keypool_topup.py',
@@ -101,6 +120,7 @@ BASE_SCRIPTS = [
'wallet_disableprivatekeys.py',
'wallet_disableprivatekeys.py --usecli',
'interface_http.py',
+ 'interface_rpc.py',
'rpc_psbt.py',
'rpc_users.py',
'feature_proxy.py',
@@ -117,16 +137,27 @@ BASE_SCRIPTS = [
'mining_prioritisetransaction.py',
'p2p_invalid_locator.py',
'p2p_invalid_block.py',
+ 'p2p_invalid_messages.py',
'p2p_invalid_tx.py',
+ 'feature_assumevalid.py',
+ 'example_test.py',
+ 'wallet_txn_doublespend.py',
+ 'wallet_txn_clone.py --mineblock',
+ 'feature_notifications.py',
+ 'rpc_invalidateblock.py',
+ 'feature_rbf.py',
+ 'mempool_packages.py',
'rpc_createmultisig.py',
'feature_versionbits_warning.py',
'rpc_preciousblock.py',
'wallet_importprunedfunds.py',
- 'rpc_zmq.py',
+ 'p2p_leak_tx.py',
'rpc_signmessage.py',
+ 'wallet_balance.py',
'feature_nulldummy.py',
'mempool_accept.py',
'wallet_import_rescan.py',
+ 'wallet_import_with_label.py',
'rpc_bind.py --ipv4',
'rpc_bind.py --ipv6',
'rpc_bind.py --nonloopback',
@@ -145,6 +176,7 @@ BASE_SCRIPTS = [
'rpc_getblockstats.py',
'p2p_fingerprint.py',
'feature_uacomment.py',
+ 'feature_filelock.py',
'p2p_unrequested_blocks.py',
'feature_includeconf.py',
'rpc_scantxoutset.py',
@@ -152,6 +184,7 @@ BASE_SCRIPTS = [
'p2p_node_network_limited.py',
'feature_blocksdir.py',
'feature_config_args.py',
+ 'rpc_help.py',
'feature_help.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
@@ -161,26 +194,7 @@ EXTENDED_SCRIPTS = [
# These tests are not run by the travis build process.
# Longest test should go first, to favor running tests in parallel
'feature_pruning.py',
- # vv Tests less than 20m vv
- 'feature_fee_estimation.py',
- # vv Tests less than 5m vv
- 'feature_maxuploadtarget.py',
- 'mempool_packages.py',
'feature_dbcrash.py',
- # vv Tests less than 2m vv
- 'feature_bip68_sequence.py',
- 'mining_getblocktemplate_longpoll.py',
- 'p2p_timeouts.py',
- # vv Tests less than 60s vv
- 'p2p_feefilter.py',
- # vv Tests less than 30s vv
- 'feature_assumevalid.py',
- 'example_test.py',
- 'wallet_txn_doublespend.py',
- 'wallet_txn_clone.py --mineblock',
- 'feature_notifications.py',
- 'rpc_invalidateblock.py',
- 'feature_rbf.py',
]
# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests
@@ -201,15 +215,16 @@ def main():
epilog='''
Help text and arguments for individual test script:''',
formatter_class=argparse.RawTextHelpFormatter)
- parser.add_argument('--combinedlogslen', '-c', type=int, default=0, help='print a combined log (of length n lines) from all test nodes and test framework to the console on failure.')
+ parser.add_argument('--combinedlogslen', '-c', type=int, default=0, metavar='n', help='On failure, print a log (of length n lines) to the console, combined from the test framework and all test nodes.')
parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')
+ parser.add_argument('--ci', action='store_true', help='Run checks and code that are usually only enabled in a continuous integration environment')
parser.add_argument('--exclude', '-x', help='specify a comma-separated-list of scripts to exclude.')
parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests')
parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).')
parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')
parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')
parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.')
- parser.add_argument('--quiet', '-q', action='store_true', help='only print results summary and failure logs')
+ parser.add_argument('--quiet', '-q', action='store_true', help='only print dots, results summary and failure logs')
parser.add_argument('--tmpdirprefix', '-t', default=tempfile.gettempdir(), help="Root directory for datadirs")
parser.add_argument('--failfast', action='store_true', help='stop execution after the first test failure')
args, unknown_args = parser.parse_known_args()
@@ -231,12 +246,15 @@ def main():
# Create base test directory
tmpdir = "%s/test_runner_₿_🏃_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
+
+ # If we fixed the command-line and filename encoding issue on Windows, these two lines could be removed
+ if config["environment"]["EXEEXT"] == ".exe":
+ tmpdir = "%s/test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
+
os.makedirs(tmpdir)
logging.debug("Temporary test directory at %s" % tmpdir)
- enable_wallet = config["components"].getboolean("ENABLE_WALLET")
- enable_utils = config["components"].getboolean("ENABLE_UTILS")
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
if config["environment"]["EXEEXT"] == ".exe" and not args.force:
@@ -245,9 +263,9 @@ def main():
print("Tests currently disabled on Windows by default. Use --force option to enable")
sys.exit(0)
- if not (enable_wallet and enable_utils and enable_bitcoind):
- print("No functional tests to run. Wallet, utils, and bitcoind must all be enabled")
- print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make")
+ if not enable_bitcoind:
+ print("No functional tests to run.")
+ print("Rerun ./configure with --with-daemon and then make")
sys.exit(0)
# Build list of tests
@@ -270,11 +288,13 @@ def main():
# Remove the test cases that the user has explicitly asked to exclude.
if args.exclude:
- exclude_tests = [re.sub("\.py$", "", test) + ".py" for test in args.exclude.split(',')]
+ exclude_tests = [test.split('.py')[0] for test in args.exclude.split(',')]
for exclude_test in exclude_tests:
- if exclude_test in test_list:
- test_list.remove(exclude_test)
- else:
+ # Remove <test_name>.py and <test_name>.py --arg from the test list
+ exclude_list = [test for test in test_list if test.split('.py')[0] == exclude_test]
+ for exclude_item in exclude_list:
+ test_list.remove(exclude_item)
+ if not exclude_list:
print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], exclude_test))
if not test_list:
@@ -288,25 +308,26 @@ def main():
subprocess.check_call([sys.executable, os.path.join(config["environment"]["SRCDIR"], 'test', 'functional', test_list[0].split()[0]), '-h'])
sys.exit(0)
- check_script_list(config["environment"]["SRCDIR"])
+ check_script_list(src_dir=config["environment"]["SRCDIR"], fail_on_warn=args.ci)
check_script_prefixes()
if not args.keepcache:
shutil.rmtree("%s/test/cache" % config["environment"]["BUILDDIR"], ignore_errors=True)
run_tests(
- test_list,
- config["environment"]["SRCDIR"],
- config["environment"]["BUILDDIR"],
- tmpdir,
+ test_list=test_list,
+ src_dir=config["environment"]["SRCDIR"],
+ build_dir=config["environment"]["BUILDDIR"],
+ tmpdir=tmpdir,
jobs=args.jobs,
enable_coverage=args.coverage,
args=passon_args,
combined_logs_len=args.combinedlogslen,
failfast=args.failfast,
+ runs_ci=args.ci,
)
-def run_tests(test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False):
+def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, runs_ci):
args = args or []
# Warn if bitcoind is already running (unix only)
@@ -341,22 +362,29 @@ def run_tests(test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=Fal
raise
#Run Tests
- job_queue = TestHandler(jobs, tests_dir, tmpdir, test_list, flags)
+ job_queue = TestHandler(
+ num_tests_parallel=jobs,
+ tests_dir=tests_dir,
+ tmpdir=tmpdir,
+ test_list=test_list,
+ flags=flags,
+ timeout_duration=40 * 60 if runs_ci else float('inf'), # in seconds
+ )
start_time = time.time()
test_results = []
max_len_name = len(max(test_list, key=len))
-
- for _ in range(len(test_list)):
+ test_count = len(test_list)
+ for i in range(test_count):
test_result, testdir, stdout, stderr = job_queue.get_next()
test_results.append(test_result)
-
+ done_str = "{}/{} - {}{}{}".format(i + 1, test_count, BOLD[1], test_result.name, BOLD[0])
if test_result.status == "Passed":
- logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], test_result.name, BOLD[0], test_result.time))
+ logging.debug("%s passed, Duration: %s s" % (done_str, test_result.time))
elif test_result.status == "Skipped":
- logging.debug("\n%s%s%s skipped" % (BOLD[1], test_result.name, BOLD[0]))
+ logging.debug("%s skipped" % (done_str))
else:
- print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], test_result.name, BOLD[0], test_result.time))
+ print("%s failed, Duration: %s s\n" % (done_str, test_result.time))
print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
if combined_logs_len and os.path.isdir(testdir):
@@ -365,7 +393,10 @@ def run_tests(test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=Fal
print('\n============')
print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0]))
print('============\n')
- combined_logs, _ = subprocess.Popen([sys.executable, os.path.join(tests_dir, 'combine_logs.py'), '-c', testdir], universal_newlines=True, stdout=subprocess.PIPE).communicate()
+ combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]
+ if BOLD[0]:
+ combined_logs_args += ['--color']
+ combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()
print("\n".join(deque(combined_logs.splitlines(), combined_logs_len)))
if failfast:
@@ -419,11 +450,12 @@ class TestHandler:
Trigger the test scripts passed in via the list.
"""
- def __init__(self, num_tests_parallel, tests_dir, tmpdir, test_list=None, flags=None):
- assert(num_tests_parallel >= 1)
+ def __init__(self, *, num_tests_parallel, tests_dir, tmpdir, test_list, flags, timeout_duration):
+ assert num_tests_parallel >= 1
self.num_jobs = num_tests_parallel
self.tests_dir = tests_dir
self.tmpdir = tmpdir
+ self.timeout_duration = timeout_duration
self.test_list = test_list
self.flags = flags
self.num_running = 0
@@ -452,12 +484,13 @@ class TestHandler:
log_stderr))
if not self.jobs:
raise IndexError('pop from empty list')
+ dot_count = 0
while True:
# Return first proc that finishes
time.sleep(.5)
for job in self.jobs:
(name, start_time, proc, testdir, log_out, log_err) = job
- if os.getenv('TRAVIS') == 'true' and int(time.time() - start_time) > TRAVIS_TIMEOUT_DURATION:
+ if int(time.time() - start_time) > self.timeout_duration:
# In travis, timeout individual tests (to stop tests hanging and not providing useful output).
proc.send_signal(signal.SIGINT)
if proc.poll() is not None:
@@ -472,9 +505,12 @@ class TestHandler:
status = "Failed"
self.num_running -= 1
self.jobs.remove(job)
-
+ clearline = '\r' + (' ' * dot_count) + '\r'
+ print(clearline, end='', flush=True)
+ dot_count = 0
return TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr
print('.', end='', flush=True)
+ dot_count += 1
def kill_and_join(self):
"""Send SIGKILL to all jobs and block until all have ended."""
@@ -504,7 +540,7 @@ class TestResult():
def __repr__(self):
if self.status == "Passed":
- color = BLUE
+ color = GREEN
glyph = TICK
elif self.status == "Failed":
color = RED
@@ -532,7 +568,7 @@ def check_script_prefixes():
raise AssertionError("Some tests are not following naming convention!")
-def check_script_list(src_dir):
+def check_script_list(*, src_dir, fail_on_warn):
"""Check scripts directory.
Check that there are no scripts in the functional tests directory which are
@@ -542,10 +578,11 @@ def check_script_list(src_dir):
missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS)))
if len(missed_tests) != 0:
print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % (BOLD[1], BOLD[0], str(missed_tests)))
- if os.getenv('TRAVIS') == 'true':
+ if fail_on_warn:
# On travis this warning is an error to prevent merging incomplete commits into master
sys.exit(1)
+
class RPCCoverage():
"""
Coverage reporting utilities for test_runner.
@@ -601,7 +638,7 @@ class RPCCoverage():
with open(coverage_ref_filename, 'r', encoding="utf8") as coverage_ref_file:
all_cmds.update([line.strip() for line in coverage_ref_file.readlines()])
- for root, dirs, files in os.walk(self.dir):
+ for root, _, files in os.walk(self.dir):
for filename in files:
if filename.startswith(coverage_file_prefix):
coverage_filenames.add(os.path.join(root, filename))
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index 8a57b55ca9..e5ac2c8bd4 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -20,6 +20,9 @@ class AbandonConflictTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [["-minrelaytxfee=0.00001"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[1].generate(100)
sync_blocks(self.nodes)
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index 30851893b8..bafa556aad 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -63,6 +63,7 @@ from test_framework.util import (
sync_mempools,
)
+
class AddressTypeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 6
@@ -72,9 +73,12 @@ class AddressTypeTest(BitcoinTestFramework):
["-addresstype=p2sh-segwit", "-changetype=bech32"],
["-addresstype=bech32"],
["-changetype=p2sh-segwit"],
- []
+ [],
]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
@@ -95,6 +99,8 @@ class AddressTypeTest(BitcoinTestFramework):
"""Run sanity checks on an address."""
info = self.nodes[node].getaddressinfo(address)
assert(self.nodes[node].validateaddress(address)['isvalid'])
+ assert_equal(info.get('solvable'), True)
+
if not multisig and typ == 'legacy':
# P2PKH
assert(not info['isscript'])
@@ -142,6 +148,47 @@ class AddressTypeTest(BitcoinTestFramework):
# Unknown type
assert(False)
+ def test_desc(self, node, address, multisig, typ, utxo):
+ """Run sanity checks on a descriptor reported by getaddressinfo."""
+ info = self.nodes[node].getaddressinfo(address)
+ assert('desc' in info)
+ assert_equal(info['desc'], utxo['desc'])
+ assert(self.nodes[node].validateaddress(address)['isvalid'])
+
+ # Use a ridiculously roundabout way to find the key origin info through
+ # the PSBT logic. However, this does test consistency between the PSBT reported
+ # fingerprints/paths and the descriptor logic.
+ psbt = self.nodes[node].createpsbt([{'txid':utxo['txid'], 'vout':utxo['vout']}],[{address:0.00010000}])
+ psbt = self.nodes[node].walletprocesspsbt(psbt, False, "ALL", True)
+ decode = self.nodes[node].decodepsbt(psbt['psbt'])
+ key_descs = {}
+ for deriv in decode['inputs'][0]['bip32_derivs']:
+ assert_equal(len(deriv['master_fingerprint']), 8)
+ assert_equal(deriv['path'][0], 'm')
+ key_descs[deriv['pubkey']] = '[' + deriv['master_fingerprint'] + deriv['path'][1:] + ']' + deriv['pubkey']
+
+ if not multisig and typ == 'legacy':
+ # P2PKH
+ assert_equal(info['desc'], "pkh(%s)" % key_descs[info['pubkey']])
+ elif not multisig and typ == 'p2sh-segwit':
+ # P2SH-P2WPKH
+ assert_equal(info['desc'], "sh(wpkh(%s))" % key_descs[info['pubkey']])
+ elif not multisig and typ == 'bech32':
+ # P2WPKH
+ assert_equal(info['desc'], "wpkh(%s)" % key_descs[info['pubkey']])
+ elif typ == 'legacy':
+ # P2SH-multisig
+ assert_equal(info['desc'], "sh(multi(2,%s,%s))" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]]))
+ elif typ == 'p2sh-segwit':
+ # P2SH-P2WSH-multisig
+ assert_equal(info['desc'], "sh(wsh(multi(2,%s,%s)))" % (key_descs[info['embedded']['pubkeys'][0]], key_descs[info['embedded']['pubkeys'][1]]))
+ elif typ == 'bech32':
+ # P2WSH-multisig
+ assert_equal(info['desc'], "wsh(multi(2,%s,%s))" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]]))
+ else:
+ # Unknown type
+ assert(False)
+
def test_change_output_type(self, node_sender, destinations, expected_type):
txid = self.nodes[node_sender].sendmany(dummy="", amounts=dict.fromkeys(destinations, 0.001))
raw_tx = self.nodes[node_sender].getrawtransaction(txid)
@@ -194,6 +241,7 @@ class AddressTypeTest(BitcoinTestFramework):
self.log.debug("Old balances are {}".format(old_balances))
to_send = (old_balances[from_node] / 101).quantize(Decimal("0.00000001"))
sends = {}
+ addresses = {}
self.log.debug("Prepare sends")
for n, to_node in enumerate(range(from_node, from_node + 4)):
@@ -224,6 +272,7 @@ class AddressTypeTest(BitcoinTestFramework):
# Output entry
sends[address] = to_send * 10 * (1 + n)
+ addresses[to_node] = (address, typ)
self.log.debug("Sending: {}".format(sends))
self.nodes[from_node].sendmany("", sends)
@@ -240,6 +289,17 @@ class AddressTypeTest(BitcoinTestFramework):
self.nodes[5].generate(1)
sync_blocks(self.nodes)
+ # Verify that the receiving wallet contains a UTXO with the expected address, and expected descriptor
+ for n, to_node in enumerate(range(from_node, from_node + 4)):
+ to_node %= 4
+ found = False
+ for utxo in self.nodes[to_node].listunspent():
+ if utxo['address'] == addresses[to_node][0]:
+ found = True
+ self.test_desc(to_node, addresses[to_node][0], multisig, addresses[to_node][1], utxo)
+ break
+ assert found
+
new_balances = self.get_balances()
self.log.debug("Check new balances: {}".format(new_balances))
# We don't know what fee was set, so we can only check bounds on the balance of the sending node
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index 4ef8f4776b..32ec385fa1 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -45,6 +45,9 @@ class WalletBackupTest(BitcoinTestFramework):
# nodes 1, 2,3 are spenders, let's give them a keypool=100
self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self, split=False):
self.setup_nodes()
connect_nodes(self.nodes[0], 3)
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
new file mode 100755
index 0000000000..05c97e0340
--- /dev/null
+++ b/test/functional/wallet_balance.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 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 the wallet balance RPC methods."""
+from decimal import Decimal
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+RANDOM_COINBASE_ADDRESS = 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ'
+
+def create_transactions(node, address, amt, fees):
+ # Create and sign raw transactions from node to address for amt.
+ # Creates a transaction for each fee and returns an array
+ # of the raw transactions.
+ utxos = node.listunspent(0)
+
+ # Create transactions
+ inputs = []
+ ins_total = 0
+ for utxo in utxos:
+ inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
+ ins_total += utxo['amount']
+ if ins_total > amt:
+ break
+
+ txs = []
+ for fee in fees:
+ outputs = {address: amt, node.getrawchangeaddress(): ins_total - amt - fee}
+ raw_tx = node.createrawtransaction(inputs, outputs, 0, True)
+ raw_tx = node.signrawtransactionwithwallet(raw_tx)
+ txs.append(raw_tx)
+
+ return txs
+
+class WalletTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ # Check that nodes don't own any UTXOs
+ assert_equal(len(self.nodes[0].listunspent()), 0)
+ assert_equal(len(self.nodes[1].listunspent()), 0)
+
+ self.log.info("Mining one block for each node")
+
+ self.nodes[0].generate(1)
+ self.sync_all()
+ self.nodes[1].generate(1)
+ self.nodes[1].generatetoaddress(100, RANDOM_COINBASE_ADDRESS)
+ self.sync_all()
+
+ assert_equal(self.nodes[0].getbalance(), 50)
+ assert_equal(self.nodes[1].getbalance(), 50)
+
+ self.log.info("Test getbalance with different arguments")
+ assert_equal(self.nodes[0].getbalance("*"), 50)
+ assert_equal(self.nodes[0].getbalance("*", 1), 50)
+ assert_equal(self.nodes[0].getbalance("*", 1, True), 50)
+ assert_equal(self.nodes[0].getbalance(minconf=1), 50)
+
+ # Send 40 BTC from 0 to 1 and 60 BTC from 1 to 0.
+ txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 40, [Decimal('0.01')])
+ self.nodes[0].sendrawtransaction(txs[0]['hex'])
+ self.nodes[1].sendrawtransaction(txs[0]['hex']) # sending on both nodes is faster than waiting for propagation
+
+ self.sync_all()
+ txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), 60, [Decimal('0.01'), Decimal('0.02')])
+ self.nodes[1].sendrawtransaction(txs[0]['hex'])
+ self.nodes[0].sendrawtransaction(txs[0]['hex']) # sending on both nodes is faster than waiting for propagation
+ self.sync_all()
+
+ # First argument of getbalance must be set to "*"
+ assert_raises_rpc_error(-32, "dummy first argument must be excluded or set to \"*\"", self.nodes[1].getbalance, "")
+
+ self.log.info("Test getbalance and getunconfirmedbalance with unconfirmed inputs")
+
+ # getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions
+ assert_equal(self.nodes[0].getbalance(), Decimal('9.99')) # change from node 0's send
+ assert_equal(self.nodes[1].getbalance(), Decimal('29.99')) # change from node 1's send
+ # Same with minconf=0
+ assert_equal(self.nodes[0].getbalance(minconf=0), Decimal('9.99'))
+ assert_equal(self.nodes[1].getbalance(minconf=0), Decimal('29.99'))
+ # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
+ # TODO: fix getbalance tracking of coin spentness depth
+ assert_equal(self.nodes[0].getbalance(minconf=1), Decimal('0'))
+ assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
+ # getunconfirmedbalance
+ assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60')) # output of node 1's spend
+ assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
+
+ # Node 1 bumps the transaction fee and resends
+ self.nodes[1].sendrawtransaction(txs[1]['hex'])
+ self.sync_all()
+
+ self.log.info("Test getbalance and getunconfirmedbalance with conflicted unconfirmed inputs")
+
+ assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('60')) # output of node 1's send
+ assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60'))
+ assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0')) # Doesn't include output of node 0's send since it was spent
+ assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0'))
+
+ self.nodes[1].generatetoaddress(1, RANDOM_COINBASE_ADDRESS)
+ self.sync_all()
+
+ # balances are correct after the transactions are confirmed
+ assert_equal(self.nodes[0].getbalance(), Decimal('69.99')) # node 1's send plus change from node 0's send
+ assert_equal(self.nodes[1].getbalance(), Decimal('29.98')) # change from node 0's send
+
+ # Send total balance away from node 1
+ txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), Decimal('29.97'), [Decimal('0.01')])
+ self.nodes[1].sendrawtransaction(txs[0]['hex'])
+ self.nodes[1].generatetoaddress(2, RANDOM_COINBASE_ADDRESS)
+ self.sync_all()
+
+ # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
+ # TODO: fix getbalance tracking of coin spentness depth
+ # getbalance with minconf=3 should still show the old balance
+ assert_equal(self.nodes[1].getbalance(minconf=3), Decimal('0'))
+
+ # getbalance with minconf=2 will show the new balance.
+ assert_equal(self.nodes[1].getbalance(minconf=2), Decimal('0'))
+
+if __name__ == '__main__':
+ WalletTest().main()
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index ea0346543a..7184bb8cb6 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -11,6 +11,7 @@ from test_framework.util import (
assert_array_result,
assert_equal,
assert_fee_amount,
+ assert_greater_than,
assert_raises_rpc_error,
connect_nodes_bi,
sync_blocks,
@@ -23,11 +24,13 @@ class WalletTest(BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
- self.add_nodes(4)
- self.start_node(0)
- self.start_node(1)
- self.start_node(2)
+ self.setup_nodes()
+ # Only need nodes 0-2 running at start of test
+ self.stop_node(3)
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes_bi(self.nodes, 1, 2)
connect_nodes_bi(self.nodes, 0, 2)
@@ -64,15 +67,6 @@ class WalletTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(), 50)
assert_equal(self.nodes[2].getbalance(), 0)
- # Check getbalance with different arguments
- assert_equal(self.nodes[0].getbalance("*"), 50)
- assert_equal(self.nodes[0].getbalance("*", 1), 50)
- assert_equal(self.nodes[0].getbalance("*", 1, True), 50)
- assert_equal(self.nodes[0].getbalance(minconf=1), 50)
-
- # first argument of getbalance must be excluded or set to "*"
- assert_raises_rpc_error(-32, "dummy first argument must be excluded or set to \"*\"", self.nodes[0].getbalance, "")
-
# Check that only first and second nodes have UTXOs
utxos = self.nodes[0].listunspent()
assert_equal(len(utxos), 1)
@@ -89,13 +83,13 @@ class WalletTest(BitcoinTestFramework):
assert_equal(txout['value'], 50)
# Send 21 BTC from 0 to 2 using sendtoaddress call.
- # Locked memory should use at least 32 bytes to sign each transaction
+ # Locked memory should increase to sign transactions
self.log.info("test getmemoryinfo")
memory_before = self.nodes[0].getmemoryinfo()
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)
mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)
memory_after = self.nodes[0].getmemoryinfo()
- assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used'])
+ assert_greater_than(memory_after['locked']['used'], memory_before['locked']['used'])
self.log.info("test gettxout (second part)")
# utxo spent in mempool should be visible if you exclude mempool
@@ -131,9 +125,15 @@ class WalletTest(BitcoinTestFramework):
assert_equal([unspent_0], self.nodes[2].listlockunspent())
self.nodes[2].lockunspent(True, [unspent_0])
assert_equal(len(self.nodes[2].listlockunspent()), 0)
- assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction",
+ assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')",
self.nodes[2].lockunspent, False,
[{"txid": "0000000000000000000000000000000000", "vout": 0}])
+ assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')",
+ self.nodes[2].lockunspent, False,
+ [{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}])
+ assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction",
+ self.nodes[2].lockunspent, False,
+ [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}])
assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds",
self.nodes[2].lockunspent, False,
[{"txid": unspent_0["txid"], "vout": 999}])
@@ -239,10 +239,6 @@ class WalletTest(BitcoinTestFramework):
assert(txid1 in self.nodes[3].getrawmempool())
- # Exercise balance rpcs
- assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], 1)
- assert_equal(self.nodes[0].getunconfirmedbalance(), 1)
-
# check if we can list zero value tx as available coins
# 1. create raw_tx
# 2. hex-changed one output to 0.0
@@ -470,7 +466,7 @@ class WalletTest(BitcoinTestFramework):
# Verify nothing new in wallet
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
- # Test getaddressinfo. Note that these addresses are taken from disablewallet.py
+ # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
@@ -478,6 +474,22 @@ class WalletTest(BitcoinTestFramework):
assert not address_info["ismine"]
assert not address_info["iswatchonly"]
assert not address_info["isscript"]
+ assert not address_info["ischange"]
+
+ # Test getaddressinfo 'ischange' field on change address.
+ self.nodes[0].generate(1)
+ destination = self.nodes[1].getnewaddress()
+ txid = self.nodes[0].sendtoaddress(destination, 0.123)
+ tx = self.nodes[0].decoderawtransaction(self.nodes[0].getrawtransaction(txid))
+ output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]]
+ assert len(output_addresses) > 1
+ for address in output_addresses:
+ ischange = self.nodes[0].getaddressinfo(address)['ischange']
+ assert_equal(ischange, address != destination)
+ if ischange:
+ change = address
+ self.nodes[0].setlabel(change, 'foobar')
+ assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
if __name__ == '__main__':
WalletTest().main()
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index a49590df19..7d3d9b61e2 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -13,31 +13,32 @@ can be disabled or reordered if needed for debugging. If new test cases are
added in the future, they should try to follow the same convention and not
make assumptions about execution order.
"""
-
from decimal import Decimal
+import io
from test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness
from test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes_bi, hex_str_to_bytes, sync_mempools
-import io
-
WALLET_PASSPHRASE = "test"
WALLET_PASSPHRASE_TIMEOUT = 3600
-
class BumpFeeTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
- self.extra_args = [["-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i), "-mintxfee=0.00002"]
- for i in range(self.num_nodes)]
+ self.extra_args = [[
+ "-walletrbf={}".format(i),
+ "-mintxfee=0.00002",
+ ] for i in range(self.num_nodes)]
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
def run_test(self):
# Encrypt wallet for test_locked_wallet_fails test
- self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE)
- self.start_node(1)
+ self.nodes[1].encryptwallet(WALLET_PASSPHRASE)
self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
connect_nodes_bi(self.nodes, 0, 1)
@@ -102,8 +103,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
# which spends it, and make sure bumpfee can be called on it.
segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001"))
- segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress())
- rbf_node.addwitnessaddress(segwit_out["address"])
+ segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress(address_type='p2sh-segwit'))
segwitid = send_to_witness(
use_p2wsh=False,
node=rbf_node,
@@ -152,7 +152,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
signedtx = peer_node.signrawtransactionwithwallet(signedtx["hex"])
rbfid = rbf_node.sendrawtransaction(signedtx["hex"])
assert_raises_rpc_error(-4, "Transaction contains inputs that don't belong to this wallet",
- rbf_node.bumpfee, rbfid)
+ rbf_node.bumpfee, rbfid)
def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address):
@@ -182,11 +182,11 @@ def test_dust_to_fee(rbf_node, dest_address):
# (32-byte p2sh-pwpkh output size + 148 p2pkh spend estimate) * 10k(discard_rate) / 1000 = 1800
# P2SH outputs are slightly "over-discarding" due to the IsDust calculation assuming it will
# be spent as a P2PKH.
- bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 50000-1800})
+ bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 50000 - 1800})
full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1)
assert_equal(bumped_tx["fee"], Decimal("0.00050000"))
assert_equal(len(fulltx["vout"]), 2)
- assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated
+ assert_equal(len(full_bumped_tx["vout"]), 1) # change output is eliminated
def test_settxfee(rbf_node, dest_address):
@@ -217,7 +217,7 @@ def test_rebumping_not_replaceable(rbf_node, dest_address):
rbfid = spend_one_input(rbf_node, dest_address)
bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
- {"totalFee": 20000})
+ {"totalFee": 20000})
def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
@@ -271,7 +271,7 @@ def test_locked_wallet_fails(rbf_node, dest_address):
rbfid = spend_one_input(rbf_node, dest_address)
rbf_node.walletlock()
assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.",
- rbf_node.bumpfee, rbfid)
+ rbf_node.bumpfee, rbfid)
def spend_one_input(node, dest_address):
diff --git a/test/functional/wallet_disableprivatekeys.py b/test/functional/wallet_disableprivatekeys.py
index 0ba2cfe9be..34ff525255 100755
--- a/test/functional/wallet_disableprivatekeys.py
+++ b/test/functional/wallet_disableprivatekeys.py
@@ -17,6 +17,9 @@ class DisablePrivateKeysTest(BitcoinTestFramework):
self.num_nodes = 1
self.supports_cli = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
node = self.nodes[0]
self.log.info("Test disableprivatekeys creation.")
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index 63316d9644..20cb816ee8 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -3,7 +3,6 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the dumpwallet RPC."""
-
import os
from test_framework.test_framework import BitcoinTestFramework
@@ -19,70 +18,82 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old):
Also check that the old hd_master is inactive
"""
with open(file_name, encoding='utf8') as inputfile:
- found_addr = 0
+ found_legacy_addr = 0
+ found_p2sh_segwit_addr = 0
+ found_bech32_addr = 0
found_script_addr = 0
found_addr_chg = 0
found_addr_rsv = 0
- witness_addr_ret = None
hd_master_addr_ret = None
for line in inputfile:
# only read non comment lines
if line[0] != "#" and len(line) > 10:
# split out some data
- key_label, comment = line.split("#")
- # key = key_label.split(" ")[0]
- keytype = key_label.split(" ")[2]
- if len(comment) > 1:
- addr_keypath = comment.split(" addr=")[1]
- addr = addr_keypath.split(" ")[0]
+ key_date_label, comment = line.split("#")
+ key_date_label = key_date_label.split(" ")
+ # key = key_date_label[0]
+ date = key_date_label[1]
+ keytype = key_date_label[2]
+
+ imported_key = date == '1970-01-01T00:00:01Z'
+ if imported_key:
+ # Imported keys have multiple addresses, no label (keypath) and timestamp
+ # Skip them
+ continue
+
+ addr_keypath = comment.split(" addr=")[1]
+ addr = addr_keypath.split(" ")[0]
+ keypath = None
+ if keytype == "inactivehdseed=1":
+ # ensure the old master is still available
+ assert (hd_master_addr_old == addr)
+ elif keytype == "hdseed=1":
+ # ensure we have generated a new hd master key
+ assert (hd_master_addr_old != addr)
+ hd_master_addr_ret = addr
+ elif keytype == "script=1":
+ # scripts don't have keypaths
keypath = None
- if keytype == "inactivehdseed=1":
- # ensure the old master is still available
- assert(hd_master_addr_old == addr)
- elif keytype == "hdseed=1":
- # ensure we have generated a new hd master key
- assert(hd_master_addr_old != addr)
- hd_master_addr_ret = addr
- elif keytype == "script=1":
- # scripts don't have keypaths
- keypath = None
- else:
- keypath = addr_keypath.rstrip().split("hdkeypath=")[1]
-
- # count key types
- for addrObj in addrs:
- if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=":
- # a labeled entry in the wallet should contain both a native address
- # and the p2sh-p2wpkh address that was added at wallet setup
- if len(addr.split(",")) == 2:
- addr_list = addr.split(",")
- # the entry should be of the first key in the wallet
- assert_equal(addrs[0]['address'], addr_list[0])
- witness_addr_ret = addr_list[1]
- found_addr += 1
- break
- elif keytype == "change=1":
- found_addr_chg += 1
- break
- elif keytype == "reserve=1":
- found_addr_rsv += 1
- break
-
- # count scripts
- for script_addr in script_addrs:
- if script_addr == addr.rstrip() and keytype == "script=1":
- found_script_addr += 1
- break
-
- return found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret, witness_addr_ret
+ else:
+ keypath = addr_keypath.rstrip().split("hdkeypath=")[1]
+
+ # count key types
+ for addrObj in addrs:
+ if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=":
+ if addr.startswith('m') or addr.startswith('n'):
+ # P2PKH address
+ found_legacy_addr += 1
+ elif addr.startswith('2'):
+ # P2SH-segwit address
+ found_p2sh_segwit_addr += 1
+ elif addr.startswith('bcrt1'):
+ found_bech32_addr += 1
+ break
+ elif keytype == "change=1":
+ found_addr_chg += 1
+ break
+ elif keytype == "reserve=1":
+ found_addr_rsv += 1
+ break
+
+ # count scripts
+ for script_addr in script_addrs:
+ if script_addr == addr.rstrip() and keytype == "script=1":
+ found_script_addr += 1
+ break
+
+ return found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret
class WalletDumpTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [["-keypool=90", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]]
+ self.extra_args = [["-keypool=90", "-addresstype=legacy"]]
self.rpc_timeout = 120
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self, split=False):
self.add_nodes(self.num_nodes, extra_args=self.extra_args)
self.start_nodes()
@@ -91,50 +102,54 @@ class WalletDumpTest(BitcoinTestFramework):
wallet_unenc_dump = os.path.join(self.nodes[0].datadir, "wallet.unencrypted.dump")
wallet_enc_dump = os.path.join(self.nodes[0].datadir, "wallet.encrypted.dump")
- # generate 20 addresses to compare against the dump
- # but since we add a p2sh-p2wpkh address for the first pubkey in the
- # wallet, we will expect 21 addresses in the dump
- test_addr_count = 20
+ # generate 30 addresses to compare against the dump
+ # - 10 legacy P2PKH
+ # - 10 P2SH-segwit
+ # - 10 bech32
+ test_addr_count = 10
addrs = []
- for i in range(0,test_addr_count):
- addr = self.nodes[0].getnewaddress()
- vaddr= self.nodes[0].getaddressinfo(addr) #required to get hd keypath
- addrs.append(vaddr)
- # Should be a no-op:
- self.nodes[0].keypoolrefill()
+ for address_type in ['legacy', 'p2sh-segwit', 'bech32']:
+ for i in range(0, test_addr_count):
+ addr = self.nodes[0].getnewaddress(address_type=address_type)
+ vaddr = self.nodes[0].getaddressinfo(addr) # required to get hd keypath
+ addrs.append(vaddr)
- # Test scripts dump by adding a P2SH witness and a 1-of-1 multisig address
- witness_addr = self.nodes[0].addwitnessaddress(addrs[0]["address"], True)
+ # Test scripts dump by adding a 1-of-1 multisig address
multisig_addr = self.nodes[0].addmultisigaddress(1, [addrs[1]["address"]])["address"]
- script_addrs = [witness_addr, multisig_addr]
+
+ # Refill the keypool. getnewaddress() refills the keypool *before* taking a key from
+ # the keypool, so the final call to getnewaddress leaves the keypool with one key below
+ # its capacity
+ self.nodes[0].keypoolrefill()
# dump unencrypted wallet
result = self.nodes[0].dumpwallet(wallet_unenc_dump)
assert_equal(result['filename'], wallet_unenc_dump)
- found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc, witness_addr_ret = \
- read_dump(wallet_unenc_dump, addrs, script_addrs, None)
- assert_equal(found_addr, test_addr_count) # all keys must be in the dump
- assert_equal(found_script_addr, 2) # all scripts must be in the dump
- assert_equal(found_addr_chg, 50) # 50 blocks where mined
- assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys
- assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key
-
- #encrypt wallet, restart, unlock and dump
- self.nodes[0].node_encrypt_wallet('test')
- self.start_node(0)
+ found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \
+ read_dump(wallet_unenc_dump, addrs, [multisig_addr], None)
+ 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) # all scripts must be in the dump
+ assert_equal(found_addr_chg, 0) # 0 blocks where mined
+ assert_equal(found_addr_rsv, 90 * 2) # 90 keys plus 100% internal keys
+
+ # encrypt wallet, restart, unlock and dump
+ self.nodes[0].encryptwallet('test')
self.nodes[0].walletpassphrase('test', 10)
# Should be a no-op:
self.nodes[0].keypoolrefill()
self.nodes[0].dumpwallet(wallet_enc_dump)
- found_addr, found_script_addr, found_addr_chg, found_addr_rsv, _, witness_addr_ret = \
- read_dump(wallet_enc_dump, addrs, script_addrs, hd_master_addr_unenc)
- assert_equal(found_addr, test_addr_count)
- assert_equal(found_script_addr, 2)
- assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now
- assert_equal(found_addr_rsv, 90*2)
- assert_equal(witness_addr_ret, witness_addr)
+ 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_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))
@@ -145,13 +160,13 @@ class WalletDumpTest(BitcoinTestFramework):
# Make sure the address is not IsMine before import
result = self.nodes[0].getaddressinfo(multisig_addr)
- assert(result['ismine'] == False)
+ assert not result['ismine']
self.nodes[0].importwallet(wallet_unenc_dump)
# Now check IsMine is true
result = self.nodes[0].getaddressinfo(multisig_addr)
- assert(result['ismine'] == True)
+ assert result['ismine']
if __name__ == '__main__':
WalletDumpTest().main()
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index cec9660259..c514b7e0b4 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -19,6 +19,9 @@ class WalletEncryptionTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
passphrase = "WalletPassphrase"
passphrase2 = "SecondWalletPassphrase"
@@ -28,13 +31,18 @@ class WalletEncryptionTest(BitcoinTestFramework):
privkey = self.nodes[0].dumpprivkey(address)
assert_equal(privkey[:1], "c")
assert_equal(len(privkey), 52)
+ assert_raises_rpc_error(-15, "Error: running with an unencrypted wallet, but walletpassphrase was called", self.nodes[0].walletpassphrase, 'ff', 1)
+ assert_raises_rpc_error(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.", self.nodes[0].walletpassphrasechange, 'ff', 'ff')
# Encrypt the wallet
- self.nodes[0].node_encrypt_wallet(passphrase)
- self.start_node(0)
+ assert_raises_rpc_error(-8, "passphrase can not be empty", self.nodes[0].encryptwallet, '')
+ self.nodes[0].encryptwallet(passphrase)
# Test that the wallet is encrypted
assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address)
+ assert_raises_rpc_error(-15, "Error: running with an encrypted wallet, but encryptwallet was called.", self.nodes[0].encryptwallet, 'ff')
+ assert_raises_rpc_error(-8, "passphrase can not be empty", self.nodes[0].walletpassphrase, '', 1)
+ assert_raises_rpc_error(-8, "passphrase can not be empty", self.nodes[0].walletpassphrasechange, '', 'ff')
# Check that walletpassphrase works
self.nodes[0].walletpassphrase(passphrase, 2)
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index 91dbae8939..0c67982bbe 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -11,6 +11,9 @@ class WalletRBFTest(BitcoinTestFramework):
self.num_nodes = 1
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[0].generate(101)
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index 12dac145bd..9d61483868 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -23,7 +23,10 @@ class WalletGroupTest(BitcoinTestFramework):
self.extra_args = [[], [], ['-avoidpartialspends']]
self.rpc_timewait = 120
- def run_test (self):
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
# Mine some coins
self.nodes[0].generate(110)
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 2a5f1934b7..eb42531693 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -21,13 +21,10 @@ class WalletHDTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [[], ['-keypool=0']]
- def run_test(self):
- # Make sure can't switch off usehd after wallet creation
- self.stop_node(1)
- self.nodes[1].assert_start_raises_init_error(['-usehd=0'], "Error: Error loading : You can't disable HD on an already existing HD wallet")
- self.start_node(1)
- connect_nodes_bi(self.nodes, 0, 1)
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ def run_test(self):
# Make sure we use hd, keep masterkeyid
masterkeyid = self.nodes[1].getwalletinfo()['hdseedid']
assert_equal(masterkeyid, self.nodes[1].getwalletinfo()['hdmasterkeyid'])
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index 0c6359976a..46462a16f3 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -26,7 +26,7 @@ import collections
import enum
import itertools
-Call = enum.Enum("Call", "single multi")
+Call = enum.Enum("Call", "single multiaddress multiscript")
Data = enum.Enum("Data", "address pub priv")
Rescan = enum.Enum("Rescan", "no yes late_timestamp")
@@ -46,33 +46,47 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
if self.call == Call.single:
if self.data == Data.address:
- response = self.try_rpc(self.node.importaddress, address=self.address["address"], rescan=rescan)
+ response = self.try_rpc(self.node.importaddress, address=self.address["address"], label=self.label, rescan=rescan)
elif self.data == Data.pub:
- response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], rescan=rescan)
+ response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], label=self.label, rescan=rescan)
elif self.data == Data.priv:
- response = self.try_rpc(self.node.importprivkey, privkey=self.key, rescan=rescan)
+ response = self.try_rpc(self.node.importprivkey, privkey=self.key, label=self.label, rescan=rescan)
assert_equal(response, None)
- elif self.call == Call.multi:
+ elif self.call in (Call.multiaddress, Call.multiscript):
response = self.node.importmulti([{
"scriptPubKey": {
"address": self.address["address"]
- },
+ } if self.call == Call.multiaddress else self.address["scriptPubKey"],
"timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
"keys": [self.key] if self.data == Data.priv else [],
+ "label": self.label,
"watchonly": self.data != Data.priv
}], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)})
assert_equal(response, [{"success": True}])
def check(self, txid=None, amount=None, confirmations=None):
- """Verify that listreceivedbyaddress returns expected values."""
+ """Verify that listtransactions/listreceivedbyaddress return expected values."""
+
+ txs = self.node.listtransactions(label=self.label, count=10000, include_watchonly=True)
+ assert_equal(len(txs), self.expected_txs)
addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address'])
if self.expected_txs:
assert_equal(len(addresses[0]["txids"]), self.expected_txs)
if txid is not None:
+ tx, = [tx for tx in txs if tx["txid"] == txid]
+ assert_equal(tx["label"], self.label)
+ assert_equal(tx["address"], self.address["address"])
+ assert_equal(tx["amount"], amount)
+ assert_equal(tx["category"], "receive")
+ assert_equal(tx["label"], self.label)
+ assert_equal(tx["txid"], txid)
+ assert_equal(tx["confirmations"], confirmations)
+ assert_equal("trusted" not in tx, True)
+
address, = [ad for ad in addresses if txid in ad["txids"]]
assert_equal(address["address"], self.address["address"])
assert_equal(address["amount"], self.expected_balance)
@@ -109,6 +123,9 @@ class ImportRescanTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2 + len(IMPORT_NODES)
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
extra_args = [["-addresstype=legacy"] for _ in range(self.num_nodes)]
for i, import_node in enumerate(IMPORT_NODES, 2):
@@ -116,6 +133,13 @@ class ImportRescanTest(BitcoinTestFramework):
extra_args[i] += ["-prune=1"]
self.add_nodes(self.num_nodes, extra_args=extra_args)
+
+ # Import keys with pruning disabled
+ self.start_nodes(extra_args=[[]] * self.num_nodes)
+ for n in self.nodes:
+ n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')
+ self.stop_nodes()
+
self.start_nodes()
for i in range(1, self.num_nodes):
connect_nodes(self.nodes[i], 0)
@@ -124,9 +148,10 @@ class ImportRescanTest(BitcoinTestFramework):
# Create one transaction on node 0 with a unique amount for
# each possible type of wallet import RPC.
for i, variant in enumerate(IMPORT_VARIANTS):
- variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())
+ variant.label = "label {} {}".format(i, variant)
+ variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label))
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
- variant.initial_amount = 10 - (i + 1) / 4.0
+ variant.initial_amount = 1 - (i + 1) / 64
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
# Generate a block containing the initial transactions, then another
@@ -156,7 +181,7 @@ class ImportRescanTest(BitcoinTestFramework):
# Create new transactions sending to each address.
for i, variant in enumerate(IMPORT_VARIANTS):
- variant.sent_amount = 10 - (2 * i + 1) / 8.0
+ variant.sent_amount = 1 - (2 * i + 1) / 128
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
# Generate a block containing the new transactions.
diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py
new file mode 100755
index 0000000000..95acaa752e
--- /dev/null
+++ b/test/functional/wallet_import_with_label.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 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 the behavior of RPC importprivkey on set and unset labels of
+addresses.
+
+It tests different cases in which an address is imported with importaddress
+with or without a label and then its private key is imported with importprivkey
+with and without a label.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+class ImportWithLabel(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ """Main test logic"""
+
+ self.log.info(
+ "Test importaddress with label and importprivkey without label."
+ )
+ self.log.info("Import a watch-only address with a label.")
+ address = self.nodes[0].getnewaddress()
+ label = "Test Label"
+ self.nodes[1].importaddress(address, label)
+ address_assert = self.nodes[1].getaddressinfo(address)
+
+ assert_equal(address_assert["iswatchonly"], True)
+ assert_equal(address_assert["ismine"], False)
+ assert_equal(address_assert["label"], label)
+
+ self.log.info(
+ "Import the watch-only address's private key without a "
+ "label and the address should keep its label."
+ )
+ priv_key = self.nodes[0].dumpprivkey(address)
+ self.nodes[1].importprivkey(priv_key)
+
+ assert_equal(label, self.nodes[1].getaddressinfo(address)["label"])
+
+ self.log.info(
+ "Test importaddress without label and importprivkey with label."
+ )
+ self.log.info("Import a watch-only address without a label.")
+ address2 = self.nodes[0].getnewaddress()
+ self.nodes[1].importaddress(address2)
+ address_assert2 = self.nodes[1].getaddressinfo(address2)
+
+ assert_equal(address_assert2["iswatchonly"], True)
+ assert_equal(address_assert2["ismine"], False)
+ assert_equal(address_assert2["label"], "")
+
+ self.log.info(
+ "Import the watch-only address's private key with a "
+ "label and the address should have its label updated."
+ )
+ priv_key2 = self.nodes[0].dumpprivkey(address2)
+ label2 = "Test Label 2"
+ self.nodes[1].importprivkey(priv_key2, label2)
+
+ assert_equal(label2, self.nodes[1].getaddressinfo(address2)["label"])
+
+ self.log.info("Test importaddress with label and importprivkey with label.")
+ self.log.info("Import a watch-only address with a label.")
+ address3 = self.nodes[0].getnewaddress()
+ label3_addr = "Test Label 3 for importaddress"
+ self.nodes[1].importaddress(address3, label3_addr)
+ address_assert3 = self.nodes[1].getaddressinfo(address3)
+
+ assert_equal(address_assert3["iswatchonly"], True)
+ assert_equal(address_assert3["ismine"], False)
+ assert_equal(address_assert3["label"], label3_addr)
+
+ self.log.info(
+ "Import the watch-only address's private key with a "
+ "label and the address should have its label updated."
+ )
+ priv_key3 = self.nodes[0].dumpprivkey(address3)
+ label3_priv = "Test Label 3 for importprivkey"
+ self.nodes[1].importprivkey(priv_key3, label3_priv)
+
+ assert_equal(label3_priv, self.nodes[1].getaddressinfo(address3)["label"])
+
+ self.log.info(
+ "Test importprivkey won't label new dests with the same "
+ "label as others labeled dests for the same key."
+ )
+ self.log.info("Import a watch-only legacy address with a label.")
+ address4 = self.nodes[0].getnewaddress()
+ label4_addr = "Test Label 4 for importaddress"
+ self.nodes[1].importaddress(address4, label4_addr)
+ address_assert4 = self.nodes[1].getaddressinfo(address4)
+
+ assert_equal(address_assert4["iswatchonly"], True)
+ assert_equal(address_assert4["ismine"], False)
+ assert_equal(address_assert4["label"], label4_addr)
+
+ self.log.info("Asserts address has no embedded field with dests.")
+
+ assert_equal(address_assert4.get("embedded"), None)
+
+ self.log.info(
+ "Import the watch-only address's private key without a "
+ "label and new destinations for the key should have an "
+ "empty label while the 'old' destination should keep "
+ "its label."
+ )
+ priv_key4 = self.nodes[0].dumpprivkey(address4)
+ self.nodes[1].importprivkey(priv_key4)
+ address_assert4 = self.nodes[1].getaddressinfo(address4)
+
+ assert address_assert4.get("embedded")
+
+ bcaddress_assert = self.nodes[1].getaddressinfo(
+ address_assert4["embedded"]["address"]
+ )
+
+ assert_equal(address_assert4["label"], label4_addr)
+ assert_equal(bcaddress_assert["label"], "")
+
+ self.stop_nodes()
+
+
+if __name__ == "__main__":
+ ImportWithLabel().main()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index 5f19e1e2c6..5c789b1c03 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -3,15 +3,32 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the importmulti RPC."""
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error
-class ImportMultiTest (BitcoinTestFramework):
+from test_framework import script
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+ assert_raises_rpc_error,
+ bytes_to_hex_str,
+ hex_str_to_bytes
+)
+from test_framework.script import (
+ CScript,
+ OP_0,
+ hash160
+)
+from test_framework.messages import sha256
+
+class ImportMultiTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"]]
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def setup_network(self):
self.setup_nodes()
@@ -37,7 +54,7 @@ class ImportMultiTest (BitcoinTestFramework):
# RPC importmulti -----------------------------------------------
- # Bitcoin Address
+ # Bitcoin Address (implicit non-internal)
self.log.info("Should import an address")
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
@@ -51,6 +68,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
assert_equal(address_assert['timestamp'], timestamp)
+ assert_equal(address_assert['ischange'], False)
watchonly_address = address['address']
watchonly_timestamp = timestamp
@@ -78,24 +96,39 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
assert_equal(address_assert['timestamp'], timestamp)
+ assert_equal(address_assert['ischange'], True)
- # ScriptPubKey + !internal
- self.log.info("Should not import a scriptPubKey without internal flag")
+ # ScriptPubKey + internal + label
+ self.log.info("Should not allow a label to be specified when internal is true")
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
"timestamp": "now",
+ "internal": True,
+ "label": "Example label"
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ assert_equal(result[0]['error']['message'], 'Internal addresses should not have a label')
+
+ # Nonstandard scriptPubKey + !internal
+ self.log.info("Should not import a nonstandard scriptPubKey without internal flag")
+ nonstandardScriptPubKey = address['scriptPubKey'] + bytes_to_hex_str(script.CScript([script.OP_NOP]))
+ address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": nonstandardScriptPubKey,
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -8)
+ assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
assert_equal('timestamp' in address_assert, False)
- # Address + Public key + !Internal
+ # Address + Public key + !Internal(explicit)
self.log.info("Should import an address with public key")
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
@@ -103,7 +136,8 @@ class ImportMultiTest (BitcoinTestFramework):
"address": address['address']
},
"timestamp": "now",
- "pubkeys": [ address['pubkey'] ]
+ "pubkeys": [ address['pubkey'] ],
+ "internal": False
}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].getaddressinfo(address['address'])
@@ -121,25 +155,25 @@ class ImportMultiTest (BitcoinTestFramework):
"pubkeys": [ address['pubkey'] ],
"internal": True
}]
- result = self.nodes[1].importmulti(request)
+ result = self.nodes[1].importmulti(requests=request)
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
assert_equal(address_assert['timestamp'], timestamp)
- # ScriptPubKey + Public key + !internal
- self.log.info("Should not import a scriptPubKey without internal and with public key")
+ # Nonstandard scriptPubKey + Public key + !internal
+ self.log.info("Should not import a nonstandard scriptPubKey without internal and with public key")
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
request = [{
- "scriptPubKey": address['scriptPubKey'],
+ "scriptPubKey": nonstandardScriptPubKey,
"timestamp": "now",
"pubkeys": [ address['pubkey'] ]
}]
- result = self.nodes[1].importmulti(request)
+ result = self.nodes[1].importmulti(requests=request)
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -186,7 +220,7 @@ class ImportMultiTest (BitcoinTestFramework):
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Incompatibility found between watchonly and keys')
+ assert_equal(result[0]['error']['message'], 'Watch-only addresses should not include private keys')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -207,17 +241,17 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['ismine'], True)
assert_equal(address_assert['timestamp'], timestamp)
- # ScriptPubKey + Private key + !internal
- self.log.info("Should not import a scriptPubKey without internal and with private key")
+ # Nonstandard scriptPubKey + Private key + !internal
+ self.log.info("Should not import a nonstandard scriptPubKey without internal and with private key")
address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
- "scriptPubKey": address['scriptPubKey'],
+ "scriptPubKey": nonstandardScriptPubKey,
"timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Internal must be set for hex scriptPubKey')
+ assert_equal(result[0]['error']['message'], 'Internal must be set to true for nonstandard scriptPubKey imports.')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -327,7 +361,7 @@ class ImportMultiTest (BitcoinTestFramework):
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
- assert_equal(result[0]['error']['message'], 'Incompatibility found between watchonly and keys')
+ assert_equal(result[0]['error']['message'], 'Watch-only addresses should not include private keys')
# Address + Public key + !Internal + Wrong pubkey
@@ -343,7 +377,7 @@ class ImportMultiTest (BitcoinTestFramework):
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -5)
- assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ assert_equal(result[0]['error']['message'], 'Key does not match address destination')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -363,7 +397,7 @@ class ImportMultiTest (BitcoinTestFramework):
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -5)
- assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ assert_equal(result[0]['error']['message'], 'Key does not match address destination')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -383,7 +417,7 @@ class ImportMultiTest (BitcoinTestFramework):
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -5)
- assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ assert_equal(result[0]['error']['message'], 'Key does not match address destination')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -402,7 +436,7 @@ class ImportMultiTest (BitcoinTestFramework):
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -5)
- assert_equal(result[0]['error']['message'], 'Consistency check failed')
+ assert_equal(result[0]['error']['message'], 'Key does not match address destination')
address_assert = self.nodes[1].getaddressinfo(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
@@ -446,6 +480,147 @@ class ImportMultiTest (BitcoinTestFramework):
"timestamp": "",
}])
+ # Import P2WPKH address as watch only
+ self.log.info("Should import a P2WPKH address as watch only")
+ address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress(address_type="bech32"))
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(address['address'])
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['solvable'], False)
+
+ # Import P2WPKH address with public key but no private key
+ self.log.info("Should import a P2WPKH address and public key as solvable but not spendable")
+ address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress(address_type="bech32"))
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "pubkeys": [ address['pubkey'] ]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(address['address'])
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['solvable'], True)
+
+ # Import P2WPKH address with key and check it is spendable
+ self.log.info("Should import a P2WPKH address with key")
+ address = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress(address_type="bech32"))
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "keys": [self.nodes[0].dumpprivkey(address['address'])]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(address['address'])
+ assert_equal(address_assert['iswatchonly'], False)
+ assert_equal(address_assert['ismine'], True)
+
+ # P2WSH multisig address without scripts or keys
+ sig_address_1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
+ sig_address_2 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
+ multi_sig_script = self.nodes[0].addmultisigaddress(2, [sig_address_1['pubkey'], sig_address_2['pubkey']], "", "bech32")
+ self.log.info("Should import a p2wsh multisig as watch only without respective redeem script and private keys")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": multi_sig_script['address']
+ },
+ "timestamp": "now"
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(multi_sig_script['address'])
+ assert_equal(address_assert['solvable'], False)
+
+ # Same P2WSH multisig address as above, but now with witnessscript + private keys
+ self.log.info("Should import a p2wsh with respective redeem script and private keys")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": multi_sig_script['address']
+ },
+ "timestamp": "now",
+ "witnessscript": multi_sig_script['redeemScript'],
+ "keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address']) ]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(multi_sig_script['address'])
+ assert_equal(address_assert['solvable'], True)
+ assert_equal(address_assert['ismine'], True)
+ assert_equal(address_assert['sigsrequired'], 2)
+
+ # P2SH-P2WPKH address with no redeemscript or public or private key
+ sig_address_1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress(address_type="p2sh-segwit"))
+ pubkeyhash = hash160(hex_str_to_bytes(sig_address_1['pubkey']))
+ pkscript = CScript([OP_0, pubkeyhash])
+ self.log.info("Should import a p2sh-p2wpkh without redeem script or keys")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": sig_address_1['address']
+ },
+ "timestamp": "now"
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(sig_address_1['address'])
+ assert_equal(address_assert['solvable'], False)
+ assert_equal(address_assert['ismine'], False)
+
+ # P2SH-P2WPKH address + redeemscript + public key with no private key
+ self.log.info("Should import a p2sh-p2wpkh with respective redeem script and pubkey as solvable")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": sig_address_1['address']
+ },
+ "timestamp": "now",
+ "redeemscript": bytes_to_hex_str(pkscript),
+ "pubkeys": [ sig_address_1['pubkey'] ]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(sig_address_1['address'])
+ assert_equal(address_assert['solvable'], True)
+ assert_equal(address_assert['ismine'], False)
+
+ # P2SH-P2WPKH address + redeemscript + private key
+ sig_address_1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress(address_type="p2sh-segwit"))
+ pubkeyhash = hash160(hex_str_to_bytes(sig_address_1['pubkey']))
+ pkscript = CScript([OP_0, pubkeyhash])
+ self.log.info("Should import a p2sh-p2wpkh with respective redeem script and private keys")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": sig_address_1['address']
+ },
+ "timestamp": "now",
+ "redeemscript": bytes_to_hex_str(pkscript),
+ "keys": [ self.nodes[0].dumpprivkey(sig_address_1['address'])]
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(sig_address_1['address'])
+ assert_equal(address_assert['solvable'], True)
+ assert_equal(address_assert['ismine'], True)
+
+ # P2SH-P2WSH 1-of-1 multisig + redeemscript with no private key
+ sig_address_1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
+ multi_sig_script = self.nodes[0].addmultisigaddress(1, [sig_address_1['pubkey']], "", "p2sh-segwit")
+ scripthash = sha256(hex_str_to_bytes(multi_sig_script['redeemScript']))
+ redeem_script = CScript([OP_0, scripthash])
+ self.log.info("Should import a p2sh-p2wsh with respective redeem script but no private key")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": multi_sig_script['address']
+ },
+ "timestamp": "now",
+ "redeemscript": bytes_to_hex_str(redeem_script),
+ "witnessscript": multi_sig_script['redeemScript']
+ }])
+ assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].getaddressinfo(multi_sig_script['address'])
+ assert_equal(address_assert['solvable'], True)
if __name__ == '__main__':
ImportMultiTest ().main ()
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 57fc754d35..78426018ef 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -16,6 +16,9 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.log.info("Mining blocks...")
self.nodes[0].generate(101)
@@ -78,7 +81,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
# Import with affiliated address with no rescan
self.nodes[1].importaddress(address=address2, rescan=False)
- self.nodes[1].importprunedfunds(rawtxn2, proof2)
+ self.nodes[1].importprunedfunds(rawtransaction=rawtxn2, txoutproof=proof2)
assert [tx for tx in self.nodes[1].listtransactions(include_watchonly=True) if tx['txid'] == txnid2]
# Import with private key with no rescan
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index f52dce04dd..ceb9709712 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -13,6 +13,9 @@ class KeyPoolTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
nodes = self.nodes
addr_before_encrypting = nodes[0].getnewaddress()
@@ -22,9 +25,7 @@ class KeyPoolTest(BitcoinTestFramework):
assert(addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid'])
# Encrypt wallet and wait to terminate
- nodes[0].node_encrypt_wallet('test')
- # Restart node 0
- self.start_node(0)
+ nodes[0].encryptwallet('test')
# Keep creating keys
addr = nodes[0].getnewaddress()
addr_data = nodes[0].getaddressinfo(addr)
@@ -72,11 +73,10 @@ class KeyPoolTest(BitcoinTestFramework):
time.sleep(1.1)
assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0)
- # drain them by mining
- nodes[0].generate(1)
- nodes[0].generate(1)
- nodes[0].generate(1)
- assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].generate, 1)
+ # drain the keypool
+ for _ in range(3):
+ nodes[0].getnewaddress()
+ assert_raises_rpc_error(-12, "Keypool ran out", nodes[0].getnewaddress)
nodes[0].walletpassphrase('test', 100)
nodes[0].keypoolrefill(100)
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index f6b88e6225..f1a441c399 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -27,6 +27,9 @@ class KeypoolRestoreTest(BitcoinTestFramework):
self.num_nodes = 2
self.extra_args = [[], ['-keypool=100']]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
wallet_path = os.path.join(self.nodes[1].datadir, "regtest", "wallets", "wallet.dat")
wallet_backup_path = os.path.join(self.nodes[1].datadir, "wallet.bak")
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index 01a73d9cef..b71dae9f40 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -19,6 +19,9 @@ class WalletLabelsTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Check that there's no UTXO on the node
node = self.nodes[0]
@@ -26,8 +29,8 @@ class WalletLabelsTest(BitcoinTestFramework):
# Note each time we call generate, all generated coins go into
# the same address, so we call twice to get two addresses w/50 each
- node.generate(1)
- node.generate(101)
+ node.generatetoaddress(nblocks=1, address=node.getnewaddress(label='coinbase'))
+ node.generatetoaddress(nblocks=101, address=node.getnewaddress(label='coinbase'))
assert_equal(node.getbalance(), 100)
# there should be 2 address groups
@@ -39,8 +42,9 @@ class WalletLabelsTest(BitcoinTestFramework):
linked_addresses = set()
for address_group in address_groups:
assert_equal(len(address_group), 1)
- assert_equal(len(address_group[0]), 2)
+ assert_equal(len(address_group[0]), 3)
assert_equal(address_group[0][1], 50)
+ assert_equal(address_group[0][2], 'coinbase')
linked_addresses.add(address_group[0][0])
# send 50 from each address to a third address not in this wallet
@@ -74,7 +78,7 @@ class WalletLabelsTest(BitcoinTestFramework):
label.verify(node)
# Check all labels are returned by listlabels.
- assert_equal(node.listlabels(), [label.name for label in labels])
+ assert_equal(node.listlabels(), sorted(['coinbase'] + [label.name for label in labels]))
# Send a transaction to each label.
for label in labels:
diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py
index 09a7c72347..011975e371 100755
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -18,11 +18,17 @@ class ReceivedByTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Generate block to get out of IBD
self.nodes[0].generate(1)
sync_blocks(self.nodes)
+ # save the number of coinbase reward addresses so far
+ num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True))
+
self.log.info("listreceivedbyaddress Test")
# Send from node 0 to 1
@@ -60,11 +66,15 @@ class ReceivedByTest(BitcoinTestFramework):
res = self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True, address_filter=addr)
assert_array_result(res, {"address": addr}, expected)
assert_equal(len(res), 1)
+ # Test for regression on CLI calls with address string (#14173)
+ cli_res = self.nodes[1].cli.listreceivedbyaddress(0, True, True, addr)
+ assert_array_result(cli_res, {"address": addr}, expected)
+ assert_equal(len(cli_res), 1)
# Error on invalid address
assert_raises_rpc_error(-4, "address_filter parameter was invalid", self.nodes[1].listreceivedbyaddress, minconf=0, include_empty=True, include_watchonly=True, address_filter="bamboozling")
# Another address receive money
res = self.nodes[1].listreceivedbyaddress(0, True, True)
- assert_equal(len(res), 2) # Right now 2 entries
+ assert_equal(len(res), 2 + num_cb_reward_addresses) # Right now 2 entries
other_addr = self.nodes[1].getnewaddress()
txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1)
self.nodes[0].generate(1)
@@ -81,7 +91,7 @@ class ReceivedByTest(BitcoinTestFramework):
assert_equal(len(res), 1)
# Should be two entries though without filter
res = self.nodes[1].listreceivedbyaddress(0, True, True)
- assert_equal(len(res), 3) # Became 3 entries
+ assert_equal(len(res), 3 + num_cb_reward_addresses) # Became 3 entries
# Not on random addr
other_addr = self.nodes[0].getnewaddress() # note on node[0]! just a random addr
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index 847b48aa89..25ab222375 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -12,6 +12,9 @@ class ListSinceBlockTest (BitcoinTestFramework):
self.num_nodes = 4
self.setup_clean_chain = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.nodes[2].generate(101)
self.sync_all()
@@ -50,8 +53,10 @@ class ListSinceBlockTest (BitcoinTestFramework):
"42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4")
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock,
"0000000000000000000000000000000000000000000000000000000000000000")
- assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock,
+ assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 11, for 'invalid-hex')", self.nodes[0].listsinceblock,
"invalid-hex")
+ assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'Z000000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].listsinceblock,
+ "Z000000000000000000000000000000000000000000000000000000000000000")
def test_reorg(self):
'''
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 4dc3ff4b26..8ca0387268 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -27,6 +27,9 @@ class ListTransactionsTest(BitcoinTestFramework):
self.num_nodes = 2
self.enable_mocktime()
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Simple send, 0 to 1:
txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
@@ -94,9 +97,10 @@ class ListTransactionsTest(BitcoinTestFramework):
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
self.nodes[1].generate(1)
self.sync_all()
- assert not [tx for tx in self.nodes[0].listtransactions(dummy="*", count=100, skip=0, include_watchonly=False) if "label" in tx and tx["label"] == "watchonly"]
- txs = [tx for tx in self.nodes[0].listtransactions(dummy="*", count=100, skip=0, include_watchonly=True) if "label" in tx and tx['label'] == 'watchonly']
- assert_array_result(txs, {"category": "receive", "amount": Decimal("0.1")}, {"txid": txid})
+ assert len(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=False)) == 0
+ assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True),
+ {"category": "receive", "amount": Decimal("0.1")},
+ {"txid": txid, "label": "watchonly"})
self.run_rbf_opt_in_test()
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 0690dcf92d..8ab569a3c3 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -8,6 +8,7 @@ Verify that a bitcoind node can load multiple wallet files
"""
import os
import shutil
+import time
from test_framework.test_framework import BitcoinTestFramework
from test_framework.test_node import ErrorMatch
@@ -23,6 +24,9 @@ class MultiWalletTest(BitcoinTestFramework):
self.num_nodes = 2
self.supports_cli = True
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
node = self.nodes[0]
@@ -35,6 +39,8 @@ class MultiWalletTest(BitcoinTestFramework):
return wallet_dir(name, "wallet.dat")
return wallet_dir(name)
+ assert_equal(self.nodes[0].listwalletdir(), { 'wallets': [{ 'name': '' }] })
+
# check wallet.dat is created
self.stop_nodes()
assert_equal(os.path.isfile(wallet_dir('wallet.dat')), True)
@@ -65,6 +71,8 @@ class MultiWalletTest(BitcoinTestFramework):
wallet_names = ['w1', 'w2', 'w3', 'w', 'sub/w5', os.path.join(self.options.tmpdir, 'extern/w6'), 'w7_symlink', 'w8', '']
extra_args = ['-wallet={}'.format(n) for n in wallet_names]
self.start_node(0, extra_args)
+ assert_equal(sorted(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), ['', os.path.join('sub', 'w5'), 'w', 'w1', 'w2', 'w3', 'w7', 'w7_symlink', 'w8'])
+
assert_equal(set(node.listwallets()), set(wallet_names))
# check that all requested wallets were created
@@ -73,7 +81,7 @@ class MultiWalletTest(BitcoinTestFramework):
assert_equal(os.path.isfile(wallet_file(wallet_name)), True)
# should not initialize if wallet path can't be created
- exp_stderr = "boost::filesystem::create_directory: (The system cannot find the path specified|Not a directory):"
+ exp_stderr = "boost::filesystem::create_directory:"
self.nodes[0].assert_start_raises_init_error(['-wallet=wallet.dat/bad'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)
self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist')
@@ -118,7 +126,7 @@ class MultiWalletTest(BitcoinTestFramework):
self.start_node(0, ['-wallet=w4', '-wallet=w5'])
assert_equal(set(node.listwallets()), {"w4", "w5"})
w5 = wallet("w5")
- w5.generate(1)
+ node.generatetoaddress(nblocks=1, address=w5.getnewaddress())
# now if wallets/ exists again, but the rootdir is specified as the walletdir, w4 and w5 should still be loaded
os.rename(wallet_dir2, wallet_dir())
@@ -136,11 +144,13 @@ class MultiWalletTest(BitcoinTestFramework):
self.restart_node(0, extra_args)
+ assert_equal(sorted(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), ['', os.path.join('sub', 'w5'), 'w', 'w1', 'w2', 'w3', 'w7', 'w7_symlink', 'w8', 'w8_copy'])
+
wallets = [wallet(w) for w in wallet_names]
wallet_bad = wallet("bad")
# check wallet names and balances
- wallets[0].generate(1)
+ node.generatetoaddress(nblocks=1, address=wallets[0].getnewaddress())
for wallet_name, wallet in zip(wallet_names, wallets):
info = wallet.getwalletinfo()
assert_equal(info['immature_balance'], 50 if wallet is wallets[0] else 0)
@@ -153,7 +163,7 @@ class MultiWalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-19, "Wallet file not specified", node.getwalletinfo)
w1, w2, w3, w4, *_ = wallets
- w1.generate(101)
+ node.generatetoaddress(nblocks=101, address=w1.getnewaddress())
assert_equal(w1.getbalance(), 100)
assert_equal(w2.getbalance(), 0)
assert_equal(w3.getbalance(), 0)
@@ -162,7 +172,7 @@ class MultiWalletTest(BitcoinTestFramework):
w1.sendtoaddress(w2.getnewaddress(), 1)
w1.sendtoaddress(w3.getnewaddress(), 2)
w1.sendtoaddress(w4.getnewaddress(), 3)
- w1.generate(1)
+ node.generatetoaddress(nblocks=1, address=w1.getnewaddress())
assert_equal(w2.getbalance(), 1)
assert_equal(w3.getbalance(), 2)
assert_equal(w4.getbalance(), 3)
@@ -213,9 +223,16 @@ class MultiWalletTest(BitcoinTestFramework):
# Fail to load duplicate wallets
assert_raises_rpc_error(-4, 'Wallet file verification failed: Error loading wallet w1. Duplicate -wallet filename specified.', self.nodes[0].loadwallet, wallet_names[0])
+ # Fail to load duplicate wallets by different ways (directory and filepath)
+ assert_raises_rpc_error(-4, "Wallet file verification failed: Error loading wallet wallet.dat. Duplicate -wallet filename specified.", self.nodes[0].loadwallet, 'wallet.dat')
+
# Fail to load if one wallet is a copy of another
assert_raises_rpc_error(-1, "BerkeleyBatch: Can't open database w8_copy (duplicates fileid", self.nodes[0].loadwallet, 'w8_copy')
+ # Fail to load if one wallet is a copy of another, test this twice to make sure that we don't re-introduce #14304
+ assert_raises_rpc_error(-1, "BerkeleyBatch: Can't open database w8_copy (duplicates fileid", self.nodes[0].loadwallet, 'w8_copy')
+
+
# Fail to load if wallet file is a symlink
assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
@@ -259,7 +276,11 @@ class MultiWalletTest(BitcoinTestFramework):
assert 'w1' not in self.nodes[0].listwallets()
# Successfully unload the wallet referenced by the request endpoint
+ # Also ensure unload works during walletpassphrase timeout
+ w2.encryptwallet('test')
+ w2.walletpassphrase('test', 1)
w2.unloadwallet()
+ time.sleep(1.1)
assert 'w2' not in self.nodes[0].listwallets()
# Successfully unload all wallets
@@ -273,6 +294,8 @@ class MultiWalletTest(BitcoinTestFramework):
assert_equal(self.nodes[0].listwallets(), ['w1'])
assert_equal(w1.getwalletinfo()['walletname'], 'w1')
+ assert_equal(sorted(map(lambda w: w['name'], self.nodes[0].listwalletdir()['wallets'])), ['', os.path.join('sub', 'w5'), 'w', 'w1', 'w2', 'w3', 'w7', 'w7_symlink', 'w8', 'w8_copy', 'w9'])
+
# Test backing up and restoring wallets
self.log.info("Test wallet backup")
self.restart_node(0, ['-nowallet'])
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 8995aa743f..00bf58d709 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -12,6 +12,9 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [['--walletbroadcast=false']]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
# Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled.
assert_raises_rpc_error(-4, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast", self.nodes[0].resendwallettransactions)
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index 4ca4ee14e9..d78c105c17 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -16,6 +16,9 @@ class TxnMallTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def add_options(self, parser):
parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index 6811f6ab73..f114d5ab68 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -18,6 +18,9 @@ class TxnMallTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def add_options(self, parser):
parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
diff --git a/test/functional/wallet_zapwallettxes.py b/test/functional/wallet_zapwallettxes.py
index cbd142d1ee..adebff360a 100755
--- a/test/functional/wallet_zapwallettxes.py
+++ b/test/functional/wallet_zapwallettxes.py
@@ -26,6 +26,9 @@ class ZapWalletTXesTest (BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 2
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
self.log.info("Mining blocks...")
self.nodes[0].generate(1)