aboutsummaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
Diffstat (limited to 'qa')
-rw-r--r--qa/README.md8
-rwxr-xr-xqa/pull-tester/rpc-tests.py313
-rw-r--r--qa/pull-tester/run-bitcoind-for-test.sh.in36
-rw-r--r--qa/pull-tester/tests_config.ini.in18
-rw-r--r--qa/pull-tester/tests_config.py.in14
-rwxr-xr-xqa/rpc-tests/abandonconflict.py9
-rwxr-xr-xqa/rpc-tests/assumevalid.py190
-rwxr-xr-xqa/rpc-tests/bip65-cltv-p2p.py26
-rwxr-xr-xqa/rpc-tests/bip65-cltv.py5
-rwxr-xr-xqa/rpc-tests/bip68-112-113-p2p.py26
-rwxr-xr-xqa/rpc-tests/bip68-sequence.py7
-rwxr-xr-xqa/rpc-tests/bip9-softforks.py40
-rwxr-xr-xqa/rpc-tests/bipdersig-p2p.py31
-rwxr-xr-xqa/rpc-tests/bipdersig.py5
-rwxr-xr-xqa/rpc-tests/blockchain.py18
-rwxr-xr-xqa/rpc-tests/bumpfee.py325
-rwxr-xr-xqa/rpc-tests/create_cache.py9
-rwxr-xr-xqa/rpc-tests/decodescript.py4
-rwxr-xr-xqa/rpc-tests/disablewallet.py8
-rwxr-xr-xqa/rpc-tests/forknotify.py7
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py124
-rwxr-xr-xqa/rpc-tests/getblocktemplate_longpoll.py5
-rwxr-xr-xqa/rpc-tests/getblocktemplate_proposals.py4
-rwxr-xr-xqa/rpc-tests/getchaintips.py9
-rwxr-xr-xqa/rpc-tests/httpbasics.py5
-rwxr-xr-xqa/rpc-tests/import-rescan.py193
-rwxr-xr-xqa/rpc-tests/importmulti.py96
-rwxr-xr-xqa/rpc-tests/importprunedfunds.py2
-rwxr-xr-xqa/rpc-tests/invalidateblock.py5
-rwxr-xr-xqa/rpc-tests/invalidblockrequest.py17
-rwxr-xr-xqa/rpc-tests/invalidtxrequest.py7
-rwxr-xr-xqa/rpc-tests/keypool.py3
-rwxr-xr-xqa/rpc-tests/listsinceblock.py81
-rwxr-xr-xqa/rpc-tests/listtransactions.py3
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py13
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py23
-rwxr-xr-xqa/rpc-tests/mempool_limit.py9
-rwxr-xr-xqa/rpc-tests/mempool_packages.py7
-rwxr-xr-xqa/rpc-tests/mempool_reorg.py10
-rwxr-xr-xqa/rpc-tests/mempool_resurrect_test.py6
-rwxr-xr-xqa/rpc-tests/mempool_spendcoinbase.py19
-rwxr-xr-xqa/rpc-tests/merkle_blocks.py5
-rwxr-xr-xqa/rpc-tests/multi_rpc.py5
-rwxr-xr-xqa/rpc-tests/nodehandling.py6
-rwxr-xr-xqa/rpc-tests/nulldummy.py21
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py18
-rwxr-xr-xqa/rpc-tests/p2p-compactblocks.py91
-rwxr-xr-xqa/rpc-tests/p2p-feefilter.py9
-rwxr-xr-xqa/rpc-tests/p2p-fullblocktest.py20
-rwxr-xr-xqa/rpc-tests/p2p-leaktests.py143
-rwxr-xr-xqa/rpc-tests/p2p-mempool.py6
-rwxr-xr-xqa/rpc-tests/p2p-segwit.py7
-rwxr-xr-xqa/rpc-tests/p2p-timeouts.py103
-rwxr-xr-xqa/rpc-tests/p2p-versionbits-warning.py12
-rwxr-xr-xqa/rpc-tests/preciousblock.py9
-rwxr-xr-xqa/rpc-tests/prioritise_transaction.py7
-rwxr-xr-xqa/rpc-tests/proxy_test.py29
-rwxr-xr-xqa/rpc-tests/pruning.py179
-rwxr-xr-xqa/rpc-tests/rawtransactions.py16
-rwxr-xr-xqa/rpc-tests/receivedby.py7
-rwxr-xr-xqa/rpc-tests/reindex.py9
-rwxr-xr-xqa/rpc-tests/replace-by-fee.py10
-rwxr-xr-xqa/rpc-tests/rest.py6
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py22
-rwxr-xr-xqa/rpc-tests/rpcnamedargs.py47
-rwxr-xr-xqa/rpc-tests/segwit.py34
-rwxr-xr-xqa/rpc-tests/sendheaders.py17
-rwxr-xr-xqa/rpc-tests/signmessages.py3
-rwxr-xr-xqa/rpc-tests/signrawtransactions.py41
-rwxr-xr-xqa/rpc-tests/smartfees.py27
-rw-r--r--qa/rpc-tests/test_framework/address.py7
-rw-r--r--qa/rpc-tests/test_framework/authproxy.py73
-rw-r--r--qa/rpc-tests/test_framework/bignum.py10
-rw-r--r--qa/rpc-tests/test_framework/blockstore.py12
-rw-r--r--qa/rpc-tests/test_framework/blocktools.py2
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py33
-rw-r--r--qa/rpc-tests/test_framework/coverage.py9
-rw-r--r--qa/rpc-tests/test_framework/key.py10
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py70
-rw-r--r--qa/rpc-tests/test_framework/netutil.py5
-rw-r--r--qa/rpc-tests/test_framework/script.py12
-rw-r--r--qa/rpc-tests/test_framework/siphash.py7
-rw-r--r--qa/rpc-tests/test_framework/socks5.py14
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py3
-rw-r--r--qa/rpc-tests/test_framework/util.py78
-rwxr-xr-xqa/rpc-tests/txn_clone.py5
-rwxr-xr-xqa/rpc-tests/txn_doublespend.py5
-rwxr-xr-xqa/rpc-tests/wallet-accounts.py12
-rwxr-xr-xqa/rpc-tests/wallet-dump.py1
-rwxr-xr-xqa/rpc-tests/wallet-hd.py1
-rwxr-xr-xqa/rpc-tests/wallet.py57
-rwxr-xr-xqa/rpc-tests/walletbackup.py4
-rwxr-xr-xqa/rpc-tests/zapwallettxes.py9
-rwxr-xr-xqa/rpc-tests/zmq_test.py8
94 files changed, 2309 insertions, 787 deletions
diff --git a/qa/README.md b/qa/README.md
index 225207cc1c..f4dce7af5c 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -39,12 +39,12 @@ Run the regression test suite with
Run all possible tests with
- qa/pull-tester/rpc-tests.py -extended
+ qa/pull-tester/rpc-tests.py --extended
By default, tests will be run in parallel. To specify how many jobs to run,
-append `-parallel=n` (default n=4).
+append `--jobs=n` (default n=4).
-If you want to create a basic coverage report for the rpc test suite, append `--coverage`.
+If you want to create a basic coverage report for the RPC test suite, append `--coverage`.
Possible options, which apply to each individual test run:
@@ -83,5 +83,5 @@ killall bitcoind
Writing tests
=============
You are encouraged to write tests for new or existing features.
-Further information about the test framework and individual rpc
+Further information about the test framework and individual RPC
tests is found in [qa/rpc-tests](/qa/rpc-tests).
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index 58bd00fdfc..68e11b4c2b 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -2,25 +2,21 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
"""
-Run Regression Test Suite
+rpc-tests.py - run regression test suite
This module calls down into individual test cases via subprocess. It will
-forward all unrecognized arguments onto the individual test scripts, other
-than:
+forward all unrecognized arguments onto the individual test scripts.
- - `-extended`: run the "extended" test suite in addition to the basic one.
- - `-win`: signal that this is running in a Windows environment, and we
- should run the tests.
- - `--coverage`: this generates a basic coverage report for the RPC
- interface.
+RPC tests are disabled on Windows by default. Use --force to run them anyway.
For a description of arguments recognized by test scripts, see
`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`.
"""
+import argparse
+import configparser
import os
import time
import shutil
@@ -29,189 +25,228 @@ import subprocess
import tempfile
import re
-sys.path.append("qa/pull-tester/")
-from tests_config import *
-
-BOLD = ("","")
-if os.name == 'posix':
- # primitive formatting on supported
- # terminal via ANSI escape sequences:
- BOLD = ('\033[0m', '\033[1m')
-
-RPC_TESTS_DIR = SRCDIR + '/qa/rpc-tests/'
-
-#If imported values are not defined then set to zero (or disabled)
-if 'ENABLE_WALLET' not in vars():
- ENABLE_WALLET=0
-if 'ENABLE_BITCOIND' not in vars():
- ENABLE_BITCOIND=0
-if 'ENABLE_UTILS' not in vars():
- ENABLE_UTILS=0
-if 'ENABLE_ZMQ' not in vars():
- ENABLE_ZMQ=0
-
-ENABLE_COVERAGE=0
-
-#Create a set to store arguments and create the passon string
-opts = set()
-passon_args = []
-PASSON_REGEX = re.compile("^--")
-PARALLEL_REGEX = re.compile('^-parallel=')
-
-print_help = False
-run_parallel = 4
-
-for arg in sys.argv[1:]:
- if arg == "--help" or arg == "-h" or arg == "-?":
- print_help = True
- break
- if arg == '--coverage':
- ENABLE_COVERAGE = 1
- elif PASSON_REGEX.match(arg):
- passon_args.append(arg)
- elif PARALLEL_REGEX.match(arg):
- run_parallel = int(arg.split(sep='=', maxsplit=1)[1])
- else:
- opts.add(arg)
-
-#Set env vars
-if "BITCOIND" not in os.environ:
- os.environ["BITCOIND"] = BUILDDIR + '/src/bitcoind' + EXEEXT
-
-if EXEEXT == ".exe" and "-win" not in opts:
- # https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
- # https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
- print("Win tests currently disabled by default. Use -win option to enable")
- sys.exit(0)
-
-if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
- print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
- sys.exit(0)
-
-# python3-zmq may not be installed. Handle this gracefully and with some helpful info
-if ENABLE_ZMQ:
- try:
- import zmq
- except ImportError:
- print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or "
- "to run zmq tests, see dependency info in /qa/README.md.")
- # ENABLE_ZMQ=0
- raise
-
-testScripts = [
- # longest test should go first, to favor running tests in parallel
- 'p2p-fullblocktest.py',
+BASE_SCRIPTS= [
+ # Scripts that are run by the travis build process.
+ # Longest test should go first, to favor running tests in parallel
+ 'wallet-hd.py',
'walletbackup.py',
- 'bip68-112-113-p2p.py',
+ # vv Tests less than 5m vv
+ 'p2p-fullblocktest.py',
+ 'fundrawtransaction.py',
+ 'p2p-compactblocks.py',
+ 'segwit.py',
+ # vv Tests less than 2m vv
'wallet.py',
'wallet-accounts.py',
- 'wallet-hd.py',
+ 'p2p-segwit.py',
'wallet-dump.py',
'listtransactions.py',
+ # vv Tests less than 60s vv
+ 'sendheaders.py',
+ 'zapwallettxes.py',
+ 'importmulti.py',
+ 'mempool_limit.py',
+ 'merkle_blocks.py',
'receivedby.py',
+ 'abandonconflict.py',
+ 'bip68-112-113-p2p.py',
+ 'rawtransactions.py',
+ 'reindex.py',
+ # vv Tests less than 30s vv
'mempool_resurrect_test.py',
'txn_doublespend.py --mineblock',
- 'p2p-segwit.py',
- 'segwit.py',
'txn_clone.py',
'getchaintips.py',
- 'rawtransactions.py',
'rest.py',
'mempool_spendcoinbase.py',
'mempool_reorg.py',
- 'mempool_limit.py',
'httpbasics.py',
'multi_rpc.py',
- 'zapwallettxes.py',
'proxy_test.py',
- 'merkle_blocks.py',
- 'fundrawtransaction.py',
'signrawtransactions.py',
'nodehandling.py',
- 'reindex.py',
'decodescript.py',
'blockchain.py',
'disablewallet.py',
- 'sendheaders.py',
'keypool.py',
'p2p-mempool.py',
'prioritise_transaction.py',
'invalidblockrequest.py',
'invalidtxrequest.py',
- 'abandonconflict.py',
'p2p-versionbits-warning.py',
'preciousblock.py',
'importprunedfunds.py',
'signmessages.py',
- 'p2p-compactblocks.py',
'nulldummy.py',
- 'importmulti.py',
+ 'import-rescan.py',
+ 'bumpfee.py',
+ 'rpcnamedargs.py',
+ 'listsinceblock.py',
+ 'p2p-leaktests.py',
]
-if ENABLE_ZMQ:
- testScripts.append('zmq_test.py')
-testScriptsExt = [
+ZMQ_SCRIPTS = [
+ # ZMQ test can only be run if bitcoin was built with zmq-enabled.
+ # call rpc_tests.py with -nozmq to explicitly exclude these tests.
+ "zmq_test.py"]
+
+EXTENDED_SCRIPTS = [
+ # These tests are not run by the travis build process.
+ # Longest test should go first, to favor running tests in parallel
+ 'pruning.py',
+ # vv Tests less than 20m vv
+ 'smartfees.py',
+ # vv Tests less than 5m vv
+ 'maxuploadtarget.py',
+ 'mempool_packages.py',
+ # vv Tests less than 2m vv
+ 'bip68-sequence.py',
+ 'getblocktemplate_longpoll.py',
+ 'p2p-timeouts.py',
+ # vv Tests less than 60s vv
'bip9-softforks.py',
+ 'p2p-feefilter.py',
+ 'rpcbind_test.py',
+ # vv Tests less than 30s vv
'bip65-cltv.py',
'bip65-cltv-p2p.py',
- 'bip68-sequence.py',
'bipdersig-p2p.py',
'bipdersig.py',
- 'getblocktemplate_longpoll.py',
'getblocktemplate_proposals.py',
'txn_doublespend.py',
'txn_clone.py --mineblock',
'forknotify.py',
'invalidateblock.py',
- 'rpcbind_test.py',
- 'smartfees.py',
'maxblocksinflight.py',
'p2p-acceptblock.py',
- 'mempool_packages.py',
- 'maxuploadtarget.py',
'replace-by-fee.py',
- 'p2p-feefilter.py',
- 'pruning.py', # leave pruning last as it takes a REALLY long time
]
+ALL_SCRIPTS = BASE_SCRIPTS + ZMQ_SCRIPTS + EXTENDED_SCRIPTS
+
+def main():
+ # Parse arguments and pass through unrecognised args
+ parser = argparse.ArgumentParser(add_help=False,
+ usage='%(prog)s [rpc-test.py options] [script options] [scripts]',
+ description=__doc__,
+ epilog='''
+ Help text and arguments for individual test script:''',
+ formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')
+ parser.add_argument('--exclude', '-x', help='specify a comma-seperated-list of scripts to exclude. Do not include the .py extension in the name.')
+ 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('--nozmq', action='store_true', help='do not run the zmq tests')
+ args, unknown_args = parser.parse_known_args()
+
+ # Create a set to store arguments and create the passon string
+ tests = set(arg for arg in unknown_args if arg[:2] != "--")
+ passon_args = [arg for arg in unknown_args if arg[:2] == "--"]
+
+ # Read config generated by configure.
+ config = configparser.ConfigParser()
+ config.read_file(open(os.path.dirname(__file__) + "/tests_config.ini"))
+
+ enable_wallet = config["components"].getboolean("ENABLE_WALLET")
+ enable_utils = config["components"].getboolean("ENABLE_UTILS")
+ enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
+ enable_zmq = config["components"].getboolean("ENABLE_ZMQ") and not args.nozmq
+
+ if config["environment"]["EXEEXT"] == ".exe" and not args.force:
+ # https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
+ # https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
+ print("Tests currently disabled on Windows by default. Use --force option to enable")
+ sys.exit(0)
-def runtests():
- test_list = []
- if '-extended' in opts:
- test_list = testScripts + testScriptsExt
- elif len(opts) == 0 or (len(opts) == 1 and "-win" in opts):
- test_list = testScripts
+ if not (enable_wallet and enable_utils and enable_bitcoind):
+ print("No rpc 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")
+ sys.exit(0)
+
+ # python3-zmq may not be installed. Handle this gracefully and with some helpful info
+ if enable_zmq:
+ try:
+ import zmq
+ except ImportError:
+ print("ERROR: \"import zmq\" failed. Use -nozmq to run without the ZMQ tests."
+ "To run zmq tests, see dependency info in /qa/README.md.")
+ raise
+
+ # Build list of tests
+ if tests:
+ # Individual tests have been specified. Run specified tests that exist
+ # in the ALL_SCRIPTS list. Accept the name with or without .py extension.
+ test_list = [t for t in ALL_SCRIPTS if
+ (t in tests or re.sub(".py$", "", t) in tests)]
else:
- for t in testScripts + testScriptsExt:
- if t in opts or re.sub(".py$", "", t) in opts:
- test_list.append(t)
+ # No individual tests have been specified. Run base tests, and
+ # optionally ZMQ tests and extended tests.
+ test_list = BASE_SCRIPTS
+ if enable_zmq:
+ test_list += ZMQ_SCRIPTS
+ if args.extended:
+ test_list += EXTENDED_SCRIPTS
+ # TODO: BASE_SCRIPTS and EXTENDED_SCRIPTS are sorted by runtime
+ # (for parallel running efficiency). This combined list will is no
+ # longer sorted.
+
+ # Remove the test cases that the user has explicitly asked to exclude.
+ if args.exclude:
+ for exclude_test in args.exclude.split(','):
+ if exclude_test + ".py" in test_list:
+ test_list.remove(exclude_test + ".py")
+
+ if not test_list:
+ print("No valid test scripts specified. Check that your test is in one "
+ "of the test lists in rpc-tests.py, or run rpc-tests.py with no arguments to run all tests")
+ sys.exit(0)
- if print_help:
- # Only print help of the first script and exit
- subprocess.check_call((RPC_TESTS_DIR + test_list[0]).split() + ['-h'])
+ if args.help:
+ # Print help for rpc-tests.py, then print help of the first script and exit.
+ parser.print_help()
+ subprocess.check_call((config["environment"]["SRCDIR"] + '/qa/rpc-tests/' + test_list[0]).split() + ['-h'])
sys.exit(0)
- coverage = None
+ run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args)
+
+def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]):
+ BOLD = ("","")
+ if os.name == 'posix':
+ # primitive formatting on supported
+ # terminal via ANSI escape sequences:
+ BOLD = ('\033[0m', '\033[1m')
+
+ #Set env vars
+ if "BITCOIND" not in os.environ:
+ os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext
- if ENABLE_COVERAGE:
+ tests_dir = src_dir + '/qa/rpc-tests/'
+
+ flags = ["--srcdir={}/src".format(build_dir)] + args
+ flags.append("--cachedir=%s/qa/cache" % build_dir)
+
+ if enable_coverage:
coverage = RPCCoverage()
- print("Initializing coverage directory at %s\n" % coverage.dir)
- flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args
- flags.append("--cachedir=%s/qa/cache" % BUILDDIR)
- if coverage:
flags.append(coverage.flag)
+ print("Initializing coverage directory at %s\n" % coverage.dir)
+ else:
+ coverage = None
- if len(test_list) > 1 and run_parallel > 1:
+ if len(test_list) > 1 and jobs > 1:
# Populate cache
- subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + flags)
+ subprocess.check_output([tests_dir + 'create_cache.py'] + flags)
#Run Tests
- max_len_name = len(max(test_list, key=len))
+ all_passed = True
time_sum = 0
time0 = time.time()
- job_queue = RPCTestHandler(run_parallel, test_list, flags)
+
+ job_queue = RPCTestHandler(jobs, tests_dir, test_list, flags)
+
+ max_len_name = len(max(test_list, key=len))
results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0]
- all_passed = True
for _ in range(len(test_list)):
(name, stdout, stderr, passed, duration) = job_queue.get_next()
all_passed = all_passed and passed
@@ -220,8 +255,10 @@ def runtests():
print('\n' + BOLD[1] + name + BOLD[0] + ":")
print('' if passed else stdout + '\n', end='')
print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='')
- results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration))
+
+ results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
+
results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0]
print(results)
print("\nRuntime: %s s" % (int(time.time() - time0)))
@@ -234,15 +271,15 @@ def runtests():
sys.exit(not all_passed)
-
class RPCTestHandler:
"""
Trigger the testscrips passed in via the list.
"""
- def __init__(self, num_tests_parallel, test_list=None, flags=None):
+ def __init__(self, num_tests_parallel, tests_dir, test_list=None, flags=None):
assert(num_tests_parallel >= 1)
self.num_jobs = num_tests_parallel
+ self.tests_dir = tests_dir
self.test_list = test_list
self.flags = flags
self.num_running = 0
@@ -262,7 +299,7 @@ class RPCTestHandler:
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
self.jobs.append((t,
time.time(),
- subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed,
+ subprocess.Popen((self.tests_dir + t).split() + self.flags + port_seed,
universal_newlines=True,
stdout=log_stdout,
stderr=log_stderr),
@@ -327,10 +364,10 @@ class RPCCoverage(object):
"""
# This is shared from `qa/rpc-tests/test-framework/coverage.py`
- REFERENCE_FILENAME = 'rpc_interface.txt'
- COVERAGE_FILE_PREFIX = 'coverage.'
+ reference_filename = 'rpc_interface.txt'
+ coverage_file_prefix = 'coverage.'
- coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME)
+ coverage_ref_filename = os.path.join(self.dir, reference_filename)
coverage_filenames = set()
all_cmds = set()
covered_cmds = set()
@@ -343,7 +380,7 @@ class RPCCoverage(object):
for root, dirs, files in os.walk(self.dir):
for filename in files:
- if filename.startswith(COVERAGE_FILE_PREFIX):
+ if filename.startswith(coverage_file_prefix):
coverage_filenames.add(os.path.join(root, filename))
for filename in coverage_filenames:
@@ -354,4 +391,4 @@ class RPCCoverage(object):
if __name__ == '__main__':
- runtests()
+ main()
diff --git a/qa/pull-tester/run-bitcoind-for-test.sh.in b/qa/pull-tester/run-bitcoind-for-test.sh.in
deleted file mode 100644
index 14ae08e4e5..0000000000
--- a/qa/pull-tester/run-bitcoind-for-test.sh.in
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2013-2014 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-DATADIR="@abs_top_builddir@/.bitcoin"
-rm -rf "$DATADIR"
-mkdir -p "$DATADIR"/regtest
-touch "$DATADIR/regtest/debug.log"
-tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" &
-WAITER=$!
-PORT=`expr 10000 + $$ % 55536`
-"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -checkmempool=0 -relaypriority=0 -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` &
-BITCOIND=$!
-
-#Install a watchdog.
-(sleep 10 && kill -0 $WAITER 2>/dev/null && kill -9 $BITCOIND $$)&
-wait $WAITER
-
-if [ -n "$TIMEOUT" ]; then
- timeout "$TIMEOUT"s "$@" $PORT
- RETURN=$?
-else
- "$@" $PORT
- RETURN=$?
-fi
-
-(sleep 15 && kill -0 $BITCOIND 2>/dev/null && kill -9 $BITCOIND $$)&
-kill $BITCOIND && wait $BITCOIND
-
-# timeout returns 124 on timeout, otherwise the return value of the child
-
-# If $RETURN is not 0, the test failed. Dump the tail of the debug log.
-if [ $RETURN -ne 0 ]; then tail -n 200 $DATADIR/regtest/debug.log; fi
-
-exit $RETURN
diff --git a/qa/pull-tester/tests_config.ini.in b/qa/pull-tester/tests_config.ini.in
new file mode 100644
index 0000000000..e3e457d0b1
--- /dev/null
+++ b/qa/pull-tester/tests_config.ini.in
@@ -0,0 +1,18 @@
+# Copyright (c) 2013-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# These environment variables are set by the build process and read by
+# rpc-tests.py
+
+[environment]
+SRCDIR=@abs_top_srcdir@
+BUILDDIR=@abs_top_builddir@
+EXEEXT=@EXEEXT@
+
+[components]
+# Which components are enabled. These are commented out by `configure` if they were disabled when running config.
+@ENABLE_WALLET_TRUE@ENABLE_WALLET=true
+@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=true
+@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true
+@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true
diff --git a/qa/pull-tester/tests_config.py.in b/qa/pull-tester/tests_config.py.in
deleted file mode 100644
index a0d0a3d98a..0000000000
--- a/qa/pull-tester/tests_config.py.in
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2013-2016 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-SRCDIR="@abs_top_srcdir@"
-BUILDDIR="@abs_top_builddir@"
-EXEEXT="@EXEEXT@"
-
-# These will turn into comments if they were disabled when configuring.
-@ENABLE_WALLET_TRUE@ENABLE_WALLET=1
-@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=1
-@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=1
-@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=1
diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py
index 874df48777..b32d4e2ce0 100755
--- a/qa/rpc-tests/abandonconflict.py
+++ b/qa/rpc-tests/abandonconflict.py
@@ -2,7 +2,14 @@
# Copyright (c) 2014-2016 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 abandontransaction RPC.
+
+ The abandontransaction RPC marks a transaction and all its in-wallet
+ descendants as abandoned which allows their inputs to be respent. It can be
+ used to replace "stuck" or evicted transactions. It only works on transactions
+ which are not included in a block and are not currently in the mempool. It has
+ no effect on transactions which are already conflicted or abandoned.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/assumevalid.py b/qa/rpc-tests/assumevalid.py
new file mode 100755
index 0000000000..b8dafff161
--- /dev/null
+++ b/qa/rpc-tests/assumevalid.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-2016 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 logic for skipping signature validation on old blocks.
+
+Test logic for skipping signature validation on blocks which we've assumed
+valid (https://github.com/bitcoin/bitcoin/pull/9484)
+
+We build a chain that includes and invalid signature for one of the
+transactions:
+
+ 0: genesis block
+ 1: block 1 with coinbase transaction output.
+ 2-101: bury that block with 100 blocks so the coinbase transaction
+ output can be spent
+ 102: a block containing a transaction spending the coinbase
+ transaction output. The transaction has an invalid signature.
+ 103-2202: bury the bad block with just over two weeks' worth of blocks
+ (2100 blocks)
+
+Start three nodes:
+
+ - node0 has no -assumevalid parameter. Try to sync to block 2202. It will
+ reject block 102 and only sync as far as block 101
+ - node1 has -assumevalid set to the hash of block 102. Try to sync to
+ block 2202. node1 will sync all the way to block 2202.
+ - node2 has -assumevalid set to the hash of block 102. Try to sync to
+ block 200. node2 will reject block 102 since it's assumed valid, but it
+ isn't buried by at least two weeks' work.
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.blocktools import create_block, create_coinbase
+from test_framework.key import CECKey
+from test_framework.script import *
+
+class BaseNode(SingleNodeConnCB):
+ def __init__(self):
+ SingleNodeConnCB.__init__(self)
+ self.last_inv = None
+ self.last_headers = None
+ self.last_block = None
+ self.last_getdata = None
+ self.block_announced = False
+ self.last_getheaders = None
+ self.disconnected = False
+ self.last_blockhash_announced = None
+
+ def on_close(self, conn):
+ self.disconnected = True
+
+ def wait_for_disconnect(self, timeout=60):
+ test_function = lambda: self.disconnected
+ assert(wait_until(test_function, timeout=timeout))
+ return
+
+ def send_header_for_blocks(self, new_blocks):
+ headers_message = msg_headers()
+ headers_message.headers = [ CBlockHeader(b) for b in new_blocks ]
+ self.send_message(headers_message)
+
+class SendHeadersTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
+ def setup_network(self):
+ # Start node0. We don't start the other nodes yet since
+ # we need to pre-mine a block with an invalid transaction
+ # signature so we can pass in the block hash as assumevalid.
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
+
+ def run_test(self):
+
+ # Connect to node0
+ node0 = BaseNode()
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
+ node0.add_connection(connections[0])
+
+ NetworkThread().start() # Start up network handling in another thread
+ node0.wait_for_verack()
+
+ # Build the blockchain
+ self.tip = int(self.nodes[0].getbestblockhash(), 16)
+ self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
+
+ self.blocks = []
+
+ # Get a pubkey for the coinbase TXO
+ coinbase_key = CECKey()
+ coinbase_key.set_secretbytes(b"horsebattery")
+ coinbase_pubkey = coinbase_key.get_pubkey()
+
+ # Create the first block with a coinbase output to our key
+ height = 1
+ block = create_block(self.tip, create_coinbase(height, coinbase_pubkey), self.block_time)
+ self.blocks.append(block)
+ self.block_time += 1
+ block.solve()
+ # Save the coinbase for later
+ self.block1 = block
+ self.tip = block.sha256
+ height += 1
+
+ # Bury the block 100 deep so the coinbase output is spendable
+ for i in range(100):
+ block = create_block(self.tip, create_coinbase(height), self.block_time)
+ block.solve()
+ self.blocks.append(block)
+ self.tip = block.sha256
+ self.block_time += 1
+ height += 1
+
+ # Create a transaction spending the coinbase output with an invalid (null) signature
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b""))
+ tx.vout.append(CTxOut(49*100000000, CScript([OP_TRUE])))
+ tx.calc_sha256()
+
+ block102 = create_block(self.tip, create_coinbase(height), self.block_time)
+ self.block_time += 1
+ block102.vtx.extend([tx])
+ block102.hashMerkleRoot = block102.calc_merkle_root()
+ block102.rehash()
+ block102.solve()
+ self.blocks.append(block102)
+ self.tip = block102.sha256
+ self.block_time += 1
+ height += 1
+
+ # Bury the assumed valid block 2100 deep
+ for i in range(2100):
+ block = create_block(self.tip, create_coinbase(height), self.block_time)
+ block.nVersion = 4
+ block.solve()
+ self.blocks.append(block)
+ self.tip = block.sha256
+ self.block_time += 1
+ height += 1
+
+ # Start node1 and node2 with assumevalid so they accept a block with a bad signature.
+ self.nodes.append(start_node(1, self.options.tmpdir,
+ ["-debug", "-assumevalid=" + hex(block102.sha256)]))
+ node1 = BaseNode() # connects to node1
+ connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1))
+ node1.add_connection(connections[1])
+ node1.wait_for_verack()
+
+ self.nodes.append(start_node(2, self.options.tmpdir,
+ ["-debug", "-assumevalid=" + hex(block102.sha256)]))
+ node2 = BaseNode() # connects to node2
+ connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
+ node2.add_connection(connections[2])
+ node2.wait_for_verack()
+
+ # send header lists to all three nodes
+ node0.send_header_for_blocks(self.blocks[0:2000])
+ node0.send_header_for_blocks(self.blocks[2000:])
+ node1.send_header_for_blocks(self.blocks[0:2000])
+ node1.send_header_for_blocks(self.blocks[2000:])
+ node2.send_header_for_blocks(self.blocks[0:200])
+
+ # Send 102 blocks to node0. Block 102 will be rejected.
+ for i in range(101):
+ node0.send_message(msg_block(self.blocks[i]))
+ node0.sync_with_ping() # make sure the most recent block is synced
+ node0.send_message(msg_block(self.blocks[101]))
+ assert_equal(self.nodes[0].getblock(self.nodes[0].getbestblockhash())['height'], 101)
+
+ # Send 3102 blocks to node1. All blocks will be accepted.
+ for i in range(2202):
+ node1.send_message(msg_block(self.blocks[i]))
+ node1.sync_with_ping() # make sure the most recent block is synced
+ assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
+
+ # Send 102 blocks to node2. Block 102 will be rejected.
+ for i in range(101):
+ node2.send_message(msg_block(self.blocks[i]))
+ node2.sync_with_ping() # make sure the most recent block is synced
+ node2.send_message(msg_block(self.blocks[101]))
+ assert_equal(self.nodes[2].getblock(self.nodes[2].getbestblockhash())['height'], 101)
+
+if __name__ == '__main__':
+ SendHeadersTest().main()
diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py
index e903b2fbf0..ea9c3d73ab 100755
--- a/qa/rpc-tests/bip65-cltv-p2p.py
+++ b/qa/rpc-tests/bip65-cltv-p2p.py
@@ -2,6 +2,19 @@
# Copyright (c) 2015-2016 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 BIP65 (CHECKLOCKTIMEVERIFY).
+
+Connect to a single node.
+Mine 2 (version 3) blocks (save the coinbases for later).
+Generate 98 more version 3 blocks, verify the node accepts.
+Mine 749 version 4 blocks, verify the node accepts.
+Check that the new CLTV rules are not enforced on the 750th version 4 block.
+Check that the new CLTV rules are enforced on the 751st version 4 block.
+Mine 199 new version blocks.
+Mine 1 old-version block.
+Mine 1 new version block.
+Mine 1 old version block, see that the node rejects.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -20,19 +33,6 @@ def cltv_invalidate(tx):
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] +
list(CScript(tx.vin[0].scriptSig)))
-'''
-This test is meant to exercise BIP65 (CHECKLOCKTIMEVERIFY)
-Connect to a single node.
-Mine 2 (version 3) blocks (save the coinbases for later).
-Generate 98 more version 3 blocks, verify the node accepts.
-Mine 749 version 4 blocks, verify the node accepts.
-Check that the new CLTV rules are not enforced on the 750th version 4 block.
-Check that the new CLTV rules are enforced on the 751st version 4 block.
-Mine 199 new version blocks.
-Mine 1 old-version block.
-Mine 1 new version block.
-Mine 1 old version block, see that the node rejects.
-'''
class BIP65Test(ComparisonTestFramework):
diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py
index baa77b92a0..c9d02a98f3 100755
--- a/qa/rpc-tests/bip65-cltv.py
+++ b/qa/rpc-tests/bip65-cltv.py
@@ -2,10 +2,7 @@
# Copyright (c) 2015-2016 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 CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic
-#
+"""Test the CHECKLOCKTIMEVERIFY (BIP65) soft-fork logic."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py
index 55b3e2a04a..836267ea7f 100755
--- a/qa/rpc-tests/bip68-112-113-p2p.py
+++ b/qa/rpc-tests/bip68-112-113-p2p.py
@@ -1,19 +1,9 @@
#!/usr/bin/env python3
-# Copyright (c) 2015 The Bitcoin Core developers
+# Copyright (c) 2015-2016 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 activation of the first version bits soft fork.
-from test_framework.test_framework import ComparisonTestFramework
-from test_framework.util import *
-from test_framework.mininode import ToHex, CTransaction, NetworkThread
-from test_framework.blocktools import create_coinbase, create_block
-from test_framework.comptool import TestInstance, TestManager
-from test_framework.script import *
-from io import BytesIO
-import time
-
-'''
-This test is meant to exercise activation of the first version bits soft fork
This soft fork will activate the following BIPS:
BIP 68 - nSequence relative lock times
BIP 112 - CHECKSEQUENCEVERIFY
@@ -51,7 +41,16 @@ bip112txs_vary_nSequence_9 - 16 txs with nSequence relative_locktimes of 9 evalu
bip112txs_vary_OP_CSV - 16 txs with nSequence = 10 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
bip112txs_vary_OP_CSV_9 - 16 txs with nSequence = 9 evaluated against varying {relative_locktimes of 10} OP_CSV OP_DROP
bip112tx_special - test negative argument to OP_CSV
-'''
+"""
+
+from test_framework.test_framework import ComparisonTestFramework
+from test_framework.util import *
+from test_framework.mininode import ToHex, CTransaction, NetworkThread
+from test_framework.blocktools import create_coinbase, create_block
+from test_framework.comptool import TestInstance, TestManager
+from test_framework.script import *
+from io import BytesIO
+import time
base_relative_locktime = 10
seq_disable_flag = 1<<31
@@ -289,6 +288,7 @@ class BIP68_112_113Test(ComparisonTestFramework):
# BIP113 test transaction will be modified before each use to put in appropriate block time
bip113tx_v1 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98"))
bip113tx_v1.vin[0].nSequence = 0xFFFFFFFE
+ bip113tx_v1.nVersion = 1
bip113tx_v2 = self.create_transaction(self.nodes[0], bip113input, self.nodeaddress, Decimal("49.98"))
bip113tx_v2.vin[0].nSequence = 0xFFFFFFFE
bip113tx_v2.nVersion = 2
diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py
index a12bf10ebd..74ac393fe9 100755
--- a/qa/rpc-tests/bip68-sequence.py
+++ b/qa/rpc-tests/bip68-sequence.py
@@ -2,15 +2,10 @@
# Copyright (c) 2014-2016 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 BIP68 implementation
-#
+"""Test BIP68 implementation."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-from test_framework.script import *
-from test_framework.mininode import *
from test_framework.blocktools import *
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py
index c42ed44c25..70d4be3f69 100755
--- a/qa/rpc-tests/bip9-softforks.py
+++ b/qa/rpc-tests/bip9-softforks.py
@@ -1,21 +1,9 @@
#!/usr/bin/env python3
-# Copyright (c) 2015 The Bitcoin Core developers
+# Copyright (c) 2015-2016 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 BIP 9 soft forks.
-from test_framework.blockstore import BlockStore
-from test_framework.test_framework import ComparisonTestFramework
-from test_framework.util import *
-from test_framework.mininode import CTransaction, NetworkThread
-from test_framework.blocktools import create_coinbase, create_block
-from test_framework.comptool import TestInstance, TestManager
-from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP
-from io import BytesIO
-import time
-import itertools
-
-'''
-This test is meant to exercise BIP forks
Connect to a single node.
regtest lock-in with 108/144 block signalling
activation after a further 144 blocks
@@ -26,8 +14,18 @@ mine 108 blocks signalling readiness and 36 blocks not signalling readiness (STA
mine a further 143 blocks (LOCKED_IN)
test that enforcement has not triggered (which triggers ACTIVE)
test that enforcement has triggered
-'''
+"""
+from test_framework.blockstore import BlockStore
+from test_framework.test_framework import ComparisonTestFramework
+from test_framework.util import *
+from test_framework.mininode import CTransaction, NetworkThread
+from test_framework.blocktools import create_coinbase, create_block
+from test_framework.comptool import TestInstance, TestManager
+from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP
+from io import BytesIO
+import time
+import itertools
class BIP9SoftForksTest(ComparisonTestFramework):
@@ -225,21 +223,21 @@ class BIP9SoftForksTest(ComparisonTestFramework):
return
def csv_invalidate(self, tx):
- '''Modify the signature in vin 0 of the tx to fail CSV
+ """Modify the signature in vin 0 of the tx to fail CSV
Prepends -1 CSV DROP in the scriptSig itself.
- '''
+ """
tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP] +
list(CScript(tx.vin[0].scriptSig)))
def sequence_lock_invalidate(self, tx):
- '''Modify the nSequence to make it fails once sequence lock rule is activated (high timespan)
- '''
+ """Modify the nSequence to make it fails once sequence lock rule is
+ activated (high timespan).
+ """
tx.vin[0].nSequence = 0x00FFFFFF
tx.nLockTime = 0
def mtp_invalidate(self, tx):
- '''Modify the nLockTime to make it fails once MTP rule is activated
- '''
+ """Modify the nLockTime to make it fails once MTP rule is activated."""
# Disable Sequence lock, Activate nLockTime
tx.vin[0].nSequence = 0x90FFFFFF
tx.nLockTime = self.last_block_time
diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py
index 3bad5af5e6..b82ef89395 100755
--- a/qa/rpc-tests/bipdersig-p2p.py
+++ b/qa/rpc-tests/bipdersig-p2p.py
@@ -2,6 +2,19 @@
# Copyright (c) 2015-2016 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 BIP66 (DER SIG).
+
+Connect to a single node.
+Mine 2 (version 2) blocks (save the coinbases for later).
+Generate 98 more version 2 blocks, verify the node accepts.
+Mine 749 version 3 blocks, verify the node accepts.
+Check that the new DERSIG rules are not enforced on the 750th version 3 block.
+Check that the new DERSIG rules are enforced on the 751st version 3 block.
+Mine 199 new version blocks.
+Mine 1 old-version block.
+Mine 1 new version block.
+Mine 1 old version block, see that the node rejects.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -15,10 +28,10 @@ import time
# A canonical signature consists of:
# <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
def unDERify(tx):
- '''
+ """
Make the signature in vin 0 of a tx non-DER-compliant,
by adding padding after the S-value.
- '''
+ """
scriptSig = CScript(tx.vin[0].scriptSig)
newscript = []
for i in scriptSig:
@@ -27,20 +40,6 @@ def unDERify(tx):
else:
newscript.append(i)
tx.vin[0].scriptSig = CScript(newscript)
-
-'''
-This test is meant to exercise BIP66 (DER SIG).
-Connect to a single node.
-Mine 2 (version 2) blocks (save the coinbases for later).
-Generate 98 more version 2 blocks, verify the node accepts.
-Mine 749 version 3 blocks, verify the node accepts.
-Check that the new DERSIG rules are not enforced on the 750th version 3 block.
-Check that the new DERSIG rules are enforced on the 751st version 3 block.
-Mine 199 new version blocks.
-Mine 1 old-version block.
-Mine 1 new version block.
-Mine 1 old version block, see that the node rejects.
-'''
class BIP66Test(ComparisonTestFramework):
diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py
index 17c2ced79a..fa54bc2749 100755
--- a/qa/rpc-tests/bipdersig.py
+++ b/qa/rpc-tests/bipdersig.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 BIP66 changeover logic
-#
+"""Test the BIP66 changeover logic."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py
index 410b85d15e..67b5826840 100755
--- a/qa/rpc-tests/blockchain.py
+++ b/qa/rpc-tests/blockchain.py
@@ -2,11 +2,14 @@
# Copyright (c) 2014-2016 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 RPCs related to blockchainstate.
-#
-# Test RPC calls related to blockchain state. Tests correspond to code in
-# rpc/blockchain.cpp.
-#
+Test the following RPCs:
+ - gettxoutsetinfo
+ - verifychain
+
+Tests correspond to code in rpc/blockchain.cpp.
+"""
from decimal import Decimal
@@ -23,13 +26,6 @@ from test_framework.util import (
class BlockchainTest(BitcoinTestFramework):
- """
- Test blockchain-related RPC calls:
-
- - gettxoutsetinfo
- - verifychain
-
- """
def __init__(self):
super().__init__()
diff --git a/qa/rpc-tests/bumpfee.py b/qa/rpc-tests/bumpfee.py
new file mode 100755
index 0000000000..cc897a32c7
--- /dev/null
+++ b/qa/rpc-tests/bumpfee.py
@@ -0,0 +1,325 @@
+#!/usr/bin/env python3
+# Copyright (c) 2016 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 bumpfee RPC."""
+
+from segwit import send_to_witness
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework import blocktools
+from test_framework.mininode import CTransaction
+from test_framework.util import *
+
+import io
+
+# Sequence number that is BIP 125 opt-in and BIP 68-compliant
+BIP125_SEQUENCE_NUMBER = 0xfffffffd
+
+WALLET_PASSPHRASE = "test"
+WALLET_PASSPHRASE_TIMEOUT = 3600
+
+
+class BumpFeeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+
+ def setup_network(self, split=False):
+ extra_args = [["-debug", "-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
+ for i in range(self.num_nodes)]
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+
+ # Encrypt wallet for test_locked_wallet_fails test
+ self.nodes[1].encryptwallet(WALLET_PASSPHRASE)
+ bitcoind_processes[1].wait()
+ self.nodes[1] = start_node(1, self.options.tmpdir, extra_args[1])
+ self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
+
+ connect_nodes_bi(self.nodes, 0, 1)
+ self.is_network_split = False
+ self.sync_all()
+
+ def run_test(self):
+ peer_node, rbf_node = self.nodes
+ rbf_node_address = rbf_node.getnewaddress()
+
+ # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis)
+ print("Mining blocks...")
+ peer_node.generate(110)
+ self.sync_all()
+ for i in range(25):
+ peer_node.sendtoaddress(rbf_node_address, 0.001)
+ self.sync_all()
+ peer_node.generate(1)
+ self.sync_all()
+ assert_equal(rbf_node.getbalance(), Decimal("0.025"))
+
+ print("Running tests")
+ dest_address = peer_node.getnewaddress()
+ test_small_output_fails(rbf_node, dest_address)
+ test_dust_to_fee(rbf_node, dest_address)
+ test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address)
+ test_segwit_bumpfee_succeeds(rbf_node, dest_address)
+ test_nonrbf_bumpfee_fails(peer_node, dest_address)
+ test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address)
+ test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
+ test_settxfee(rbf_node, dest_address)
+ test_rebumping(rbf_node, dest_address)
+ test_rebumping_not_replaceable(rbf_node, dest_address)
+ test_unconfirmed_not_spendable(rbf_node, rbf_node_address)
+ test_bumpfee_metadata(rbf_node, dest_address)
+ test_locked_wallet_fails(rbf_node, dest_address)
+ print("Success")
+
+
+def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address):
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ rbftx = rbf_node.gettransaction(rbfid)
+ sync_mempools((rbf_node, peer_node))
+ assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["fee"] - abs(rbftx["fee"]) > 0
+ # check that bumped_tx propogates, original tx was evicted and has a wallet conflict
+ sync_mempools((rbf_node, peer_node))
+ assert bumped_tx["txid"] in rbf_node.getrawmempool()
+ assert bumped_tx["txid"] in peer_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+ assert rbfid not in peer_node.getrawmempool()
+ oldwtx = rbf_node.gettransaction(rbfid)
+ assert len(oldwtx["walletconflicts"]) > 0
+ # check wallet transaction replaces and replaced_by values
+ bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"])
+ assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"])
+ assert_equal(bumpedwtx["replaces_txid"], rbfid)
+
+
+def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
+ # Create a transaction with segwit output, then create an RBF transaction
+ # 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.validateaddress(rbf_node.getnewaddress())
+ rbf_node.addwitnessaddress(segwit_out["address"])
+ segwitid = send_to_witness(
+ version=0,
+ node=rbf_node,
+ utxo=segwit_in,
+ pubkey=segwit_out["pubkey"],
+ encode_p2sh=False,
+ amount=Decimal("0.0009"),
+ sign=True)
+
+ rbfraw = rbf_node.createrawtransaction([{
+ 'txid': segwitid,
+ 'vout': 0,
+ "sequence": BIP125_SEQUENCE_NUMBER
+ }], {dest_address: Decimal("0.0005"),
+ get_change_address(rbf_node): Decimal("0.0003")})
+ rbfsigned = rbf_node.signrawtransaction(rbfraw)
+ rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"])
+ assert rbfid in rbf_node.getrawmempool()
+
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["txid"] in rbf_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+
+
+def test_nonrbf_bumpfee_fails(peer_node, dest_address):
+ # cannot replace a non RBF transaction (from node which did not enable RBF)
+ not_rbfid = create_fund_sign_send(peer_node, {dest_address: 0.00090000})
+ assert_raises_message(JSONRPCException, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
+
+
+def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
+ # cannot bump fee unless the tx has only inputs that we own.
+ # here, the rbftx has a peer_node coin and then adds a rbf_node input
+ # Note that this test depends upon the RPC code checking input ownership prior to change outputs
+ # (since it can't use fundrawtransaction, it lacks a proper change output)
+ utxos = [node.listunspent()[-1] for node in (rbf_node, peer_node)]
+ inputs = [{
+ "txid": utxo["txid"],
+ "vout": utxo["vout"],
+ "address": utxo["address"],
+ "sequence": BIP125_SEQUENCE_NUMBER
+ } for utxo in utxos]
+ output_val = sum(utxo["amount"] for utxo in utxos) - Decimal("0.001")
+ rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val})
+ signedtx = rbf_node.signrawtransaction(rawtx)
+ signedtx = peer_node.signrawtransaction(signedtx["hex"])
+ rbfid = rbf_node.sendrawtransaction(signedtx["hex"])
+ assert_raises_message(JSONRPCException, "Transaction contains inputs that don't belong to this wallet",
+ rbf_node.bumpfee, rbfid)
+
+
+def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address):
+ # cannot bump fee if the transaction has a descendant
+ # parent is send-to-self, so we don't have to check which output is change when creating the child tx
+ parent_id = create_fund_sign_send(rbf_node, {rbf_node_address: 0.00050000})
+ tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000})
+ tx = rbf_node.signrawtransaction(tx)
+ txid = rbf_node.sendrawtransaction(tx["hex"])
+ assert_raises_message(JSONRPCException, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
+
+
+def test_small_output_fails(rbf_node, dest_address):
+ # cannot bump fee with a too-small output
+ rbfid = spend_one_input(rbf_node,
+ Decimal("0.00100000"),
+ {dest_address: 0.00080000,
+ get_change_address(rbf_node): Decimal("0.00010000")})
+ rbf_node.bumpfee(rbfid, {"totalFee": 20000})
+
+ rbfid = spend_one_input(rbf_node,
+ Decimal("0.00100000"),
+ {dest_address: 0.00080000,
+ get_change_address(rbf_node): Decimal("0.00010000")})
+ assert_raises_message(JSONRPCException, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001})
+
+
+def test_dust_to_fee(rbf_node, dest_address):
+ # check that if output is reduced to dust, it will be converted to fee
+ # the bumped tx sets fee=9900, but it converts to 10,000
+ rbfid = spend_one_input(rbf_node,
+ Decimal("0.00100000"),
+ {dest_address: 0.00080000,
+ get_change_address(rbf_node): Decimal("0.00010000")})
+ fulltx = rbf_node.getrawtransaction(rbfid, 1)
+ bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 19900})
+ full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1)
+ assert_equal(bumped_tx["fee"], Decimal("0.00020000"))
+ assert_equal(len(fulltx["vout"]), 2)
+ assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated
+
+
+def test_settxfee(rbf_node, dest_address):
+ # check that bumpfee reacts correctly to the use of settxfee (paytxfee)
+ # increase feerate by 2.5x, test that fee increased at least 2x
+ rbf_node.settxfee(Decimal("0.00001000"))
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ rbftx = rbf_node.gettransaction(rbfid)
+ rbf_node.settxfee(Decimal("0.00002500"))
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["fee"] > 2 * abs(rbftx["fee"])
+ rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee
+
+
+def test_rebumping(rbf_node, dest_address):
+ # check that re-bumping the original tx fails, but bumping the bumper succeeds
+ rbf_node.settxfee(Decimal("0.00001000"))
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ bumped = rbf_node.bumpfee(rbfid, {"totalFee": 1000})
+ assert_raises_message(JSONRPCException, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000})
+ rbf_node.bumpfee(bumped["txid"], {"totalFee": 2000})
+
+
+def test_rebumping_not_replaceable(rbf_node, dest_address):
+ # check that re-bumping a non-replaceable bump tx fails
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
+ assert_raises_message(JSONRPCException, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
+ {"totalFee": 20000})
+
+
+def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
+ # check that unconfirmed outputs from bumped transactions are not spendable
+ rbfid = create_fund_sign_send(rbf_node, {rbf_node_address: 0.00090000})
+ rbftx = rbf_node.gettransaction(rbfid)["hex"]
+ assert rbfid in rbf_node.getrawmempool()
+ bumpid = rbf_node.bumpfee(rbfid)["txid"]
+ assert bumpid in rbf_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+
+ # check that outputs from the bump transaction are not spendable
+ # due to the replaces_txid check in CWallet::AvailableCoins
+ assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], [])
+
+ # submit a block with the rbf tx to clear the bump tx out of the mempool,
+ # then call abandon to make sure the wallet doesn't attempt to resubmit the
+ # bump tx, then invalidate the block so the rbf tx will be put back in the
+ # mempool. this makes it possible to check whether the rbf tx outputs are
+ # spendable before the rbf tx is confirmed.
+ block = submit_block_with_tx(rbf_node, rbftx)
+ rbf_node.abandontransaction(bumpid)
+ rbf_node.invalidateblock(block.hash)
+ assert bumpid not in rbf_node.getrawmempool()
+ assert rbfid in rbf_node.getrawmempool()
+
+ # check that outputs from the rbf tx are not spendable before the
+ # transaction is confirmed, due to the replaced_by_txid check in
+ # CWallet::AvailableCoins
+ assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == rbfid], [])
+
+ # check that the main output from the rbf tx is spendable after confirmed
+ rbf_node.generate(1)
+ assert_equal(
+ sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False)
+ if t["txid"] == rbfid and t["address"] == rbf_node_address and t["spendable"]), 1)
+
+
+def test_bumpfee_metadata(rbf_node, dest_address):
+ rbfid = rbf_node.sendtoaddress(dest_address, 0.00090000, "comment value", "to value")
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"])
+ assert_equal(bumped_wtx["comment"], "comment value")
+ assert_equal(bumped_wtx["to"], "to value")
+
+
+def test_locked_wallet_fails(rbf_node, dest_address):
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ rbf_node.walletlock()
+ assert_raises_message(JSONRPCException, "Please enter the wallet passphrase with walletpassphrase first.",
+ rbf_node.bumpfee, rbfid)
+
+
+def create_fund_sign_send(node, outputs):
+ rawtx = node.createrawtransaction([], outputs)
+ fundtx = node.fundrawtransaction(rawtx)
+ signedtx = node.signrawtransaction(fundtx["hex"])
+ txid = node.sendrawtransaction(signedtx["hex"])
+ return txid
+
+
+def spend_one_input(node, input_amount, outputs):
+ input = dict(sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u["amount"] == input_amount))
+ rawtx = node.createrawtransaction([input], outputs)
+ signedtx = node.signrawtransaction(rawtx)
+ txid = node.sendrawtransaction(signedtx["hex"])
+ return txid
+
+
+def get_change_address(node):
+ """Get a wallet change address.
+
+ There is no wallet RPC to access unused change addresses, so this creates a
+ dummy transaction, calls fundrawtransaction to give add an input and change
+ output, then returns the change address."""
+ dest_address = node.getnewaddress()
+ dest_amount = Decimal("0.00012345")
+ rawtx = node.createrawtransaction([], {dest_address: dest_amount})
+ fundtx = node.fundrawtransaction(rawtx)
+ info = node.decoderawtransaction(fundtx["hex"])
+ return next(address for out in info["vout"]
+ if out["value"] != dest_amount for address in out["scriptPubKey"]["addresses"])
+
+
+def submit_block_with_tx(node, tx):
+ ctx = CTransaction()
+ ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx)))
+
+ tip = node.getbestblockhash()
+ height = node.getblockcount() + 1
+ block_time = node.getblockheader(tip)["mediantime"] + 1
+ block = blocktools.create_block(int(tip, 16), blocktools.create_coinbase(height), block_time)
+ block.vtx.append(ctx)
+ block.rehash()
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.solve()
+ error = node.submitblock(bytes_to_hex_str(block.serialize(True)))
+ if error is not None:
+ raise Exception(error)
+ return block
+
+
+if __name__ == "__main__":
+ BumpFeeTest().main()
diff --git a/qa/rpc-tests/create_cache.py b/qa/rpc-tests/create_cache.py
index 1ace6310d0..13eac92bbc 100755
--- a/qa/rpc-tests/create_cache.py
+++ b/qa/rpc-tests/create_cache.py
@@ -2,11 +2,12 @@
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Create a blockchain cache.
-#
-# Helper script to create the cache
-# (see BitcoinTestFramework.setup_chain)
-#
+Creating a cache of the blockchain speeds up test execution when running
+multiple qa tests. This helper script is executed by rpc-tests when multiple
+tests are being run in parallel.
+"""
from test_framework.test_framework import BitcoinTestFramework
diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py
index 24768c2655..5555e96c44 100755
--- a/qa/rpc-tests/decodescript.py
+++ b/qa/rpc-tests/decodescript.py
@@ -2,6 +2,7 @@
# Copyright (c) 2015-2016 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 decoding scripts via decodescript RPC command."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -9,7 +10,6 @@ from test_framework.mininode import *
from io import BytesIO
class DecodeScriptTest(BitcoinTestFramework):
- """Tests decoding scripts via RPC command "decodescript"."""
def __init__(self):
super().__init__()
@@ -111,7 +111,7 @@ class DecodeScriptTest(BitcoinTestFramework):
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
def decoderawtransaction_asm_sighashtype(self):
- """Tests decoding scripts via RPC command "decoderawtransaction".
+ """Test decoding scripts via RPC command "decoderawtransaction".
This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
"""
diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py
index 36c147edad..ff7121659b 100755
--- a/qa/rpc-tests/disablewallet.py
+++ b/qa/rpc-tests/disablewallet.py
@@ -2,10 +2,11 @@
# Copyright (c) 2015-2016 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 a node with the -disablewallet option.
-#
-# Exercise API with -disablewallet.
-#
+- Test that validateaddress RPC works when running with -disablewallet
+- Test that it is not possible to mine to an invalid address.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -24,7 +25,6 @@ class DisableWalletTest (BitcoinTestFramework):
self.sync_all()
def run_test (self):
- # Check regression: https://github.com/bitcoin/bitcoin/issues/6963#issuecomment-154548880
x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
assert(x['isvalid'] == False)
x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py
index a1901aedab..c2724ba5df 100755
--- a/qa/rpc-tests/forknotify.py
+++ b/qa/rpc-tests/forknotify.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 -alertnotify
-#
+"""Test the -alertnotify option."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -22,7 +19,7 @@ class ForkNotifyTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
- with open(self.alert_filename, 'w', encoding='utf8') as f:
+ with open(self.alert_filename, 'w', encoding='utf8'):
pass # Just open then close to create zero-length file
self.nodes.append(start_node(0, self.options.tmpdir,
["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]))
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index 8c45578fcf..7892e85e22 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -2,6 +2,7 @@
# Copyright (c) 2014-2016 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 fundrawtransaction RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -226,7 +227,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert(False)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- out = dec_tx['vout'][0];
+ out = dec_tx['vout'][0]
assert_equal(change, out['scriptPubKey']['addresses'][0])
@@ -469,7 +470,9 @@ class RawTransactionsTest(BitcoinTestFramework):
# locked wallet test
self.nodes[1].encryptwallet("test")
self.nodes.pop(1)
- stop_nodes(self.nodes)
+ stop_node(self.nodes[0], 0)
+ stop_node(self.nodes[1], 2)
+ stop_node(self.nodes[2], 3)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
# This test is not meant to test fee estimation and we'd like
@@ -484,6 +487,23 @@ class RawTransactionsTest(BitcoinTestFramework):
self.is_network_split=False
self.sync_all()
+ # drain the keypool
+ self.nodes[1].getnewaddress()
+ inputs = []
+ outputs = {self.nodes[0].getnewaddress():1.1}
+ rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
+ # fund a transaction that requires a new key for the change output
+ # creating the key must be impossible because the wallet is locked
+ try:
+ fundedTx = self.nodes[1].fundrawtransaction(rawTx)
+ raise AssertionError("Wallet unlocked without passphrase")
+ except JSONRPCException as e:
+ assert('Keypool ran out' in e.error['message'])
+
+ #refill the keypool
+ self.nodes[1].walletpassphrase("test", 100)
+ self.nodes[1].walletlock()
+
try:
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
raise AssertionError("Wallet unlocked without passphrase")
@@ -498,7 +518,7 @@ class RawTransactionsTest(BitcoinTestFramework):
fundedTx = self.nodes[1].fundrawtransaction(rawTx)
#now we need to unlock
- self.nodes[1].walletpassphrase("test", 100)
+ self.nodes[1].walletpassphrase("test", 600)
signedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
txId = self.nodes[1].sendrawtransaction(signedTx['hex'])
self.nodes[1].generate(1)
@@ -634,7 +654,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(len(self.nodes[3].listunspent(1)), 1)
inputs = []
- outputs = {self.nodes[2].getnewaddress() : 1}
+ outputs = {self.nodes[3].getnewaddress() : 1}
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee})
@@ -643,5 +663,101 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
+ #############################
+ # Test address reuse option #
+ #############################
+
+ result3 = self.nodes[3].fundrawtransaction(rawtx, {"reserveChangeKey": False})
+ res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
+ changeaddress = ""
+ for out in res_dec['vout']:
+ if out['value'] > 1.0:
+ changeaddress += out['scriptPubKey']['addresses'][0]
+ assert(changeaddress != "")
+ nextaddr = self.nodes[3].getnewaddress()
+ # frt should not have removed the key from the keypool
+ assert(changeaddress == nextaddr)
+
+ result3 = self.nodes[3].fundrawtransaction(rawtx)
+ res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
+ changeaddress = ""
+ for out in res_dec['vout']:
+ if out['value'] > 1.0:
+ changeaddress += out['scriptPubKey']['addresses'][0]
+ assert(changeaddress != "")
+ nextaddr = self.nodes[3].getnewaddress()
+ # Now the change address key should be removed from the keypool
+ assert(changeaddress != nextaddr)
+
+ ######################################
+ # Test subtractFeeFromOutputs option #
+ ######################################
+
+ # Make sure there is exactly one input so coin selection can't skew the result
+ assert_equal(len(self.nodes[3].listunspent(1)), 1)
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress(): 1}
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = [self.nodes[3].fundrawtransaction(rawtx), # uses min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}),
+ self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee, "subtractFeeFromOutputs": [0]})]
+
+ dec_tx = [self.nodes[3].decoderawtransaction(tx['hex']) for tx in result]
+ output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]
+ change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]
+
+ assert_equal(result[0]['fee'], result[1]['fee'], result[2]['fee'])
+ assert_equal(result[3]['fee'], result[4]['fee'])
+ assert_equal(change[0], change[1])
+ assert_equal(output[0], output[1])
+ assert_equal(output[0], output[2] + result[2]['fee'])
+ assert_equal(change[0] + result[0]['fee'], change[2])
+ assert_equal(output[3], output[4] + result[4]['fee'])
+ assert_equal(change[3] + result[3]['fee'], change[4])
+
+ inputs = []
+ outputs = {self.nodes[2].getnewaddress(): value for value in (1.0, 1.1, 1.2, 1.3)}
+ keys = list(outputs.keys())
+ rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
+
+ result = [self.nodes[3].fundrawtransaction(rawtx),
+ # split the fee between outputs 0, 2, and 3, but not output 1
+ self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3]})]
+
+ dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']),
+ self.nodes[3].decoderawtransaction(result[1]['hex'])]
+
+ # Nested list of non-change output amounts for each transaction
+ output = [[out['value'] for i, out in enumerate(d['vout']) if i != r['changepos']]
+ for d, r in zip(dec_tx, result)]
+
+ # List of differences in output amounts between normal and subtractFee transactions
+ share = [o0 - o1 for o0, o1 in zip(output[0], output[1])]
+
+ # output 1 is the same in both transactions
+ assert_equal(share[1], 0)
+
+ # the other 3 outputs are smaller as a result of subtractFeeFromOutputs
+ assert_greater_than(share[0], 0)
+ assert_greater_than(share[2], 0)
+ assert_greater_than(share[3], 0)
+
+ # outputs 2 and 3 take the same share of the fee
+ assert_equal(share[2], share[3])
+
+ # output 0 takes at least as much share of the fee, and no more than 2 satoshis more, than outputs 2 and 3
+ assert_greater_than_or_equal(share[0], share[2])
+ assert_greater_than_or_equal(share[2] + Decimal(2e-8), share[0])
+
+ # the fee is the same in both transactions
+ assert_equal(result[0]['fee'], result[1]['fee'])
+
+ # the total subtracted from the outputs is equal to the fee
+ assert_equal(share[0] + share[2] + share[3], result[0]['fee'])
+
if __name__ == '__main__':
RawTransactionsTest().main()
diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py
index 3cddf4046a..b73fea0695 100755
--- a/qa/rpc-tests/getblocktemplate_longpoll.py
+++ b/qa/rpc-tests/getblocktemplate_longpoll.py
@@ -2,6 +2,7 @@
# Copyright (c) 2014-2016 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 longpolling with getblocktemplate."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -22,10 +23,6 @@ class LongpollThread(threading.Thread):
self.node.getblocktemplate({'longpollid':self.longpollid})
class GetBlockTemplateLPTest(BitcoinTestFramework):
- '''
- Test longpolling with getblocktemplate.
- '''
-
def __init__(self):
super().__init__()
self.num_nodes = 4
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py
index 7a4f8f8fdc..3b17dfcfb5 100755
--- a/qa/rpc-tests/getblocktemplate_proposals.py
+++ b/qa/rpc-tests/getblocktemplate_proposals.py
@@ -2,6 +2,7 @@
# Copyright (c) 2014-2016 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 block proposals with getblocktemplate."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -66,9 +67,6 @@ def assert_template(node, tmpl, txlist, expect):
raise AssertionError('unexpected: %s' % (rsp,))
class GetBlockTemplateProposalTest(BitcoinTestFramework):
- '''
- Test block proposals with getblocktemplate.
- '''
def __init__(self):
super().__init__()
diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py
index 1c66b8c289..14222334a6 100755
--- a/qa/rpc-tests/getchaintips.py
+++ b/qa/rpc-tests/getchaintips.py
@@ -2,10 +2,13 @@
# Copyright (c) 2014-2016 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 getchaintips RPC.
-# Exercise the getchaintips API. We introduce a network split, work
-# on chains of different lengths, and join the network together again.
-# This gives us two tips, verify that it works.
+- introduce a network split
+- work on chains of different lengths
+- join the network together again
+- verify that getchaintips now returns two chain tips.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
index 10bc927e1a..8f35f0ab87 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/qa/rpc-tests/httpbasics.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 http basics
-#
+"""Test the RPC HTTP basics."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/import-rescan.py b/qa/rpc-tests/import-rescan.py
new file mode 100755
index 0000000000..7ca61824c9
--- /dev/null
+++ b/qa/rpc-tests/import-rescan.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-2016 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 wallet import RPCs.
+
+Test rescan behavior of importaddress, importpubkey, importprivkey, and
+importmulti RPCs with different types of keys and rescan options.
+
+In the first part of the test, node 1 creates an address for each type of
+import RPC call and node 0 sends BTC to it. Then other nodes import the
+addresses, and the test makes listtransactions and getbalance calls to confirm
+that the importing node either did or did not execute rescans picking up the
+send transactions.
+
+In the second part of the test, node 0 sends more BTC to each address, and the
+test makes more listtransactions and getbalance calls to confirm that the
+importing nodes pick up the new transactions regardless of whether rescans
+happened previously.
+"""
+
+from test_framework.authproxy import JSONRPCException
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal, set_node_times)
+from decimal import Decimal
+
+import collections
+import enum
+import itertools
+
+Call = enum.Enum("Call", "single multi")
+Data = enum.Enum("Data", "address pub priv")
+Rescan = enum.Enum("Rescan", "no yes late_timestamp")
+
+
+class Variant(collections.namedtuple("Variant", "call data rescan prune")):
+ """Helper for importing one key and verifying scanned transactions."""
+
+ def do_import(self, timestamp):
+ """Call one key import RPC."""
+
+ if self.call == Call.single:
+ if self.data == Data.address:
+ response, error = try_rpc(self.node.importaddress, self.address["address"], self.label,
+ self.rescan == Rescan.yes)
+ elif self.data == Data.pub:
+ response, error = try_rpc(self.node.importpubkey, self.address["pubkey"], self.label,
+ self.rescan == Rescan.yes)
+ elif self.data == Data.priv:
+ response, error = try_rpc(self.node.importprivkey, self.key, self.label, self.rescan == Rescan.yes)
+ assert_equal(response, None)
+ assert_equal(error, {'message': 'Rescan is disabled in pruned mode',
+ 'code': -4} if self.expect_disabled else None)
+ elif self.call == Call.multi:
+ response = self.node.importmulti([{
+ "scriptPubKey": {
+ "address": self.address["address"]
+ },
+ "timestamp": timestamp + RESCAN_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 getbalance/listtransactions return expected values."""
+
+ balance = self.node.getbalance(self.label, 0, True)
+ assert_equal(balance, self.expected_balance)
+
+ txs = self.node.listtransactions(self.label, 10000, 0, True)
+ assert_equal(len(txs), self.expected_txs)
+
+ if txid is not None:
+ tx, = [tx for tx in txs if tx["txid"] == txid]
+ assert_equal(tx["account"], 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)
+ # Verify the transaction is correctly marked watchonly depending on
+ # whether the transaction pays to an imported public key or
+ # imported private key. The test setup ensures that transaction
+ # inputs will not be from watchonly keys (important because
+ # involvesWatchonly will be true if either the transaction output
+ # or inputs are watchonly).
+ if self.data != Data.priv:
+ assert_equal(tx["involvesWatchonly"], True)
+ else:
+ assert_equal("involvesWatchonly" not in tx, True)
+
+
+# List of Variants for each way a key or address could be imported.
+IMPORT_VARIANTS = [Variant(*variants) for variants in itertools.product(Call, Data, Rescan, (False, True))]
+
+# List of nodes to import keys to. Half the nodes will have pruning disabled,
+# half will have it enabled. Different nodes will be used for imports that are
+# expected to cause rescans, and imports that are not expected to cause
+# rescans, in order to prevent rescans during later imports picking up
+# transactions associated with earlier imports. This makes it easier to keep
+# track of expected balances and transactions.
+ImportNode = collections.namedtuple("ImportNode", "prune rescan")
+IMPORT_NODES = [ImportNode(*fields) for fields in itertools.product((False, True), repeat=2)]
+
+# Rescans start at the earliest block up to 2 hours before the key timestamp.
+RESCAN_WINDOW = 2 * 60 * 60
+
+
+class ImportRescanTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2 + len(IMPORT_NODES)
+
+ def setup_network(self):
+ extra_args = [["-debug=1"] for _ in range(self.num_nodes)]
+ for i, import_node in enumerate(IMPORT_NODES, 2):
+ if import_node.prune:
+ extra_args[i] += ["-prune=1"]
+
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ for i in range(1, self.num_nodes):
+ connect_nodes(self.nodes[i], 0)
+
+ def run_test(self):
+ # Create one transaction on node 0 with a unique amount and label for
+ # each possible type of wallet import RPC.
+ for i, variant in enumerate(IMPORT_VARIANTS):
+ variant.label = "label {} {}".format(i, variant)
+ variant.address = self.nodes[1].validateaddress(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_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
+
+ # Generate a block containing the initial transactions, then another
+ # block further in the future (past the rescan window).
+ self.nodes[0].generate(1)
+ assert_equal(self.nodes[0].getrawmempool(), [])
+ timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
+ set_node_times(self.nodes, timestamp + RESCAN_WINDOW + 1)
+ self.nodes[0].generate(1)
+ sync_blocks(self.nodes)
+
+ # For each variation of wallet key import, invoke the import RPC and
+ # check the results from getbalance and listtransactions.
+ for variant in IMPORT_VARIANTS:
+ variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single
+ expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled
+ variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))]
+ variant.do_import(timestamp)
+ if expect_rescan:
+ variant.expected_balance = variant.initial_amount
+ variant.expected_txs = 1
+ variant.check(variant.initial_txid, variant.initial_amount, 2)
+ else:
+ variant.expected_balance = 0
+ variant.expected_txs = 0
+ variant.check()
+
+ # Create new transactions sending to each address.
+ fee = self.nodes[0].getnetworkinfo()["relayfee"]
+ for i, variant in enumerate(IMPORT_VARIANTS):
+ variant.sent_amount = 10 - (2 * i + 1) / 8.0
+ variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
+
+ # Generate a block containing the new transactions.
+ self.nodes[0].generate(1)
+ assert_equal(self.nodes[0].getrawmempool(), [])
+ sync_blocks(self.nodes)
+
+ # Check the latest results from getbalance and listtransactions.
+ for variant in IMPORT_VARIANTS:
+ if not variant.expect_disabled:
+ variant.expected_balance += variant.sent_amount
+ variant.expected_txs += 1
+ variant.check(variant.sent_txid, variant.sent_amount, 1)
+ else:
+ variant.check()
+
+
+def try_rpc(func, *args, **kwargs):
+ try:
+ return func(*args, **kwargs), None
+ except JSONRPCException as e:
+ return None, e.error
+
+
+if __name__ == "__main__":
+ ImportRescanTest().main()
diff --git a/qa/rpc-tests/importmulti.py b/qa/rpc-tests/importmulti.py
index 5c536f2f49..015336effe 100755
--- a/qa/rpc-tests/importmulti.py
+++ b/qa/rpc-tests/importmulti.py
@@ -2,7 +2,7 @@
# Copyright (c) 2014-2016 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 importmulti RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -20,6 +20,7 @@ class ImportMultiTest (BitcoinTestFramework):
print ("Mining blocks...")
self.nodes[0].generate(1)
self.nodes[1].generate(1)
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
# keyword definition
PRIV_KEY = 'privkey'
@@ -52,31 +53,48 @@ class ImportMultiTest (BitcoinTestFramework):
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": address['address']
- }
+ },
+ "timestamp": "now",
}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
+ watchonly_address = address['address']
+ watchonly_timestamp = timestamp
+ print("Should not import an invalid address")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": "not valid address",
+ },
+ "timestamp": "now",
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -5)
+ assert_equal(result[0]['error']['message'], 'Invalid address')
# ScriptPubKey + internal
print("Should import a scriptPubKey with internal flag")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
"internal": True
}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
# ScriptPubKey + !internal
print("Should not import a scriptPubKey without internal flag")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
- "scriptPubKey": address['scriptPubKey']
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
}])
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
@@ -84,6 +102,7 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(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
@@ -93,12 +112,14 @@ class ImportMultiTest (BitcoinTestFramework):
"scriptPubKey": {
"address": address['address']
},
+ "timestamp": "now",
"pubkeys": [ address['pubkey'] ]
}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
# ScriptPubKey + Public key + internal
@@ -106,22 +127,25 @@ class ImportMultiTest (BitcoinTestFramework):
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
request = [{
"scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
"pubkeys": [ address['pubkey'] ],
"internal": True
- }];
+ }]
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], timestamp)
# ScriptPubKey + Public key + !internal
print("Should not import a scriptPubKey without internal and with public key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
request = [{
"scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
"pubkeys": [ address['pubkey'] ]
- }];
+ }]
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
@@ -129,6 +153,7 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
# Address + Private key + !watchonly
print("Should import an address with private key")
@@ -137,12 +162,14 @@ class ImportMultiTest (BitcoinTestFramework):
"scriptPubKey": {
"address": address['address']
},
+ "timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], True)
+ assert_equal(address_assert['timestamp'], timestamp)
# Address + Private key + watchonly
print("Should not import an address with private key and with watchonly")
@@ -151,6 +178,7 @@ class ImportMultiTest (BitcoinTestFramework):
"scriptPubKey": {
"address": address['address']
},
+ "timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
"watchonly": True
}])
@@ -160,12 +188,14 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
# ScriptPubKey + Private key + internal
print("Should import a scriptPubKey with internal and with private key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address['address']) ],
"internal": True
}])
@@ -173,12 +203,14 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], True)
+ assert_equal(address_assert['timestamp'], timestamp)
# ScriptPubKey + Private key + !internal
print("Should not import a scriptPubKey without internal and with private key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address['address']) ]
}])
assert_equal(result[0]['success'], False)
@@ -187,6 +219,7 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
# P2SH address
@@ -197,18 +230,21 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
- }
+ },
+ "timestamp": "now",
}])
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
assert_equal(address_assert['isscript'], True)
assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['timestamp'], timestamp)
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
assert_equal(p2shunspent['spendable'], False)
assert_equal(p2shunspent['solvable'], False)
@@ -222,16 +258,20 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh with respective redeem script")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
},
+ "timestamp": "now",
"redeemscript": multi_sig_script['redeemScript']
}])
assert_equal(result[0]['success'], True)
+ address_assert = self.nodes[1].validateaddress(multi_sig_script['address'])
+ assert_equal(address_assert['timestamp'], timestamp)
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
assert_equal(p2shunspent['spendable'], False)
@@ -246,17 +286,21 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
},
+ "timestamp": "now",
"redeemscript": 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].validateaddress(multi_sig_script['address'])
+ assert_equal(address_assert['timestamp'], timestamp)
p2shunspent = self.nodes[1].listunspent(0,999999, [multi_sig_script['address']])[0]
assert_equal(p2shunspent['spendable'], False)
@@ -270,13 +314,14 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
},
+ "timestamp": "now",
"redeemscript": multi_sig_script['redeemScript'],
"keys": [ self.nodes[0].dumpprivkey(sig_address_1['address']), self.nodes[0].dumpprivkey(sig_address_2['address'])],
"watchonly": True
@@ -294,6 +339,7 @@ class ImportMultiTest (BitcoinTestFramework):
"scriptPubKey": {
"address": address['address']
},
+ "timestamp": "now",
"pubkeys": [ address2['pubkey'] ]
}])
assert_equal(result[0]['success'], False)
@@ -302,6 +348,7 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
# ScriptPubKey + Public key + internal + Wrong pubkey
@@ -310,9 +357,10 @@ class ImportMultiTest (BitcoinTestFramework):
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
request = [{
"scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
"pubkeys": [ address2['pubkey'] ],
"internal": True
- }];
+ }]
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -5)
@@ -320,6 +368,7 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
# Address + Private key + !watchonly + Wrong private key
@@ -330,6 +379,7 @@ class ImportMultiTest (BitcoinTestFramework):
"scriptPubKey": {
"address": address['address']
},
+ "timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ]
}])
assert_equal(result[0]['success'], False)
@@ -338,6 +388,7 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
# ScriptPubKey + Private key + internal + Wrong private key
@@ -346,6 +397,7 @@ class ImportMultiTest (BitcoinTestFramework):
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
+ "timestamp": "now",
"keys": [ self.nodes[0].dumpprivkey(address2['address']) ],
"internal": True
}])
@@ -355,6 +407,28 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(address['address'])
assert_equal(address_assert['iswatchonly'], False)
assert_equal(address_assert['ismine'], False)
+ assert_equal('timestamp' in address_assert, False)
+
+ # restart nodes to check for proper serialization/deserialization of watch only address
+ stop_nodes(self.nodes)
+ self.nodes = start_nodes(2, self.options.tmpdir)
+ address_assert = self.nodes[1].validateaddress(watchonly_address)
+ assert_equal(address_assert['iswatchonly'], True)
+ assert_equal(address_assert['ismine'], False)
+ assert_equal(address_assert['timestamp'], watchonly_timestamp);
+
+ # Bad or missing timestamps
+ print("Should throw on invalid or missing timestamp values")
+ assert_raises_message(JSONRPCException, 'Missing required timestamp field for key',
+ self.nodes[1].importmulti, [{
+ "scriptPubKey": address['scriptPubKey'],
+ }])
+ assert_raises_message(JSONRPCException, 'Expected number or "now" timestamp value for key. got type string',
+ self.nodes[1].importmulti, [{
+ "scriptPubKey": address['scriptPubKey'],
+ "timestamp": "",
+ }])
+
if __name__ == '__main__':
ImportMultiTest ().main ()
diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py
index 0dee8ad4ec..a941124656 100755
--- a/qa/rpc-tests/importprunedfunds.py
+++ b/qa/rpc-tests/importprunedfunds.py
@@ -2,7 +2,7 @@
# Copyright (c) 2014-2016 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 importprunedfunds and removeprunedfunds RPCs."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/invalidateblock.py b/qa/rpc-tests/invalidateblock.py
index 0faadd33ab..92e65927d5 100755
--- a/qa/rpc-tests/invalidateblock.py
+++ b/qa/rpc-tests/invalidateblock.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 InvalidateBlock code
-#
+"""Test the invalidateblock RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/invalidblockrequest.py b/qa/rpc-tests/invalidblockrequest.py
index 3d8107a76c..eabc0db8df 100755
--- a/qa/rpc-tests/invalidblockrequest.py
+++ b/qa/rpc-tests/invalidblockrequest.py
@@ -2,6 +2,14 @@
# Copyright (c) 2015-2016 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 blocks.
+
+In this test we connect to one node over p2p, and test block requests:
+1) Valid blocks should be requested and become chain tip.
+2) Invalid block with duplicated transaction should be re-requested.
+3) Invalid block with bad coinbase value should be rejected and not
+re-requested.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -10,15 +18,6 @@ from test_framework.blocktools import *
import copy
import time
-
-'''
-In this test we connect to one node over p2p, and test block requests:
-1) Valid blocks should be requested and become chain tip.
-2) Invalid block with duplicated transaction should be re-requested.
-3) Invalid block with bad coinbase value should be rejected and not
-re-requested.
-'''
-
# Use the ComparisonTestFramework with 1 node: only use --testbinary.
class InvalidBlockRequestTest(ComparisonTestFramework):
diff --git a/qa/rpc-tests/invalidtxrequest.py b/qa/rpc-tests/invalidtxrequest.py
index 93205d79de..a9ac231f09 100755
--- a/qa/rpc-tests/invalidtxrequest.py
+++ b/qa/rpc-tests/invalidtxrequest.py
@@ -2,6 +2,10 @@
# Copyright (c) 2015-2016 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 transactions.
+
+In this test we connect to one node over p2p, and test tx requests.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.comptool import TestManager, TestInstance, RejectResult
@@ -9,9 +13,6 @@ from test_framework.blocktools import *
import time
-'''
-In this test we connect to one node over p2p, and test tx requests.
-'''
# Use the ComparisonTestFramework with 1 node: only use --testbinary.
class InvalidTxRequestTest(ComparisonTestFramework):
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
index fa39476568..4b9936a1fd 100755
--- a/qa/rpc-tests/keypool.py
+++ b/qa/rpc-tests/keypool.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# Exercise the wallet keypool, and interaction with wallet encryption/locking
+"""Test the wallet keypool and interaction with wallet encryption/locking."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/listsinceblock.py b/qa/rpc-tests/listsinceblock.py
new file mode 100755
index 0000000000..88304af5b0
--- /dev/null
+++ b/qa/rpc-tests/listsinceblock.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 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 listsincelast RPC."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class ListSinceBlockTest (BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
+
+ def run_test (self):
+ '''
+ `listsinceblock` did not behave correctly when handed a block that was
+ no longer in the main chain:
+
+ ab0
+ / \
+ aa1 [tx0] bb1
+ | |
+ aa2 bb2
+ | |
+ aa3 bb3
+ |
+ bb4
+
+ Consider a client that has only seen block `aa3` above. It asks the node
+ to `listsinceblock aa3`. But at some point prior the main chain switched
+ to the bb chain.
+
+ Previously: listsinceblock would find height=4 for block aa3 and compare
+ this to height=5 for the tip of the chain (bb4). It would then return
+ results restricted to bb3-bb4.
+
+ Now: listsinceblock finds the fork at ab0 and returns results in the
+ range bb1-bb4.
+
+ This test only checks that [tx0] is present.
+ '''
+
+ assert_equal(self.is_network_split, False)
+ self.nodes[2].generate(101)
+ self.sync_all()
+
+ assert_equal(self.nodes[0].getbalance(), 0)
+ assert_equal(self.nodes[1].getbalance(), 0)
+ assert_equal(self.nodes[2].getbalance(), 50)
+ assert_equal(self.nodes[3].getbalance(), 0)
+
+ # Split network into two
+ self.split_network()
+ assert_equal(self.is_network_split, True)
+
+ # send to nodes[0] from nodes[2]
+ senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+
+ # generate on both sides
+ lastblockhash = self.nodes[1].generate(6)[5]
+ self.nodes[2].generate(7)
+ print('lastblockhash=%s' % (lastblockhash))
+
+ self.sync_all()
+
+ self.join_network()
+
+ # listsinceblock(lastblockhash) should now include tx, as seen from nodes[0]
+ lsbres = self.nodes[0].listsinceblock(lastblockhash)
+ found = False
+ for tx in lsbres['transactions']:
+ if tx['txid'] == senttx:
+ found = True
+ break
+ assert_equal(found, True)
+
+if __name__ == '__main__':
+ ListSinceBlockTest().main()
diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py
index 5ec6ce17e0..92fb96c809 100755
--- a/qa/rpc-tests/listtransactions.py
+++ b/qa/rpc-tests/listtransactions.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# Exercise the listtransactions API
+"""Test the listtransactions API."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py
index 1df1c484be..8ea405b4d5 100755
--- a/qa/rpc-tests/maxblocksinflight.py
+++ b/qa/rpc-tests/maxblocksinflight.py
@@ -2,18 +2,19 @@
# Copyright (c) 2015-2016 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 nodes responses to having many blocks in flight.
+
+In this test we connect to one node over p2p, send it numerous inv's, and
+compare the resulting number of getdata requests to a max allowed value. We
+test for exceeding 128 blocks in flight, which was the limit an 0.9 client will
+reach. [0.10 clients shouldn't request more than 16 from a single peer.]
+"""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
import logging
-'''
-In this test we connect to one node over p2p, send it numerous inv's, and
-compare the resulting number of getdata requests to a max allowed value. We
-test for exceeding 128 blocks in flight, which was the limit an 0.9 client will
-reach. [0.10 clients shouldn't request more than 16 from a single peer.]
-'''
MAX_REQUESTS = 128
class TestManager(NodeConnCB):
diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index 83168a7ce7..757aa60afd 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -2,21 +2,19 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-import time
-
-'''
-Test behavior of -maxuploadtarget.
+"""Test behavior of -maxuploadtarget.
* Verify that getdata requests for old blocks (>1week) are dropped
if uploadtarget has been reached.
* Verify that getdata requests for recent blocks are respecteved even
if uploadtarget has been reached.
* Verify that the upload counters are reset after 24 hours.
-'''
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+import time
# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
# p2p messages to a node, generating the messages in the main testing logic.
@@ -86,6 +84,9 @@ class MaxUploadTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 1
+ # Cache for utxos, as the listunspent may take a long time later in the test
+ self.utxo_cache = []
+
def setup_network(self):
# Start a node with maxuploadtarget of 200 MB (/24h)
self.nodes = []
@@ -118,7 +119,7 @@ class MaxUploadTest(BitcoinTestFramework):
# Test logic begins here
# Now mine a big block
- mine_large_block(self.nodes[0])
+ mine_large_block(self.nodes[0], self.utxo_cache)
# Store the hash; we'll request this later
big_old_block = self.nodes[0].getbestblockhash()
@@ -129,7 +130,7 @@ class MaxUploadTest(BitcoinTestFramework):
self.nodes[0].setmocktime(int(time.time()) - 2*60*60*24)
# Mine one more block, so that the prior block looks old
- mine_large_block(self.nodes[0])
+ mine_large_block(self.nodes[0], self.utxo_cache)
# We'll be requesting this new block too
big_new_block = self.nodes[0].getbestblockhash()
diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py
index 4438c152df..8fae92ad2b 100755
--- a/qa/rpc-tests/mempool_limit.py
+++ b/qa/rpc-tests/mempool_limit.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-2016 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 mempool limiting together/eviction with the wallet
+"""Test mempool limiting together/eviction with the wallet."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -26,7 +25,7 @@ class MempoolLimitTest(BitcoinTestFramework):
def run_test(self):
txids = []
- utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 90)
+ utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 91)
#create a mempool tx that will be evicted
us0 = utxos.pop()
@@ -41,9 +40,9 @@ class MempoolLimitTest(BitcoinTestFramework):
relayfee = self.nodes[0].getnetworkinfo()['relayfee']
base_fee = relayfee*100
- for i in range (4):
+ for i in range (3):
txids.append([])
- txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], (i+1)*base_fee)
+ txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], 30, (i+1)*base_fee)
# by now, the tx should be evicted, check confirmation state
assert(txid not in self.nodes[0].getrawmempool())
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 45dc0e65c4..388889d07c 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-2016 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 descendant package tracking code
+"""Test descendant package tracking code."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -20,8 +19,8 @@ class MempoolPackagesTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-relaypriority=0", "-debug"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-relaypriority=0", "-limitancestorcount=5", "-debug"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug"]))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-limitancestorcount=5", "-debug"]))
connect_nodes(self.nodes[0], 1)
self.is_network_split = False
self.sync_all()
diff --git a/qa/rpc-tests/mempool_reorg.py b/qa/rpc-tests/mempool_reorg.py
index 301b094eb0..2cd5573277 100755
--- a/qa/rpc-tests/mempool_reorg.py
+++ b/qa/rpc-tests/mempool_reorg.py
@@ -2,11 +2,11 @@
# Copyright (c) 2014-2016 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 mempool re-org scenarios.
-#
-# Test re-org scenarios with a mempool that contains transactions
-# that spend (directly or indirectly) coinbase transactions.
-#
+Test re-org scenarios with a mempool that contains transactions
+that spend (directly or indirectly) coinbase transactions.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -55,7 +55,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
# Create a block-height-locked transaction which will be invalid after reorg
timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99})
# Set the time lock
- timelock_tx = timelock_tx.replace("ffffffff", "11111111", 1)
+ timelock_tx = timelock_tx.replace("ffffffff", "11111191", 1)
timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000"
timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"]
assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx)
diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py
index 3db12cbf76..c7f37aaa44 100755
--- a/qa/rpc-tests/mempool_resurrect_test.py
+++ b/qa/rpc-tests/mempool_resurrect_test.py
@@ -2,11 +2,7 @@
# Copyright (c) 2014-2016 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 resurrection of mined transactions when
-# the blockchain is re-organized.
-#
+"""Test resurrection of mined transactions when the blockchain is re-organized."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
index d5e4bf52d2..da8485e2a2 100755
--- a/qa/rpc-tests/mempool_spendcoinbase.py
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -2,16 +2,15 @@
# Copyright (c) 2014-2016 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 spending coinbase transactions.
-# The coinbase transaction in block N can appear in block
-# N+100... so is valid in the mempool when the best block
-# height is N+99.
-# This test makes sure coinbase spends that will be mature
-# in the next block are accepted into the memory pool,
-# but less mature coinbase spends are NOT.
-#
+"""Test spending coinbase transactions.
+
+The coinbase transaction in block N can appear in block
+N+100... so is valid in the mempool when the best block
+height is N+99.
+This test makes sure coinbase spends that will be mature
+in the next block are accepted into the memory pool,
+but less mature coinbase spends are NOT.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py
index b2155d7fc3..c4b45425d7 100755
--- a/qa/rpc-tests/merkle_blocks.py
+++ b/qa/rpc-tests/merkle_blocks.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 merkleblock fetch/validation
-#
+"""Test gettxoutproof and verifytxoutproof RPCs."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py
index 95d9090ce2..3b74bf1c46 100755
--- a/qa/rpc-tests/multi_rpc.py
+++ b/qa/rpc-tests/multi_rpc.py
@@ -2,10 +2,7 @@
# Copyright (c) 2015-2016 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 multiple rpc user config option rpcauth
-#
+"""Test multiple RPC users."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import str_to_b64str, assert_equal
diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py
index e9682c4908..89059d2760 100755
--- a/qa/rpc-tests/nodehandling.py
+++ b/qa/rpc-tests/nodehandling.py
@@ -2,15 +2,11 @@
# Copyright (c) 2014-2016 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 handling
-#
+"""Test node handling."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import http.client
import urllib.parse
class NodeHandlingTest (BitcoinTestFramework):
diff --git a/qa/rpc-tests/nulldummy.py b/qa/rpc-tests/nulldummy.py
index 54b7eac376..66c4e90f21 100755
--- a/qa/rpc-tests/nulldummy.py
+++ b/qa/rpc-tests/nulldummy.py
@@ -2,6 +2,16 @@
# Copyright (c) 2016 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 NULLDUMMY softfork.
+
+Connect to a single node.
+Generate 2 blocks (save the coinbases for later).
+Generate 427 more blocks.
+[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block.
+[Policy] Check that non-NULLDUMMY transactions are rejected before activation.
+[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.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -25,17 +35,6 @@ def trueDummy(tx):
tx.vin[0].scriptSig = CScript(newscript)
tx.rehash()
-'''
-This test is meant to exercise NULLDUMMY softfork.
-Connect to a single node.
-Generate 2 blocks (save the coinbases for later).
-Generate 427 more blocks.
-[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block.
-[Policy] Check that non-NULLDUMMY transactions are rejected before activation.
-[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.
-'''
-
class NULLDUMMYTest(BitcoinTestFramework):
def __init__(self):
diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py
index 015ec34eff..2f21fa149a 100755
--- a/qa/rpc-tests/p2p-acceptblock.py
+++ b/qa/rpc-tests/p2p-acceptblock.py
@@ -2,15 +2,7 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-import time
-from test_framework.blocktools import create_block, create_coinbase
-
-'''
-AcceptBlockTest -- test processing of unrequested blocks.
+"""Test processing of unrequested blocks.
Since behavior differs when receiving unrequested blocks from whitelisted peers
versus non-whitelisted peers, this tests the behavior of both (effectively two
@@ -54,7 +46,13 @@ The test:
7. Send Node0 the missing block again.
Node0 should process and the tip should advance.
-'''
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+import time
+from test_framework.blocktools import create_block, create_coinbase
# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
# p2p messages to a node, generating the messages in the main testing logic.
diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py
index ab4b809ded..79561f35f7 100755
--- a/qa/rpc-tests/p2p-compactblocks.py
+++ b/qa/rpc-tests/p2p-compactblocks.py
@@ -2,21 +2,18 @@
# Copyright (c) 2016 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 compact blocks (BIP 152).
+
+Version 1 compact blocks are pre-segwit (txids)
+Version 2 compact blocks are post-segwit (wtxids)
+"""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
-from test_framework.siphash import siphash256
from test_framework.script import CScript, OP_TRUE
-'''
-CompactBlocksTest -- test compact blocks (BIP 152)
-
-Version 1 compact blocks are pre-segwit (txids)
-Version 2 compact blocks are post-segwit (wtxids)
-'''
-
# TestNode: A peer we use to send messages to bitcoind, and store responses.
class TestNode(SingleNodeConnCB):
def __init__(self):
@@ -310,6 +307,9 @@ class CompactBlocksTest(BitcoinTestFramework):
tip = int(node.getbestblockhash(), 16)
assert(test_node.wait_for_block_announcement(tip))
+ # Make sure we will receive a fast-announce compact block
+ self.request_cb_announcements(test_node, node, version)
+
# Now mine a block, and look at the resulting compact block.
test_node.clear_block_announcement()
block_hash = int(node.generate(1)[0], 16)
@@ -319,27 +319,36 @@ class CompactBlocksTest(BitcoinTestFramework):
[tx.calc_sha256() for tx in block.vtx]
block.rehash()
- # Don't care which type of announcement came back for this test; just
- # request the compact block if we didn't get one yet.
+ # Wait until the block was announced (via compact blocks)
wait_until(test_node.received_block_announcement, timeout=30)
assert(test_node.received_block_announcement())
+ # Now fetch and check the compact block
+ header_and_shortids = None
with mininode_lock:
- if test_node.last_cmpctblock is None:
- test_node.clear_block_announcement()
- inv = CInv(4, block_hash) # 4 == "CompactBlock"
- test_node.send_message(msg_getdata([inv]))
+ assert(test_node.last_cmpctblock is not None)
+ # Convert the on-the-wire representation to absolute indexes
+ header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
+ self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
+
+ # Now fetch the compact block using a normal non-announce getdata
+ with mininode_lock:
+ test_node.clear_block_announcement()
+ inv = CInv(4, block_hash) # 4 == "CompactBlock"
+ test_node.send_message(msg_getdata([inv]))
wait_until(test_node.received_block_announcement, timeout=30)
assert(test_node.received_block_announcement())
- # Now we should have the compactblock
+ # Now fetch and check the compact block
header_and_shortids = None
with mininode_lock:
assert(test_node.last_cmpctblock is not None)
# Convert the on-the-wire representation to absolute indexes
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
+ self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
+ def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):
# Check that we got the right block!
header_and_shortids.header.calc_sha256()
assert_equal(header_and_shortids.header.sha256, block_hash)
@@ -764,6 +773,54 @@ class CompactBlocksTest(BitcoinTestFramework):
msg.announce = True
peer.send_and_ping(msg)
+ def test_compactblock_reconstruction_multiple_peers(self, node, stalling_peer, delivery_peer):
+ assert(len(self.utxos))
+
+ def announce_cmpct_block(node, peer):
+ utxo = self.utxos.pop(0)
+ block = self.build_block_with_transactions(node, utxo, 5)
+
+ cmpct_block = HeaderAndShortIDs()
+ cmpct_block.initialize_from_block(block)
+ msg = msg_cmpctblock(cmpct_block.to_p2p())
+ peer.send_and_ping(msg)
+ with mininode_lock:
+ assert(peer.last_getblocktxn is not None)
+ return block, cmpct_block
+
+ block, cmpct_block = announce_cmpct_block(node, stalling_peer)
+
+ for tx in block.vtx[1:]:
+ delivery_peer.send_message(msg_tx(tx))
+ delivery_peer.sync_with_ping()
+ mempool = node.getrawmempool()
+ for tx in block.vtx[1:]:
+ assert(tx.hash in mempool)
+
+ delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+
+ # Now test that delivering an invalid compact block won't break relay
+
+ block, cmpct_block = announce_cmpct_block(node, stalling_peer)
+ for tx in block.vtx[1:]:
+ 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[0].scriptWitness.stack = [ser_uint256(0)]
+
+ cmpct_block.use_witness = True
+ delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ assert(int(node.getbestblockhash(), 16) != block.sha256)
+
+ msg = msg_blocktxn()
+ msg.block_transactions.blockhash = block.sha256
+ msg.block_transactions.transactions = block.vtx[1:]
+ stalling_peer.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
def run_test(self):
# Setup the p2p connections and start up the network thread.
@@ -848,6 +905,10 @@ class CompactBlocksTest(BitcoinTestFramework):
self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False)
self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False)
+ print("\tTesting reconstructing compact blocks from all peers...")
+ self.test_compactblock_reconstruction_multiple_peers(self.nodes[1], self.segwit_node, self.old_node)
+ sync_blocks(self.nodes)
+
# Advance to segwit activation
print ("\nAdvancing to segwit activation\n")
self.activate_segwit(self.nodes[1])
diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py
index 96d99d38a7..1c62961db0 100755
--- a/qa/rpc-tests/p2p-feefilter.py
+++ b/qa/rpc-tests/p2p-feefilter.py
@@ -2,16 +2,13 @@
# Copyright (c) 2016 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 processing of feefilter messages."""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
import time
-'''
-FeeFilterTest -- test processing of feefilter messages
-'''
def hashToHex(hash):
return format(hash, '064x')
@@ -21,9 +18,9 @@ def allInvsMatch(invsExpected, testnode):
for x in range(60):
with mininode_lock:
if (sorted(invsExpected) == sorted(testnode.txinvs)):
- return True;
+ return True
time.sleep(1)
- return False;
+ return False
# TestNode: bare-bones "peer". Used to track which invs are received from a node
# and to send the node feefilter messages.
diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/qa/rpc-tests/p2p-fullblocktest.py
index e4b889d761..274dbb8a92 100755
--- a/qa/rpc-tests/p2p-fullblocktest.py
+++ b/qa/rpc-tests/p2p-fullblocktest.py
@@ -2,6 +2,14 @@
# Copyright (c) 2015-2016 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 block processing.
+
+This reimplements tests from the bitcoinj/FullBlockTestGenerator used
+by the pull-tester.
+
+We use the testing framework in which we expect a particular answer from
+each test.
+"""
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
@@ -17,14 +25,6 @@ class PreviousSpendableOutput(object):
self.tx = tx
self.n = n # the output we're spending
-'''
-This reimplements tests from the bitcoinj/FullBlockTestGenerator used
-by the pull-tester.
-
-We use the testing framework in which we expect a particular answer from
-each test.
-'''
-
# Use this class for tests that require behavior other than normal "mininode" behavior.
# For now, it is used to serialize a bloated varint (b64).
class CBrokenBlock(CBlock):
@@ -398,7 +398,7 @@ class FullBlockTest(ComparisonTestFramework):
# Extend the b26 chain to make sure bitcoind isn't accepting b26
b27 = block(27, spend=out[7])
- yield rejected(RejectResult(16, b'bad-prevblk'))
+ yield rejected(RejectResult(0, b'bad-prevblk'))
# Now try a too-large-coinbase script
tip(15)
@@ -410,7 +410,7 @@ class FullBlockTest(ComparisonTestFramework):
# Extend the b28 chain to make sure bitcoind isn't accepting b28
b29 = block(29, spend=out[7])
- yield rejected(RejectResult(16, b'bad-prevblk'))
+ yield rejected(RejectResult(0, b'bad-prevblk'))
# b30 has a max-sized coinbase scriptSig.
tip(23)
diff --git a/qa/rpc-tests/p2p-leaktests.py b/qa/rpc-tests/p2p-leaktests.py
new file mode 100755
index 0000000000..bf08ea32f4
--- /dev/null
+++ b/qa/rpc-tests/p2p-leaktests.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 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 message sending before handshake completion.
+
+A node should never send anything other than VERSION/VERACK/REJECT until it's
+received a VERACK.
+
+This test connects to a node and sends it a few messages, trying to intice it
+into sending us something it shouldn't.
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+banscore = 10
+
+class CLazyNode(NodeConnCB):
+ def __init__(self):
+ self.connection = None
+ self.unexpected_msg = False
+ self.connected = False
+ super().__init__()
+
+ def add_connection(self, conn):
+ self.connection = conn
+
+ def send_message(self, message):
+ self.connection.send_message(message)
+
+ def bad_message(self, message):
+ self.unexpected_msg = True
+ print("should not have received message: %s" % message.command)
+
+ def on_open(self, conn):
+ self.connected = True
+
+ def on_version(self, conn, message): self.bad_message(message)
+ def on_verack(self, conn, message): self.bad_message(message)
+ def on_reject(self, conn, message): self.bad_message(message)
+ def on_inv(self, conn, message): self.bad_message(message)
+ def on_addr(self, conn, message): self.bad_message(message)
+ def on_alert(self, conn, message): self.bad_message(message)
+ def on_getdata(self, conn, message): self.bad_message(message)
+ def on_getblocks(self, conn, message): self.bad_message(message)
+ def on_tx(self, conn, message): self.bad_message(message)
+ def on_block(self, conn, message): self.bad_message(message)
+ def on_getaddr(self, conn, message): self.bad_message(message)
+ def on_headers(self, conn, message): self.bad_message(message)
+ def on_getheaders(self, conn, message): self.bad_message(message)
+ def on_ping(self, conn, message): self.bad_message(message)
+ def on_mempool(self, conn): self.bad_message(message)
+ def on_pong(self, conn, message): self.bad_message(message)
+ def on_feefilter(self, conn, message): self.bad_message(message)
+ def on_sendheaders(self, conn, message): self.bad_message(message)
+ def on_sendcmpct(self, conn, message): self.bad_message(message)
+ def on_cmpctblock(self, conn, message): self.bad_message(message)
+ def on_getblocktxn(self, conn, message): self.bad_message(message)
+ def on_blocktxn(self, conn, message): self.bad_message(message)
+
+# Node that never sends a version. We'll use this to send a bunch of messages
+# anyway, and eventually get disconnected.
+class CNodeNoVersionBan(CLazyNode):
+ def __init__(self):
+ super().__init__()
+
+ # send a bunch of veracks without sending a message. This should get us disconnected.
+ # NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
+ def on_open(self, conn):
+ super().on_open(conn)
+ for i in range(banscore):
+ self.send_message(msg_verack())
+
+ def on_reject(self, conn, message): pass
+
+# Node that never sends a version. This one just sits idle and hopes to receive
+# any message (it shouldn't!)
+class CNodeNoVersionIdle(CLazyNode):
+ def __init__(self):
+ super().__init__()
+
+# Node that sends a version but not a verack.
+class CNodeNoVerackIdle(CLazyNode):
+ def __init__(self):
+ self.version_received = False
+ super().__init__()
+
+ def on_reject(self, conn, message): pass
+ def on_verack(self, conn, message): pass
+ # When version is received, don't reply with a verack. Instead, see if the
+ # node will give us a message that it shouldn't. This is not an exhaustive
+ # list!
+ def on_version(self, conn, message):
+ self.version_received = True
+ conn.send_message(msg_ping())
+ conn.send_message(msg_getaddr())
+
+class P2PLeakTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ def setup_network(self):
+ extra_args = [['-debug', '-banscore='+str(banscore)]
+ for i in range(self.num_nodes)]
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+
+ def run_test(self):
+ no_version_bannode = CNodeNoVersionBan()
+ no_version_idlenode = CNodeNoVersionIdle()
+ no_verack_idlenode = CNodeNoVerackIdle()
+
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_bannode, send_version=False))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_idlenode, send_version=False))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_verack_idlenode))
+ no_version_bannode.add_connection(connections[0])
+ no_version_idlenode.add_connection(connections[1])
+ no_verack_idlenode.add_connection(connections[2])
+
+ NetworkThread().start() # Start up network handling in another thread
+
+ assert(wait_until(lambda: no_version_bannode.connected and no_version_idlenode.connected and no_verack_idlenode.version_received, timeout=10))
+
+ # Mine a block and make sure that it's not sent to the connected nodes
+ self.nodes[0].generate(1)
+
+ #Give the node enough time to possibly leak out a message
+ time.sleep(5)
+
+ #This node should have been banned
+ assert(no_version_bannode.connection.state == "closed")
+
+ [conn.disconnect_node() for conn in connections]
+
+ # Make sure no unexpected messages came in
+ assert(no_version_bannode.unexpected_msg == False)
+ assert(no_version_idlenode.unexpected_msg == False)
+ assert(no_verack_idlenode.unexpected_msg == False)
+
+if __name__ == '__main__':
+ P2PLeakTest().main()
diff --git a/qa/rpc-tests/p2p-mempool.py b/qa/rpc-tests/p2p-mempool.py
index 382d7f1e82..c6b1490211 100755
--- a/qa/rpc-tests/p2p-mempool.py
+++ b/qa/rpc-tests/p2p-mempool.py
@@ -2,11 +2,15 @@
# Copyright (c) 2015-2016 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 p2p mempool message.
+
+Test that nodes are disconnected if they send mempool messages when bloom
+filters are not enabled.
+"""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import time
class TestNode(NodeConnCB):
def __init__(self):
diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py
index 51adec5cae..470a5398b6 100755
--- a/qa/rpc-tests/p2p-segwit.py
+++ b/qa/rpc-tests/p2p-segwit.py
@@ -2,6 +2,7 @@
# Copyright (c) 2016 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 segwit transactions and blocks on P2P network."""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
@@ -21,9 +22,6 @@ VB_TOP_BITS = 0x20000000
MAX_SIGOP_COST = 80000
-'''
-SegWit p2p test.
-'''
# Calculate the virtual size of a witness block:
# (base + witness/4)
@@ -951,7 +949,6 @@ class SegWitTest(BitcoinTestFramework):
tx.rehash()
tx_hash = tx.sha256
- tx_value = tx.vout[0].nValue
# Verify that unnecessary witnesses are rejected.
self.test_node.announce_tx_and_wait_for_getdata(tx)
@@ -1662,7 +1659,7 @@ class SegWitTest(BitcoinTestFramework):
# too many sigops (contributing to legacy sigop count).
checksig_count = (extra_sigops_available // 4) + 1
scriptPubKey_checksigs = CScript([OP_CHECKSIG]*checksig_count)
- tx2.vout.append(CTxOut(0, scriptPubKey_checksigs));
+ tx2.vout.append(CTxOut(0, scriptPubKey_checksigs))
tx2.vin.pop()
tx2.wit.vtxinwit.pop()
tx2.vout[0].nValue -= tx.vout[-2].nValue
diff --git a/qa/rpc-tests/p2p-timeouts.py b/qa/rpc-tests/p2p-timeouts.py
new file mode 100755
index 0000000000..7f596b6e4b
--- /dev/null
+++ b/qa/rpc-tests/p2p-timeouts.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+# Copyright (c) 2016 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 various net timeouts.
+
+- Create three bitcoind nodes:
+
+ no_verack_node - we never send a verack in response to their version
+ no_version_node - we never send a version (only a ping)
+ no_send_node - we never send any P2P message.
+
+- Start all three nodes
+- Wait 1 second
+- Assert that we're connected
+- Send a ping to no_verack_node and no_version_node
+- Wait 30 seconds
+- Assert that we're still connected
+- Send a ping to no_verack_node and no_version_node
+- Wait 31 seconds
+- Assert that we're no longer connected (timeout to receive version/verack is 60 seconds)
+"""
+
+from time import sleep
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class TestNode(SingleNodeConnCB):
+ def __init__(self):
+ SingleNodeConnCB.__init__(self)
+ self.connected = False
+ self.received_version = False
+
+ def on_open(self, conn):
+ self.connected = True
+
+ def on_close(self, conn):
+ self.connected = False
+
+ def on_version(self, conn, message):
+ # Don't send a verack in response
+ self.received_version = True
+
+class TimeoutsTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def setup_network(self):
+ self.nodes = []
+
+ # Start up node0 to be a version 1, pre-segwit node.
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
+ [["-debug", "-logtimemicros=1"]])
+
+ def run_test(self):
+ # Setup the p2p connections and start up the network thread.
+ self.no_verack_node = TestNode() # never send verack
+ self.no_version_node = TestNode() # never send version (just ping)
+ self.no_send_node = TestNode() # never send anything
+
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_verack_node))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_version_node, send_version=False))
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_send_node, send_version=False))
+ self.no_verack_node.add_connection(connections[0])
+ self.no_version_node.add_connection(connections[1])
+ self.no_send_node.add_connection(connections[2])
+
+ NetworkThread().start() # Start up network handling in another thread
+
+ sleep(1)
+
+ assert(self.no_verack_node.connected)
+ assert(self.no_version_node.connected)
+ assert(self.no_send_node.connected)
+
+ ping_msg = msg_ping()
+ connections[0].send_message(ping_msg)
+ connections[1].send_message(ping_msg)
+
+ sleep(30)
+
+ assert(self.no_verack_node.received_version)
+
+ assert(self.no_verack_node.connected)
+ assert(self.no_version_node.connected)
+ assert(self.no_send_node.connected)
+
+ connections[0].send_message(ping_msg)
+ connections[1].send_message(ping_msg)
+
+ sleep(31)
+
+ assert(not self.no_verack_node.connected)
+ assert(not self.no_version_node.connected)
+ assert(not self.no_send_node.connected)
+
+if __name__ == '__main__':
+ TimeoutsTest().main()
diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py
index fc3eddddee..8e3e361fc1 100755
--- a/qa/rpc-tests/p2p-versionbits-warning.py
+++ b/qa/rpc-tests/p2p-versionbits-warning.py
@@ -2,6 +2,11 @@
# Copyright (c) 2016 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 version bits warning system.
+
+Generate chains with block versions that appear to be signalling unknown
+soft-forks, and test that warning alerts are generated.
+"""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
@@ -10,13 +15,6 @@ import re
import time
from test_framework.blocktools import create_block, create_coinbase
-'''
-Test version bits' warning system.
-
-Generate chains with block versions that appear to be signalling unknown
-soft-forks, and test that warning alerts are generated.
-'''
-
VB_PERIOD = 144 # versionbits period length for regtest
VB_THRESHOLD = 108 # versionbits activation threshold for regtest
VB_TOP_BITS = 0x20000000
diff --git a/qa/rpc-tests/preciousblock.py b/qa/rpc-tests/preciousblock.py
index 3cefa51c0a..dde164f329 100755
--- a/qa/rpc-tests/preciousblock.py
+++ b/qa/rpc-tests/preciousblock.py
@@ -1,11 +1,8 @@
#!/usr/bin/env python3
-# Copyright (c) 2015 The Bitcoin Core developers
+# Copyright (c) 2015-2016 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 PreciousBlock code
-#
+"""Test the preciousblock RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -102,7 +99,7 @@ class PreciousTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getblockcount(), 6)
hashL = self.nodes[2].getbestblockhash()
print("Connect nodes and check no reorg occurs")
- node_sync_via_rpc(self.nodes[0:3])
+ node_sync_via_rpc(self.nodes[1:3])
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
assert_equal(self.nodes[0].getbestblockhash(), hashH)
diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py
index 85afeab2e3..9a63d0838f 100755
--- a/qa/rpc-tests/prioritise_transaction.py
+++ b/qa/rpc-tests/prioritise_transaction.py
@@ -2,10 +2,7 @@
# Copyright (c) 2015-2016 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 PrioritiseTransaction code
-#
+"""Test the prioritisetransaction mining RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -39,7 +36,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
txids.append([])
start_range = i * range_size
end_range = start_range + range_size
- txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], (i+1)*base_fee)
+ txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[start_range:end_range], end_range - start_range, (i+1)*base_fee)
# Make sure that the size of each group of transactions exceeds
# MAX_BLOCK_BASE_SIZE -- otherwise the test needs to be revised to create
diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py
index 9ccc0ffbb0..e4e231f312 100755
--- a/qa/rpc-tests/proxy_test.py
+++ b/qa/rpc-tests/proxy_test.py
@@ -2,20 +2,8 @@
# Copyright (c) 2015-2016 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 bitcoind with different proxy configuration.
-import socket
-import os
-
-from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (
- PORT_MIN,
- PORT_RANGE,
- start_nodes,
- assert_equal,
-)
-from test_framework.netutil import test_ipv6_local
-'''
Test plan:
- Start bitcoind's with different proxy configurations
- Use addnode to initiate connections
@@ -37,7 +25,20 @@ addnode connect to IPv4
addnode connect to IPv6
addnode connect to onion
addnode connect to generic DNS name
-'''
+"""
+
+import socket
+import os
+
+from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ PORT_MIN,
+ PORT_RANGE,
+ start_nodes,
+ assert_equal,
+)
+from test_framework.netutil import test_ipv6_local
RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index 6635b0dff2..ace8ced422 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -2,17 +2,25 @@
# Copyright (c) 2014-2016 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 pruning code.
-#
-# Test pruning code
-# ********
-# WARNING:
-# This test uses 4GB of disk space.
-# This test takes 30 mins or more (up to 2 hours)
-# ********
+WARNING:
+This test uses 4GB of disk space.
+This test takes 30 mins or more (up to 2 hours)
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+import time
+import os
+
+MIN_BLOCKS_TO_KEEP = 288
+
+# Rescans start at the earliest block up to 2 hours before a key timestamp, so
+# the manual prune RPC avoids pruning blocks in the same window to be
+# compatible with pruning based on key creation time.
+RESCAN_WINDOW = 2 * 60 * 60
+
def calc_usage(blockdir):
return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.)
@@ -22,7 +30,11 @@ class PruneTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.setup_clean_chain = True
- self.num_nodes = 3
+ self.num_nodes = 6
+
+ # Cache for utxos, as the listunspent may take a long time later in the test
+ self.utxo_cache_0 = []
+ self.utxo_cache_1 = []
def setup_network(self):
self.nodes = []
@@ -36,10 +48,22 @@ class PruneTest(BitcoinTestFramework):
self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-prune=550"], timewait=900))
self.prunedir = self.options.tmpdir+"/node2/regtest/blocks/"
+ # Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
+ self.nodes.append(start_node(3, self.options.tmpdir, ["-debug=0","-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900))
+ self.nodes.append(start_node(4, self.options.tmpdir, ["-debug=0","-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900))
+
+ # Create nodes 5 to test wallet in prune mode, but do not connect
+ self.nodes.append(start_node(5, self.options.tmpdir, ["-debug=0", "-prune=550"]))
+
+ # Determine default relay fee
+ self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
+
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[1], 2)
connect_nodes(self.nodes[2], 0)
- sync_blocks(self.nodes[0:3])
+ connect_nodes(self.nodes[0], 3)
+ connect_nodes(self.nodes[0], 4)
+ sync_blocks(self.nodes[0:5])
def create_big_chain(self):
# Start by creating some coinbases we can spend later
@@ -48,9 +72,9 @@ class PruneTest(BitcoinTestFramework):
self.nodes[0].generate(150)
# Then mine enough full blocks to create more than 550MiB of data
for i in range(645):
- mine_large_block(self.nodes[0])
+ mine_large_block(self.nodes[0], self.utxo_cache_0)
- sync_blocks(self.nodes[0:3])
+ sync_blocks(self.nodes[0:5])
def test_height_min(self):
if not os.path.isfile(self.prunedir+"blk00000.dat"):
@@ -60,7 +84,7 @@ class PruneTest(BitcoinTestFramework):
print("Mining 25 more blocks should cause the first block file to be pruned")
# Pruning doesn't run until we're allocating another chunk, 20 full blocks past the height cutoff will ensure this
for i in range(25):
- mine_large_block(self.nodes[0])
+ mine_large_block(self.nodes[0], self.utxo_cache_0)
waitstart = time.time()
while os.path.isfile(self.prunedir+"blk00000.dat"):
@@ -82,18 +106,18 @@ class PruneTest(BitcoinTestFramework):
# Disconnect node 0 so it can mine a longer reorg chain without knowing about node 1's soon-to-be-stale chain
# Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects
# Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine
- stop_node(self.nodes[0],0)
+ self.stop_node(0)
self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)
# Mine 24 blocks in node 1
for i in range(24):
if j == 0:
- mine_large_block(self.nodes[1])
+ mine_large_block(self.nodes[1], self.utxo_cache_1)
else:
self.nodes[1].generate(1) #tx's already in mempool from previous disconnects
# Reorg back with 25 block chain from node 0
for i in range(25):
- mine_large_block(self.nodes[0])
+ mine_large_block(self.nodes[0], self.utxo_cache_0)
# Create connections in the order so both nodes can see the reorg at the same time
connect_nodes(self.nodes[1], 0)
@@ -107,7 +131,7 @@ class PruneTest(BitcoinTestFramework):
# This will cause Node 2 to do a reorg requiring 288 blocks of undo data to the reorg_test chain
# Reboot node 1 to clear its mempool (hopefully make the invalidate faster)
# Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks)
- stop_node(self.nodes[1],1)
+ self.stop_node(1)
self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
height = self.nodes[1].getblockcount()
@@ -130,7 +154,7 @@ class PruneTest(BitcoinTestFramework):
print("New best height", self.nodes[1].getblockcount())
# Reboot node1 to clear those giant tx's from mempool
- stop_node(self.nodes[1],1)
+ self.stop_node(1)
self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
print("Generating new longer chain of 300 more blocks")
@@ -205,6 +229,114 @@ class PruneTest(BitcoinTestFramework):
# Verify we can now have the data for a block previously pruned
assert(self.nodes[2].getblock(self.forkhash)["height"] == self.forkheight)
+ def manual_test(self, node_number, use_timestamp):
+ # at this point, node has 995 blocks and has not yet run in prune mode
+ node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0"], timewait=900)
+ assert_equal(node.getblockcount(), 995)
+ assert_raises_message(JSONRPCException, "not in prune mode", node.pruneblockchain, 500)
+ self.stop_node(node_number)
+
+ # now re-start in manual pruning mode
+ node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0","-prune=1"], timewait=900)
+ assert_equal(node.getblockcount(), 995)
+
+ def height(index):
+ if use_timestamp:
+ return node.getblockheader(node.getblockhash(index))["time"] + RESCAN_WINDOW
+ else:
+ return index
+
+ def prune(index, expected_ret=None):
+ ret = node.pruneblockchain(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,
+ # a timestamp will not be granular enough to uniquely identify an
+ # individual block.
+ if expected_ret is None:
+ expected_ret = index
+ if use_timestamp:
+ assert_greater_than(ret, 0)
+ assert_greater_than(expected_ret + 1, ret)
+ else:
+ assert_equal(ret, expected_ret)
+
+ def has_block(index):
+ return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index))
+
+ # should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
+ assert_raises_message(JSONRPCException, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
+
+ # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
+ node.generate(6)
+ assert_equal(node.getblockchaininfo()["blocks"], 1001)
+
+ # negative heights should raise an exception
+ assert_raises_message(JSONRPCException, "Negative", node.pruneblockchain, -10)
+
+ # height=100 too low to prune first block file so this is a no-op
+ prune(100)
+ if not has_block(0):
+ raise AssertionError("blk00000.dat is missing when should still be there")
+
+ # Does nothing
+ node.pruneblockchain(height(0))
+ if not has_block(0):
+ raise AssertionError("blk00000.dat is missing when should still be there")
+
+ # height=500 should prune first file
+ prune(500)
+ if has_block(0):
+ raise AssertionError("blk00000.dat is still there, should be pruned by now")
+ if not has_block(1):
+ raise AssertionError("blk00001.dat is missing when should still be there")
+
+ # height=650 should prune second file
+ prune(650)
+ if has_block(1):
+ raise AssertionError("blk00001.dat is still there, should be pruned by now")
+
+ # height=1000 should not prune anything more, because tip-288 is in blk00002.dat.
+ prune(1000, 1001 - MIN_BLOCKS_TO_KEEP)
+ if not has_block(2):
+ raise AssertionError("blk00002.dat is still there, should be pruned by now")
+
+ # advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat)
+ node.generate(288)
+ prune(1000)
+ if has_block(2):
+ raise AssertionError("blk00002.dat is still there, should be pruned by now")
+ if has_block(3):
+ raise AssertionError("blk00003.dat is still there, should be pruned by now")
+
+ # stop node, start back up with auto-prune at 550MB, make sure still runs
+ self.stop_node(node_number)
+ self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0","-prune=550"], timewait=900)
+
+ print("Success")
+
+ def wallet_test(self):
+ # check that the pruning node's wallet is still in good shape
+ print("Stop and start pruning node to trigger wallet rescan")
+ try:
+ self.stop_node(2)
+ start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"])
+ print("Success")
+ except Exception as detail:
+ raise AssertionError("Wallet test: unable to re-start the pruning node")
+
+ # check that wallet loads loads successfully when restarting a pruned node after IBD.
+ # this was reported to fail in #7494.
+ print ("Syncing node 5 to test wallet")
+ connect_nodes(self.nodes[0], 5)
+ nds = [self.nodes[0], self.nodes[5]]
+ sync_blocks(nds, wait=5, timeout=300)
+ try:
+ self.stop_node(5) #stop and start to trigger rescan
+ start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"])
+ print ("Success")
+ except Exception as detail:
+ raise AssertionError("Wallet test: unable to re-start node5")
def run_test(self):
print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
@@ -219,6 +351,10 @@ class PruneTest(BitcoinTestFramework):
# Start by mining a simple chain that all nodes have
# N0=N1=N2 **...*(995)
+ # stop manual-pruning node with 995 blocks
+ self.stop_node(3)
+ self.stop_node(4)
+
print("Check that we haven't started pruning yet because we're below PruneAfterHeight")
self.test_height_min()
# Extend this chain past the PruneAfterHeight
@@ -301,6 +437,15 @@ class PruneTest(BitcoinTestFramework):
#
# N1 doesn't change because 1033 on main chain (*) is invalid
+ print("Test manual pruning with block indices")
+ self.manual_test(3, use_timestamp=False)
+
+ print("Test manual pruning with timestamps")
+ self.manual_test(4, use_timestamp=True)
+
+ print("Test wallet re-scan")
+ self.wallet_test()
+
print("Done")
if __name__ == '__main__':
diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py
index 33a6f2b0cc..5adef31207 100755
--- a/qa/rpc-tests/rawtransactions.py
+++ b/qa/rpc-tests/rawtransactions.py
@@ -2,14 +2,14 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""rawtranscation RPCs QA test.
-
-# Tests the following RPCs:
-# - createrawtransaction
-# - signrawtransaction
-# - sendrawtransaction
-# - decoderawtransaction
-# - getrawtransaction
+"""Test the rawtranscation RPCs.
+
+Test the following RPCs:
+ - createrawtransaction
+ - signrawtransaction
+ - sendrawtransaction
+ - decoderawtransaction
+ - getrawtransaction
"""
from test_framework.test_framework import BitcoinTestFramework
diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py
index 4f17b661cb..248bcdbd68 100755
--- a/qa/rpc-tests/receivedby.py
+++ b/qa/rpc-tests/receivedby.py
@@ -2,19 +2,16 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# Exercise the listreceivedbyaddress API
+"""Test the listreceivedbyaddress RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-
def get_sub_array_from_array(object_array, to_match):
'''
Finds and returns a sub array from an array of arrays.
to_match should be a unique idetifier of a sub array
'''
- num_matched = 0
for item in object_array:
all_match = True
for key,value in to_match.items():
@@ -104,7 +101,7 @@ class ReceivedByTest(BitcoinTestFramework):
received_by_account_json = get_sub_array_from_array(self.nodes[1].listreceivedbyaccount(),{"account":account})
if len(received_by_account_json) == 0:
raise AssertionError("No accounts found in node")
- balance_by_account = rec_by_accountArr = self.nodes[1].getreceivedbyaccount(account)
+ balance_by_account = self.nodes[1].getreceivedbyaccount(account)
txid = self.nodes[0].sendtoaddress(addr, 0.1)
self.sync_all()
diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py
index 25cf4c1679..1b547a920f 100755
--- a/qa/rpc-tests/reindex.py
+++ b/qa/rpc-tests/reindex.py
@@ -2,10 +2,13 @@
# Copyright (c) 2014-2016 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 running bitcoind with -reindex and -reindex-chainstate options.
+
+- Start a single node and generate 3 blocks.
+- Stop the node and restart it with -reindex. Verify that the node has reindexed up to block 3.
+- Stop the node and restart it with -reindex-chainstate. Verify that the node has reindexed up to block 3.
+"""
-#
-# Test -reindex and -reindex-chainstate with CheckBlockIndex
-#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
start_nodes,
diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py
index 34c0f9d795..a3c1deddf6 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/qa/rpc-tests/replace-by-fee.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 replace by fee code
-#
+"""Test the RBF code."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -76,7 +73,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
- "-relaypriority=0", "-whitelist=127.0.0.1",
+ "-whitelist=127.0.0.1",
"-limitancestorcount=50",
"-limitancestorsize=101",
"-limitdescendantcount=200",
@@ -393,7 +390,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
utxo = make_utxo(self.nodes[0], initial_nValue)
fee = int(0.0001*COIN)
split_value = int((initial_nValue-fee)/(MAX_REPLACEMENT_LIMIT+1))
- actual_fee = initial_nValue - split_value*(MAX_REPLACEMENT_LIMIT+1)
outputs = []
for i in range(MAX_REPLACEMENT_LIMIT+1):
@@ -443,7 +439,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
self.nodes[0].sendrawtransaction(double_tx_hex, True)
def test_opt_in(self):
- """ Replacing should only work if orig tx opted in """
+ """Replacing should only work if orig tx opted in"""
tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
# Create a non-opting in transaction
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index b769cd71f2..9ca1cc187a 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -2,11 +2,7 @@
# Copyright (c) 2014-2016 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 REST interface
-#
-
+"""Test the REST API."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index d78d0b884e..499fe33679 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-2016 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 -rpcbind, as well as -rpcallowip and -rpcconnect
+"""Test running bitcoind with the -rpcbind and -rpcallowip options."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -35,11 +34,9 @@ class RPCBindTest(BitcoinTestFramework):
base_args += ['-rpcallowip=' + x for x in allow_ips]
binds = ['-rpcbind='+addr for addr in addresses]
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to)
- try:
- pid = bitcoind_processes[0].pid
- assert_equal(set(get_bind_addrs(pid)), set(expected))
- finally:
- stop_nodes(self.nodes)
+ pid = bitcoind_processes[0].pid
+ assert_equal(set(get_bind_addrs(pid)), set(expected))
+ stop_nodes(self.nodes)
def run_allowip_test(self, allow_ips, rpchost, rpcport):
'''
@@ -48,13 +45,10 @@ class RPCBindTest(BitcoinTestFramework):
'''
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
- try:
- # connect to node through non-loopback interface
- node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0)
- node.getnetworkinfo()
- finally:
- node = None # make sure connection will be garbage collected and closed
- stop_nodes(self.nodes)
+ # connect to node through non-loopback interface
+ node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0)
+ node.getnetworkinfo()
+ stop_nodes(self.nodes)
def run_test(self):
# due to OS-specific network stats queries, this test works only on Linux
diff --git a/qa/rpc-tests/rpcnamedargs.py b/qa/rpc-tests/rpcnamedargs.py
new file mode 100755
index 0000000000..f6175c8ca7
--- /dev/null
+++ b/qa/rpc-tests/rpcnamedargs.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+# Copyright (c) 2016 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 using named arguments for RPCs."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_jsonrpc,
+ start_nodes,
+)
+
+
+class NamedArgumentTest(BitcoinTestFramework):
+ """
+ Test named arguments on RPC calls.
+ """
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+
+ def setup_network(self, split=False):
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
+ self.is_network_split = False
+ self.sync_all()
+
+ def run_test(self):
+ node = self.nodes[0]
+ h = node.help(command='getinfo')
+ assert(h.startswith('getinfo\n'))
+
+ assert_raises_jsonrpc(-8, 'Unknown named parameter', node.help, random='getinfo')
+
+ h = node.getblockhash(height=0)
+ node.getblock(blockhash=h)
+
+ assert_equal(node.echo(), [])
+ assert_equal(node.echo(arg0=0,arg9=9), [0] + [None]*8 + [9])
+ assert_equal(node.echo(arg1=1), [None, 1])
+ assert_equal(node.echo(arg9=None), [None]*10)
+ assert_equal(node.echo(arg0=0,arg3=3,arg9=9), [0] + [None]*2 + [3] + [None]*5 + [9])
+
+if __name__ == '__main__':
+ NamedArgumentTest().main()
diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py
index 41a1b3b20f..f475427842 100755
--- a/qa/rpc-tests/segwit.py
+++ b/qa/rpc-tests/segwit.py
@@ -2,10 +2,7 @@
# Copyright (c) 2016 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 SegWit changeover logic
-#
+"""Test the SegWit changeover logic."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -13,6 +10,7 @@ from test_framework.mininode import sha256, ripemd160, CTransaction, CTxIn, COut
from test_framework.address import script_to_p2sh, key_to_p2pkh
from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG
from io import BytesIO
+from test_framework.mininode import FromHex
NODE_0 = 0
NODE_1 = 1
@@ -38,7 +36,7 @@ def addlength(script):
return scriptlen + script
def create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount):
- pkscript = witness_script(version, pubkey);
+ pkscript = witness_script(version, pubkey)
if (encode_p2sh):
p2sh_hash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pkscript))))
pkscript = "a914"+p2sh_hash+"87"
@@ -84,8 +82,8 @@ class SegWitTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness", "-rpcserialversion=0"]))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"]))
self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
connect_nodes(self.nodes[1], 0)
connect_nodes(self.nodes[2], 1)
@@ -129,10 +127,14 @@ class SegWitTest(BitcoinTestFramework):
print("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
tmpl = self.nodes[0].getblocktemplate({})
+ 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)
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)
@@ -211,7 +213,19 @@ class SegWitTest(BitcoinTestFramework):
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)
- assert_equal(len(self.nodes[2].getblock(block[0])["tx"]), 5)
+ segwit_tx_list = self.nodes[2].getblock(block[0])["tx"]
+ assert_equal(len(segwit_tx_list), 5)
+
+ print("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))
+ 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]))
+ assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i]))
+ assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
+ assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
+ assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness()))
print("Verify witness txs without witness data are invalid after the fork")
self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
@@ -228,6 +242,8 @@ class SegWitTest(BitcoinTestFramework):
print("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']})
+ 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)
@@ -237,6 +253,8 @@ class SegWitTest(BitcoinTestFramework):
try:
tmpl = self.nodes[0].getblocktemplate({})
assert(len(tmpl['transactions']) == 1) # Doesn't include witness tx
+ 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)
diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py
index 37b98c576e..16ca4a4913 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/qa/rpc-tests/sendheaders.py
@@ -2,14 +2,7 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-from test_framework.blocktools import create_block, create_coinbase
-
-'''
-SendHeadersTest -- test behavior of headers messages to announce blocks.
+"""Test behavior of headers messages to announce blocks.
Setup:
@@ -78,7 +71,13 @@ d. Announce 49 headers that don't connect.
Expect: getheaders message each time.
e. Announce one more that doesn't connect.
Expect: disconnect.
-'''
+"""
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+from test_framework.blocktools import create_block, create_coinbase
+
direct_fetch_response_time = 0.05
diff --git a/qa/rpc-tests/signmessages.py b/qa/rpc-tests/signmessages.py
index 31b6f14a26..91f5abef5d 100755
--- a/qa/rpc-tests/signmessages.py
+++ b/qa/rpc-tests/signmessages.py
@@ -2,13 +2,12 @@
# Copyright (c) 2016 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 commands for signing and verifying messages."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-
class SignMessagesTest(BitcoinTestFramework):
- """Tests RPC commands for signing and verifying messages."""
def __init__(self):
super().__init__()
diff --git a/qa/rpc-tests/signrawtransactions.py b/qa/rpc-tests/signrawtransactions.py
index c61a280616..b24162ab97 100755
--- a/qa/rpc-tests/signrawtransactions.py
+++ b/qa/rpc-tests/signrawtransactions.py
@@ -2,14 +2,13 @@
# Copyright (c) 2015-2016 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 transaction signing using the signrawtransaction RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class SignRawTransactionsTest(BitcoinTestFramework):
- """Tests transaction signing via RPC command "signrawtransaction"."""
-
def __init__(self):
super().__init__()
self.setup_clean_chain = True
@@ -20,18 +19,20 @@ class SignRawTransactionsTest(BitcoinTestFramework):
self.is_network_split = False
def successful_signing_test(self):
- """Creates and signs a valid raw transaction with one input.
+ """Create and sign a valid raw transaction with one input.
Expected results:
1) The transaction has a complete set of signatures
2) No script verification error occurred"""
- privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N']
+ privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N', 'cVKpPfVKSJxKqVpE9awvXNWuLHCa5j5tiE7K6zbUSptFpTEtiFrA']
inputs = [
- # Valid pay-to-pubkey script
+ # Valid pay-to-pubkey scripts
{'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0,
- 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'}
+ 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'},
+ {'txid': '83a4f6a6b73660e13ee6cb3c6063fa3759c50c9b7521d0536022961898f4fb02', 'vout': 0,
+ 'scriptPubKey': '76a914669b857c03a5ed269d5d85a1ffac9ed5d663072788ac'},
]
outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1}
@@ -46,8 +47,24 @@ class SignRawTransactionsTest(BitcoinTestFramework):
# 2) No script verification error occurred
assert 'errors' not in rawTxSigned
+ # Check that signrawtransaction doesn't blow up on garbage merge attempts
+ dummyTxInconsistent = self.nodes[0].createrawtransaction([inputs[0]], outputs)
+ rawTxUnsigned = self.nodes[0].signrawtransaction(rawTx + dummyTxInconsistent, inputs)
+
+ assert 'complete' in rawTxUnsigned
+ assert_equal(rawTxUnsigned['complete'], False)
+
+ # Check that signrawtransaction properly merges unsigned and signed txn, even with garbage in the middle
+ rawTxSigned2 = self.nodes[0].signrawtransaction(rawTxUnsigned["hex"] + dummyTxInconsistent + rawTxSigned["hex"], inputs)
+
+ assert 'complete' in rawTxSigned2
+ assert_equal(rawTxSigned2['complete'], True)
+
+ assert 'errors' not in rawTxSigned2
+
+
def script_verification_error_test(self):
- """Creates and signs a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script.
+ """Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script.
Expected results:
@@ -78,6 +95,16 @@ class SignRawTransactionsTest(BitcoinTestFramework):
outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1}
rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
+
+ # Make sure decoderawtransaction is at least marginally sane
+ decodedRawTx = self.nodes[0].decoderawtransaction(rawTx)
+ for i, inp in enumerate(inputs):
+ assert_equal(decodedRawTx["vin"][i]["txid"], inp["txid"])
+ assert_equal(decodedRawTx["vin"][i]["vout"], inp["vout"])
+
+ # Make sure decoderawtransaction throws if there is extra data
+ assert_raises(JSONRPCException, self.nodes[0].decoderawtransaction, rawTx + "00")
+
rawTxSigned = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys)
# 3) The transaction has no complete set of signatures
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
index 74a74f679a..bde454968f 100755
--- a/qa/rpc-tests/smartfees.py
+++ b/qa/rpc-tests/smartfees.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 fee estimation code
-#
+"""Test fee estimation code."""
from collections import OrderedDict
from test_framework.test_framework import BitcoinTestFramework
@@ -21,7 +18,7 @@ P2SH_2 = "2NBdpwq8Aoo1EEKEXPNrKvr5xQr3M9UfcZA" # P2SH of "OP_2 OP_DROP"
SCRIPT_SIG = ["0451025175", "0451025275"]
def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment):
- '''
+ """
Create and send a transaction with a random fee.
The transaction pays to a trivial P2SH script, and assumes that its inputs
are of the same form.
@@ -29,7 +26,7 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
and attempts to use the confirmed list first for its inputs.
It adds the newly created outputs to the unconfirmed list.
Returns (raw transaction, fee)
- '''
+ """
# It's best to exponentially distribute our random fees
# because the buckets are exponentially spaced.
# Exponentially distributed from 1-128 * fee_increment
@@ -71,12 +68,12 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
return (completetx, fee)
def split_inputs(from_node, txins, txouts, initial_split = False):
- '''
+ """
We need to generate a lot of very small inputs so we can generate a ton of transactions
and they will have low priority.
This function takes an input from txins, and creates and sends a transaction
which splits the value into 2 outputs which are appended to txouts.
- '''
+ """
prevtxout = txins.pop()
inputs = []
inputs.append({ "txid" : prevtxout["txid"], "vout" : prevtxout["vout"] })
@@ -95,10 +92,10 @@ def split_inputs(from_node, txins, txouts, initial_split = False):
txouts.append({ "txid" : txid, "vout" : 1 , "amount" : rem_change})
def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
- '''
+ """
This function calls estimatefee and verifies that the estimates
meet certain invariants.
- '''
+ """
all_estimates = [ node.estimatefee(i) for i in range(1,26) ]
if print_estimates:
print([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]])
@@ -151,15 +148,15 @@ class EstimateFeeTest(BitcoinTestFramework):
self.setup_clean_chain = False
def setup_network(self):
- '''
+ """
We'll setup the network to have 3 nodes that all mine with different parameters.
But first we need to use one node to create a lot of small low priority outputs
which we will use to generate our transactions.
- '''
+ """
self.nodes = []
# Use node0 to mine blocks for input splitting
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
- "-relaypriority=0", "-whitelist=127.0.0.1"]))
+ "-whitelist=127.0.0.1"]))
print("This test is time consuming, please be patient")
print("Splitting inputs to small size so we can generate low priority tx's")
@@ -197,12 +194,12 @@ class EstimateFeeTest(BitcoinTestFramework):
# (17k is room enough for 110 or so transactions)
self.nodes.append(start_node(1, self.options.tmpdir,
["-blockprioritysize=1500", "-blockmaxsize=17000",
- "-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"]))
+ "-maxorphantx=1000", "-debug=estimatefee"]))
connect_nodes(self.nodes[1], 0)
# Node2 is a stingy miner, that
# produces too small blocks (room for only 55 or so transactions)
- node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000", "-relaypriority=0"]
+ node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000"]
self.nodes.append(start_node(2, self.options.tmpdir, node2args))
connect_nodes(self.nodes[0], 2)
diff --git a/qa/rpc-tests/test_framework/address.py b/qa/rpc-tests/test_framework/address.py
index 50b999be61..96bebe1ea1 100644
--- a/qa/rpc-tests/test_framework/address.py
+++ b/qa/rpc-tests/test_framework/address.py
@@ -2,12 +2,7 @@
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#
-# address.py
-#
-# This file encodes and decodes BASE58 P2PKH and P2SH addresses
-#
+"""Encode and decode BASE58, P2PKH and P2SH addresses."""
from .script import hash256, hash160, sha256, CScript, OP_0
from .util import bytes_to_hex_str, hex_str_to_bytes
diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py
index 9bee1962e2..9ab3094b06 100644
--- a/qa/rpc-tests/test_framework/authproxy.py
+++ b/qa/rpc-tests/test_framework/authproxy.py
@@ -1,37 +1,36 @@
-
-"""
- Copyright (c) 2011 Jeff Garzik
-
- AuthServiceProxy has the following improvements over python-jsonrpc's
- ServiceProxy class:
-
- - HTTP connections persist for the life of the AuthServiceProxy object
- (if server supports HTTP/1.1)
- - sends protocol 'version', per JSON-RPC 1.1
- - sends proper, incrementing 'id'
- - sends Basic HTTP authentication headers
- - parses all JSON numbers that look like floats as Decimal
- - uses standard Python json lib
-
- Previous copyright, from python-jsonrpc/jsonrpc/proxy.py:
-
- Copyright (c) 2007 Jan-Klaas Kollhof
-
- This file is part of jsonrpc.
-
- jsonrpc is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this software; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# Copyright (c) 2011 Jeff Garzik
+#
+# Previous copyright, from python-jsonrpc/jsonrpc/proxy.py:
+#
+# Copyright (c) 2007 Jan-Klaas Kollhof
+#
+# This file is part of jsonrpc.
+#
+# jsonrpc is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this software; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""HTTP proxy for opening RPC connection to bitcoind.
+
+AuthServiceProxy has the following improvements over python-jsonrpc's
+ServiceProxy class:
+
+- HTTP connections persist for the life of the AuthServiceProxy object
+ (if server supports HTTP/1.1)
+- sends protocol 'version', per JSON-RPC 1.1
+- sends proper, incrementing 'id'
+- sends Basic HTTP authentication headers
+- parses all JSON numbers that look like floats as Decimal
+- uses standard Python json lib
"""
try:
@@ -138,14 +137,16 @@ class AuthServiceProxy(object):
self.__conn.request(method, path, postdata, headers)
return self._get_response()
- def __call__(self, *args):
+ def __call__(self, *args, **argsn):
AuthServiceProxy.__id_count += 1
log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name,
json.dumps(args, default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
+ if args and argsn:
+ raise ValueError('Cannot handle both named and positional arguments')
postdata = json.dumps({'version': '1.1',
'method': self._service_name,
- 'params': args,
+ 'params': args or argsn,
'id': AuthServiceProxy.__id_count}, default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
response = self._request('POST', self.__url.path, postdata.encode('utf-8'))
if response['error'] is not None:
diff --git a/qa/rpc-tests/test_framework/bignum.py b/qa/rpc-tests/test_framework/bignum.py
index ef800e4d57..024611da6e 100644
--- a/qa/rpc-tests/test_framework/bignum.py
+++ b/qa/rpc-tests/test_framework/bignum.py
@@ -1,15 +1,11 @@
#!/usr/bin/env python3
#
-# bignum.py
-#
-# This file is copied from python-bitcoinlib.
-#
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-
-"""Bignum routines"""
+"""Big number routines.
+This file is copied from python-bitcoinlib.
+"""
import struct
diff --git a/qa/rpc-tests/test_framework/blockstore.py b/qa/rpc-tests/test_framework/blockstore.py
index 28a6b92b81..5280d18cdc 100644
--- a/qa/rpc-tests/test_framework/blockstore.py
+++ b/qa/rpc-tests/test_framework/blockstore.py
@@ -2,16 +2,20 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-# BlockStore: a helper class that keeps a map of blocks and implements
-# helper functions for responding to getheaders and getdata,
-# and for constructing a getheaders message
-#
+"""BlockStore and TxStore helper classes."""
from .mininode import *
from io import BytesIO
import dbm.dumb as dbmd
class BlockStore(object):
+ """BlockStore helper class.
+
+ BlockStore keeps a map of blocks and implements helper functions for
+ responding to getheaders and getdata, and for constructing a getheaders
+ message.
+ """
+
def __init__(self, datadir):
self.blockDB = dbmd.open(datadir + "/blocks", 'c')
self.currentBlock = 0
diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py
index f69958823c..2c9a0857df 100644
--- a/qa/rpc-tests/test_framework/blocktools.py
+++ b/qa/rpc-tests/test_framework/blocktools.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
-# blocktools.py - utilities for manipulating blocks and transactions
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Utilities for manipulating blocks and transactions."""
from .mininode import *
from .script import CScript, OP_TRUE, OP_CHECKSIG, OP_RETURN
diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py
index 17679fc7e1..b617895cac 100755
--- a/qa/rpc-tests/test_framework/comptool.py
+++ b/qa/rpc-tests/test_framework/comptool.py
@@ -2,34 +2,29 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-from .mininode import *
-from .blockstore import BlockStore, TxStore
-from .util import p2p_port
-
-'''
-This is a tool for comparing two or more bitcoinds to each other
-using a script provided.
+"""Compare two or more bitcoinds to each other.
To use, create a class that implements get_tests(), and pass it in
as the test generator to TestManager. get_tests() should be a python
generator that returns TestInstance objects. See below for definition.
-'''
-# TestNode behaves as follows:
-# Configure with a BlockStore and TxStore
-# on_inv: log the message but don't request
-# on_headers: log the chain tip
-# on_pong: update ping response map (for synchronization)
-# on_getheaders: provide headers via BlockStore
-# on_getdata: provide blocks via BlockStore
+TestNode behaves as follows:
+ Configure with a BlockStore and TxStore
+ on_inv: log the message but don't request
+ on_headers: log the chain tip
+ on_pong: update ping response map (for synchronization)
+ on_getheaders: provide headers via BlockStore
+ on_getdata: provide blocks via BlockStore
+"""
+
+from .mininode import *
+from .blockstore import BlockStore, TxStore
+from .util import p2p_port
global mininode_lock
class RejectResult(object):
- '''
- Outcome that expects rejection of a transaction or block.
- '''
+ """Outcome that expects rejection of a transaction or block."""
def __init__(self, code, reason=b''):
self.code = code
self.reason = reason
diff --git a/qa/rpc-tests/test_framework/coverage.py b/qa/rpc-tests/test_framework/coverage.py
index 13b33869f5..3f87ef91f6 100644
--- a/qa/rpc-tests/test_framework/coverage.py
+++ b/qa/rpc-tests/test_framework/coverage.py
@@ -2,15 +2,12 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Utilities for doing coverage analysis on the RPC interface.
-"""
-This module contains utilities for doing coverage analysis on the RPC
-interface.
-
-It provides a way to track which RPC commands are exercised during
+Provides a way to track which RPC commands are exercised during
testing.
-
"""
+
import os
diff --git a/qa/rpc-tests/test_framework/key.py b/qa/rpc-tests/test_framework/key.py
index c63a15c1e0..85a6158a2f 100644
--- a/qa/rpc-tests/test_framework/key.py
+++ b/qa/rpc-tests/test_framework/key.py
@@ -1,14 +1,10 @@
# Copyright (c) 2011 Sam Rushing
-#
-# key.py - OpenSSL wrapper
-#
-# This file is modified from python-bitcoinlib.
-#
-
-"""ECC secp256k1 crypto routines
+"""ECC secp256k1 OpenSSL wrapper.
WARNING: This module does not mlock() secrets; your private keys may end up on
disk in swap! Use with caution!
+
+This file is modified from python-bitcoinlib.
"""
import ctypes
diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py
index 91daa4ab1f..b2292f6477 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/qa/rpc-tests/test_framework/mininode.py
@@ -4,23 +4,21 @@
# Copyright (c) 2010-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#
-# mininode.py - Bitcoin P2P network half-a-node
-#
-# This python code was modified from ArtForz' public domain half-a-node, as
-# found in the mini-node branch of http://github.com/jgarzik/pynode.
-#
-# NodeConn: an object which manages p2p connectivity to a bitcoin node
-# NodeConnCB: a base class that describes the interface for receiving
-# callbacks with network messages from a NodeConn
-# CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....:
-# data structures that should map to corresponding structures in
-# bitcoin/primitives
-# msg_block, msg_tx, msg_headers, etc.:
-# data structures that represent network messages
-# ser_*, deser_*: functions that handle serialization/deserialization
-
+"""Bitcoin P2P network half-a-node.
+
+This python code was modified from ArtForz' public domain half-a-node, as
+found in the mini-node branch of http://github.com/jgarzik/pynode.
+
+NodeConn: an object which manages p2p connectivity to a bitcoin node
+NodeConnCB: a base class that describes the interface for receiving
+ callbacks with network messages from a NodeConn
+CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....:
+ data structures that should map to corresponding structures in
+ bitcoin/primitives
+msg_block, msg_tx, msg_headers, etc.:
+ data structures that represent network messages
+ser_*, deser_*: functions that handle serialization/deserialization
+"""
import struct
import socket
@@ -1540,6 +1538,7 @@ class NodeConnCB(object):
if conn.ver_send > BIP0031_VERSION:
conn.send_message(msg_pong(message.nonce))
def on_reject(self, conn, message): pass
+ def on_open(self, conn): pass
def on_close(self, conn): pass
def on_mempool(self, conn): pass
def on_pong(self, conn, message): pass
@@ -1614,7 +1613,7 @@ class NodeConn(asyncore.dispatcher):
"regtest": b"\xfa\xbf\xb5\xda", # regtest
}
- def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK):
+ def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True):
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
self.dstaddr = dstaddr
@@ -1631,14 +1630,16 @@ class NodeConn(asyncore.dispatcher):
self.disconnect = False
self.nServices = 0
- # stuff version msg into sendbuf
- vt = msg_version()
- vt.nServices = services
- vt.addrTo.ip = self.dstaddr
- vt.addrTo.port = self.dstport
- vt.addrFrom.ip = "0.0.0.0"
- vt.addrFrom.port = 0
- self.send_message(vt, True)
+ if send_version:
+ # stuff version msg into sendbuf
+ vt = msg_version()
+ vt.nServices = services
+ vt.addrTo.ip = self.dstaddr
+ vt.addrTo.port = self.dstport
+ vt.addrFrom.ip = "0.0.0.0"
+ vt.addrFrom.port = 0
+ self.send_message(vt, True)
+
print('MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' \
+ str(dstport))
@@ -1652,8 +1653,10 @@ class NodeConn(asyncore.dispatcher):
self.log.debug(msg)
def handle_connect(self):
- self.show_debug_msg("MiniNode: Connected & Listening: \n")
- self.state = "connected"
+ if self.state != "connected":
+ self.show_debug_msg("MiniNode: Connected & Listening: \n")
+ self.state = "connected"
+ self.cb.on_open(self)
def handle_close(self):
self.show_debug_msg("MiniNode: Closing Connection to %s:%d... "
@@ -1681,11 +1684,20 @@ class NodeConn(asyncore.dispatcher):
def writable(self):
with mininode_lock:
+ pre_connection = self.state == "connecting"
length = len(self.sendbuf)
- return (length > 0)
+ return (length > 0 or pre_connection)
def handle_write(self):
with mininode_lock:
+ # asyncore does not expose socket connection, only the first read/write
+ # event, thus we must check connection manually here to know when we
+ # actually connect
+ if self.state == "connecting":
+ self.handle_connect()
+ if not self.writable():
+ return
+
try:
sent = self.send(self.sendbuf)
except:
diff --git a/qa/rpc-tests/test_framework/netutil.py b/qa/rpc-tests/test_framework/netutil.py
index b92a9f6e1c..45d8e22d22 100644
--- a/qa/rpc-tests/test_framework/netutil.py
+++ b/qa/rpc-tests/test_framework/netutil.py
@@ -2,8 +2,10 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Linux network utilities.
-# Linux network utilities
+Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal
+"""
import sys
import socket
@@ -13,7 +15,6 @@ import array
import os
from binascii import unhexlify, hexlify
-# Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal
STATE_ESTABLISHED = '01'
STATE_SYN_SENT = '02'
STATE_SYN_RECV = '03'
diff --git a/qa/rpc-tests/test_framework/script.py b/qa/rpc-tests/test_framework/script.py
index 83bbf20479..3d9572788e 100644
--- a/qa/rpc-tests/test_framework/script.py
+++ b/qa/rpc-tests/test_framework/script.py
@@ -2,19 +2,11 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Functionality to build scripts, as well as SignatureHash().
-#
-# script.py
-#
-# This file is modified from python-bitcoinlib.
-#
-
-"""Scripts
-
-Functionality to build scripts, as well as SignatureHash().
+This file is modified from python-bitcoinlib.
"""
-
from .mininode import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string
from binascii import hexlify
import hashlib
diff --git a/qa/rpc-tests/test_framework/siphash.py b/qa/rpc-tests/test_framework/siphash.py
index 9c0574bd93..f68ecad36b 100644
--- a/qa/rpc-tests/test_framework/siphash.py
+++ b/qa/rpc-tests/test_framework/siphash.py
@@ -2,11 +2,10 @@
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Specialized SipHash-2-4 implementations.
-#
-# siphash.py - Specialized SipHash-2-4 implementations
-#
-# This implements SipHash-2-4 for 256-bit integers.
+This implements SipHash-2-4 for 256-bit integers.
+"""
def rotl64(n, b):
return n >> (64 - b) | (n & ((1 << (64 - b)) - 1)) << b
diff --git a/qa/rpc-tests/test_framework/socks5.py b/qa/rpc-tests/test_framework/socks5.py
index 372f5ed605..450bf3775e 100644
--- a/qa/rpc-tests/test_framework/socks5.py
+++ b/qa/rpc-tests/test_framework/socks5.py
@@ -2,9 +2,7 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-'''
-Dummy Socks5 server for testing.
-'''
+"""Dummy Socks5 server for testing."""
import socket, threading, queue
import traceback, sys
@@ -20,7 +18,7 @@ class AddressType:
### Utility functions
def recvall(s, n):
- '''Receive n bytes from a socket, or fail'''
+ """Receive n bytes from a socket, or fail."""
rv = bytearray()
while n > 0:
d = s.recv(n)
@@ -32,7 +30,7 @@ def recvall(s, n):
### Implementation classes
class Socks5Configuration(object):
- '''Proxy configuration'''
+ """Proxy configuration."""
def __init__(self):
self.addr = None # Bind address (must be set)
self.af = socket.AF_INET # Bind address family
@@ -40,7 +38,7 @@ class Socks5Configuration(object):
self.auth = False # Support authentication
class Socks5Command(object):
- '''Information about an incoming socks5 command'''
+ """Information about an incoming socks5 command."""
def __init__(self, cmd, atyp, addr, port, username, password):
self.cmd = cmd # Command (one of Command.*)
self.atyp = atyp # Address type (one of AddressType.*)
@@ -58,9 +56,7 @@ class Socks5Connection(object):
self.peer = peer
def handle(self):
- '''
- Handle socks5 request according to RFC1928
- '''
+ """Handle socks5 request according to RFC192."""
try:
# Verify socks version
ver = recvall(self.conn, 1)[0]
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index 98c4f6070b..c5e9c6a658 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -2,8 +2,7 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# Base class for RPC testing
+"""Base class for RPC testing."""
import logging
import optparse
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 1d6c9aa230..e838a40582 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -2,11 +2,7 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-
-#
-# Helpful routines for regression testing
-#
+"""Helpful routines for regression testing."""
import os
import sys
@@ -375,28 +371,19 @@ def stop_node(node, i):
node.stop()
except http.client.CannotSendRequest as e:
print("WARN: Unable to stop node: " + repr(e))
- bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
+ return_code = bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
+ assert_equal(return_code, 0)
del bitcoind_processes[i]
def stop_nodes(nodes):
- for node in nodes:
- try:
- node.stop()
- except http.client.CannotSendRequest as e:
- print("WARN: Unable to stop node: " + repr(e))
- del nodes[:] # Emptying array closes connections as a side effect
- wait_bitcoinds()
+ for i, node in enumerate(nodes):
+ stop_node(node, i)
+ assert not bitcoind_processes.values() # All connections must be gone now
def set_node_times(nodes, t):
for node in nodes:
node.setmocktime(t)
-def wait_bitcoinds():
- # Wait for all bitcoinds to cleanly exit
- for bitcoind in bitcoind_processes.values():
- bitcoind.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
- bitcoind_processes.clear()
-
def connect_nodes(from_connection, node_num):
ip_port = "127.0.0.1:"+str(p2p_port(node_num))
from_connection.addnode(ip_port, "onetry")
@@ -524,14 +511,18 @@ def assert_fee_amount(fee, tx_size, fee_per_kB):
if fee > (tx_size + 2) * fee_per_kB / 1000:
raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee)))
-def assert_equal(thing1, thing2):
- if thing1 != thing2:
- raise AssertionError("%s != %s"%(str(thing1),str(thing2)))
+def assert_equal(thing1, thing2, *args):
+ if thing1 != thing2 or any(thing1 != arg for arg in args):
+ raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args))
def assert_greater_than(thing1, thing2):
if thing1 <= thing2:
raise AssertionError("%s <= %s"%(str(thing1),str(thing2)))
+def assert_greater_than_or_equal(thing1, thing2):
+ if thing1 < thing2:
+ raise AssertionError("%s < %s"%(str(thing1),str(thing2)))
+
def assert_raises(exc, fun, *args, **kwds):
assert_raises_message(exc, None, fun, *args, **kwds)
@@ -546,6 +537,35 @@ def assert_raises_message(exc, message, fun, *args, **kwds):
else:
raise AssertionError("No exception raised")
+def assert_raises_jsonrpc(code, message, fun, *args, **kwds):
+ """Run an RPC and verify that a specific JSONRPC exception code and message is raised.
+
+ Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException
+ and verifies that the error code and message are as expected. Throws AssertionError if
+ no JSONRPCException was returned or if the error code/message are not as expected.
+
+ Args:
+ code (int), optional: the error code returned by the RPC call (defined
+ in src/rpc/protocol.h). Set to None if checking the error code is not required.
+ message (string), optional: [a substring of] the error string returned by the
+ RPC call. Set to None if checking the error string is not required
+ fun (function): the function to call. This should be the name of an RPC.
+ args*: positional arguments for the function.
+ kwds**: named arguments for the function.
+ """
+ try:
+ fun(*args, **kwds)
+ except JSONRPCException as e:
+ # JSONRPCException was thrown as expected. Check the code and message values are correct.
+ if (code is not None) and (code != e.error["code"]):
+ raise AssertionError("Unexpected JSONRPC error code %i" % e.error["code"])
+ if (message is not None) and (message not in e.error['message']):
+ raise AssertionError("Expected substring not found:"+e.error['message'])
+ except Exception as e:
+ raise AssertionError("Unexpected exception raised: "+type(e).__name__)
+ else:
+ raise AssertionError("No exception raised")
+
def assert_is_hex_string(string):
try:
int(string, 16)
@@ -654,10 +674,10 @@ def create_tx(node, coinbase, to_address, amount):
# Create a spend of each passed-in utxo, splicing in "txouts" to each raw
# transaction to make it large. See gen_return_txouts() above.
-def create_lots_of_big_transactions(node, txouts, utxos, fee):
+def create_lots_of_big_transactions(node, txouts, utxos, num, fee):
addr = node.getnewaddress()
txids = []
- for _ in range(len(utxos)):
+ for _ in range(num):
t = utxos.pop()
inputs=[{ "txid" : t["txid"], "vout" : t["vout"]}]
outputs = {}
@@ -672,13 +692,17 @@ def create_lots_of_big_transactions(node, txouts, utxos, fee):
txids.append(txid)
return txids
-def mine_large_block(node):
+def mine_large_block(node, utxos=None):
# generate a 66k transaction,
# and 14 of them is close to the 1MB block limit
+ num = 14
txouts = gen_return_txouts()
- utxos = node.listunspent()[:14]
+ utxos = utxos if utxos is not None else []
+ if len(utxos) < num:
+ utxos.clear()
+ utxos.extend(node.listunspent())
fee = 100 * node.getnetworkinfo()["relayfee"]
- create_lots_of_big_transactions(node, txouts, utxos, fee=fee)
+ create_lots_of_big_transactions(node, txouts, utxos, num, fee=fee)
node.generate(1)
def get_bip9_status(node, key):
diff --git a/qa/rpc-tests/txn_clone.py b/qa/rpc-tests/txn_clone.py
index 22f850ece6..7a3b8d3474 100755
--- a/qa/rpc-tests/txn_clone.py
+++ b/qa/rpc-tests/txn_clone.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 proper accounting with an equivalent malleability clone
-#
+"""Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py
index 84944c3c19..5b12cf4c29 100755
--- a/qa/rpc-tests/txn_doublespend.py
+++ b/qa/rpc-tests/txn_doublespend.py
@@ -2,10 +2,7 @@
# Copyright (c) 2014-2016 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 proper accounting with a double-spend conflict
-#
+"""Test the wallet accounts properly when there is a double-spend conflict."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/wallet-accounts.py b/qa/rpc-tests/wallet-accounts.py
index c51181e4f8..ea12d4ec22 100755
--- a/qa/rpc-tests/wallet-accounts.py
+++ b/qa/rpc-tests/wallet-accounts.py
@@ -2,16 +2,22 @@
# Copyright (c) 2016 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 account RPCs.
+
+RPCs tested are:
+ - getaccountaddress
+ - getaddressesbyaccount
+ - setaccount
+ - sendfrom (with account arguments)
+ - move (with account arguments)
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
start_nodes,
- start_node,
assert_equal,
- connect_nodes_bi,
)
-
class WalletAccountsTest(BitcoinTestFramework):
def __init__(self):
diff --git a/qa/rpc-tests/wallet-dump.py b/qa/rpc-tests/wallet-dump.py
index c6dc2e3d10..b819b72b75 100755
--- a/qa/rpc-tests/wallet-dump.py
+++ b/qa/rpc-tests/wallet-dump.py
@@ -2,6 +2,7 @@
# Copyright (c) 2016 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 dumpwallet RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (start_nodes, start_node, assert_equal, bitcoind_processes)
diff --git a/qa/rpc-tests/wallet-hd.py b/qa/rpc-tests/wallet-hd.py
index a49d91f6f4..bf07590098 100755
--- a/qa/rpc-tests/wallet-hd.py
+++ b/qa/rpc-tests/wallet-hd.py
@@ -2,6 +2,7 @@
# Copyright (c) 2016 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 Hierarchical Deterministic wallet function."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index 3c0dc0f4ea..ddeac657e5 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -2,7 +2,7 @@
# Copyright (c) 2014-2016 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."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -330,10 +330,12 @@ class WalletTest (BitcoinTestFramework):
# disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463
# '-salvagewallet',
]
+ chainlimit = 6
for m in maintenance:
print("check " + m)
stop_nodes(self.nodes)
- self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3)
+ # set lower ancestor limit for later
+ self.nodes = start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3)
while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]:
# reindex will leave rpc warm up "early"; Wait for it to finish
time.sleep(0.1)
@@ -346,5 +348,56 @@ class WalletTest (BitcoinTestFramework):
assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1])
assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0)
+ # ==Check that wallet prefers to use coins that don't exceed mempool limits =====
+
+ # Get all non-zero utxos together
+ chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()]
+ singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True)
+ self.nodes[0].generate(1)
+ node0_balance = self.nodes[0].getbalance()
+ # Split into two chains
+ rawtx = self.nodes[0].createrawtransaction([{"txid":singletxid, "vout":0}], {chain_addrs[0]:node0_balance/2-Decimal('0.01'), chain_addrs[1]:node0_balance/2-Decimal('0.01')})
+ signedtx = self.nodes[0].signrawtransaction(rawtx)
+ singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"])
+ self.nodes[0].generate(1)
+
+ # Make a long chain of unconfirmed payments without hitting mempool limit
+ # Each tx we make leaves only one output of change on a chain 1 longer
+ # Since the amount to send is always much less than the outputs, we only ever need one output
+ # So we should be able to generate exactly chainlimit txs for each original output
+ sending_addr = self.nodes[1].getnewaddress()
+ txid_list = []
+ for i in range(chainlimit*2):
+ txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')))
+ assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit*2)
+ assert_equal(len(txid_list), chainlimit*2)
+
+ # Without walletrejectlongchains, we will still generate a txid
+ # The tx will be stored in the wallet but not accepted to the mempool
+ extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))
+ assert(extra_txid not in self.nodes[0].getrawmempool())
+ assert(extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()])
+ self.nodes[0].abandontransaction(extra_txid)
+ total_txs = len(self.nodes[0].listtransactions("*",99999))
+
+ # Try with walletrejectlongchains
+ # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
+ stop_node(self.nodes[0],0)
+ self.nodes[0] = start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)])
+
+ # wait for loadmempool
+ timeout = 10
+ while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit*2):
+ time.sleep(0.5)
+ timeout -= 0.5
+ assert_equal(len(self.nodes[0].getrawmempool()), chainlimit*2)
+
+ node0_balance = self.nodes[0].getbalance()
+ # With walletrejectlongchains we will not create the tx and store it in our wallet.
+ assert_raises_message(JSONRPCException, "mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))
+
+ # Verify nothing new in wallet
+ assert_equal(total_txs, len(self.nodes[0].listtransactions("*",99999)))
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py
index e12cb10a50..ea249096cf 100755
--- a/qa/rpc-tests/walletbackup.py
+++ b/qa/rpc-tests/walletbackup.py
@@ -2,9 +2,7 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-"""
-Exercise the wallet backup code. Ported from walletbackup.sh.
+"""Test the wallet backup features.
Test case is:
4 nodes. 1 2 and 3 send transactions between each other,
diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py
index 17ba53a844..9597d05f3a 100755
--- a/qa/rpc-tests/zapwallettxes.py
+++ b/qa/rpc-tests/zapwallettxes.py
@@ -2,7 +2,16 @@
# Copyright (c) 2014-2016 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 zapwallettxes functionality.
+- start three bitcoind nodes
+- create four transactions on node 0 - two are confirmed and two are
+ unconfirmed.
+- restart node 1 and verify that both the confirmed and the unconfirmed
+ transactions are still available.
+- restart node 0 and verify that the confirmed transactions are still
+ available, but that the unconfirmed transaction has been zapped.
+"""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py
index 3a116317fe..1e2f06bd54 100755
--- a/qa/rpc-tests/zmq_test.py
+++ b/qa/rpc-tests/zmq_test.py
@@ -2,19 +2,13 @@
# Copyright (c) 2015-2016 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 ZMQ interface
-#
+"""Test the ZMQ API."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
import zmq
import struct
-import http.client
-import urllib.parse
-
class ZMQTest (BitcoinTestFramework):
def __init__(self):