Auto merge of #4874 - str4d:rpc-tests-py, r=str4d

Backport migration from rpc-tests.sh to rpc-tests.py

Cherry-picked from the following upstream PRs:
- bitcoin/bitcoin#6567
- bitcoin/bitcoin#6523
- bitcoin/bitcoin#6616
- bitcoin/bitcoin#6788
  - Only the commit fixing `rpc-tests.py`
- bitcoin/bitcoin#6791
  - Only the fix to `qa/rpc-tests/README.md`
- bitcoin/bitcoin#6827
- bitcoin/bitcoin#6930
- bitcoin/bitcoin#6804
- bitcoin/bitcoin#7029
- bitcoin/bitcoin#7028
- bitcoin/bitcoin#7027
- bitcoin/bitcoin#7135
- bitcoin/bitcoin#7209
- bitcoin/bitcoin#7635
- bitcoin/bitcoin#7778
- bitcoin/bitcoin#7851
- bitcoin/bitcoin#7814
  - Only the changes to the new .py files in this PR.
- bitcoin/bitcoin#7971
- bitcoin/bitcoin#7972
- bitcoin/bitcoin#8056
  - Only the first commit.
- bitcoin/bitcoin#8098
- bitcoin/bitcoin#8104
- bitcoin/bitcoin#8133
  - Only the `rpc-tests.py` commit.
- bitcoin/bitcoin#8066
- bitcoin/bitcoin#8216
  - Only the last two commits.
- bitcoin/bitcoin#8254
- bitcoin/bitcoin#8400
- bitcoin/bitcoin#8482
  - Excluding the first commit (only affects RPC tests we don't have).
- bitcoin/bitcoin#8551
- bitcoin/bitcoin#8607
  - Only the pull-tester commit, for conflict removal.
- bitcoin/bitcoin#8625
- bitcoin/bitcoin#8713
- bitcoin/bitcoin#8750
- bitcoin/bitcoin#8789
- bitcoin/bitcoin#9098
- bitcoin/bitcoin#9276
  - Excluding the second commit (we don't have the changes it requires).
- bitcoin/bitcoin#9657
- bitcoin/bitcoin#9807
- bitcoin/bitcoin#9766
- bitcoin/bitcoin#9823
This commit is contained in:
Homu 2020-12-02 13:53:52 +00:00
commit c8896f9907
96 changed files with 2122 additions and 1279 deletions

7
.gitignore vendored
View File

@ -104,10 +104,9 @@ afl-temp
linux-coverage-build
linux-build
win32-build
qa/pull-tester/run-bitcoind-for-test.sh
qa/pull-tester/tests-config.sh
qa/pull-tester/cache/*
qa/pull-tester/test.*/*
qa/pull-tester/tests_config.py
qa/pull-tester/tests_config.ini
qa/cache/*
!src/leveldb*/Makefile

View File

@ -147,7 +147,7 @@ dist_noinst_SCRIPTS = autogen.sh zcutil/build-debian-package.sh zcutil/build.sh
RUST_DIST = $(top_srcdir)/.cargo $(top_srcdir)/Cargo.toml $(top_srcdir)/Cargo.lock rust-toolchain
EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.sh qa/rpc-tests qa/zcash $(DIST_DOCS) $(BIN_CHECKS) $(RUST_DIST)
EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-tests qa/zcash $(DIST_DOCS) $(BIN_CHECKS) $(RUST_DIST)
install-exec-hook:
mv $(DESTDIR)$(bindir)/fetch-params.sh $(DESTDIR)$(bindir)/zcash-fetch-params
@ -159,6 +159,7 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-man
clean-local:
rm -rf test_bitcoin.coverage/ zcash-gtest.coverage/ total.coverage/
rm -rf afl-temp
rm -rf qa/pull-tester/__pycache__
distclean-local:
rm -f zcutil/bin/db_*

View File

@ -968,8 +968,8 @@ AC_SUBST(EVENT_PTHREADS_LIBS)
AC_SUBST(ZMQ_LIBS)
AC_SUBST(LIBZCASH_LIBS)
AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile src/test/buildenv.py])
AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh])
AC_CONFIG_FILES([qa/pull-tester/tests-config.sh],[chmod +x qa/pull-tester/tests-config.sh])
AC_CONFIG_FILES([qa/pull-tester/tests_config.ini],[chmod +x qa/pull-tester/tests_config.ini])
AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py])
dnl boost's m4 checks do something really nasty: they export these vars. As a
dnl result, they leak into secp256k1's configure and crazy things happen.
@ -1010,6 +1010,15 @@ case $host in
;;
esac
dnl Replace the BUILDDIR path with the correct Windows path if compiling on Native Windows
case ${OS} in
*Windows*)
sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' qa/pull-tester/tests_config.py > qa/pull-tester/tests_config-2.py
mv qa/pull-tester/tests_config-2.py qa/pull-tester/tests_config.py
chmod +x qa/pull-tester/tests_config.py
;;
esac
echo
echo "Options used to compile and link:"
echo " with wallet = $enable_wallet"

View File

@ -40,7 +40,7 @@ Typically, it is packaged by distributions as something like
*libzmq5-dev*. The C++ wrapper for ZeroMQ is *not* needed.
In order to run the example Python client scripts in contrib/ one must
also install *python-zmq*, though this is not necessary for daemon
also install *python3-zmq*, though this is not necessary for daemon
operation.
## Security WARNING

87
qa/README.md Normal file
View File

@ -0,0 +1,87 @@
The [pull-tester](/qa/pull-tester/) folder contains a script to call
multiple tests from the [rpc-tests](/qa/rpc-tests/) folder.
Every pull request to the zcash repository is built and run through
the regression test suite. You can also run all or only individual
tests locally.
Test dependencies
=================
Before running the tests, the following must be installed.
Unix
----
The python3-zmq library is required. On Ubuntu or Debian it can be installed via:
```
sudo apt-get install python3-zmq
```
OS X
------
```
pip3 install pyzmq
```
Running tests
=============
You can run any single test by calling
qa/pull-tester/rpc-tests.py <testname>
Or you can run any combination of tests by calling
qa/pull-tester/rpc-tests.py <testname1> <testname2> <testname3> ...
Run the regression test suite with
qa/pull-tester/rpc-tests.py
Run all possible tests with
qa/pull-tester/rpc-tests.py --extended
By default, tests will be run in parallel. To specify how many jobs to run,
append `--jobs=n` (default n=4).
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:
```
-h, --help show this help message and exit
--nocleanup Leave zcashds and test.* datadir on exit or error
--noshutdown Don't stop zcashds after the test execution
--srcdir=SRCDIR Source directory containing zcashd/zcash-cli
(default: ../../src)
--tmpdir=TMPDIR Root directory for datadirs
--tracerpc Print out all RPC calls as they are made
--coveragedir=COVERAGEDIR
Write tested RPC commands into this directory
```
If you set the environment variable `PYTHON_DEBUG=1` you will get some debug
output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`).
A 200-block -regtest blockchain and wallets for four nodes
is created the first time a regression test is run and
is stored in the cache/ directory. Each node has the miner
subsidy from 25 mature blocks (25*10=250 ZEC) in its wallet.
After the first run, the cache/ blockchain and wallets are
copied into a temporary directory and used as the initial
test state.
If you get into a bad state, you should be able
to recover with:
```bash
rm -rf cache
killall zcashd
```
Writing tests
=============
You are encouraged to write tests for new or existing features.
Further information about the test framework and individual RPC
tests is found in [qa/rpc-tests](/qa/rpc-tests).

428
qa/pull-tester/rpc-tests.py Executable file
View File

@ -0,0 +1,428 @@
#!/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.
"""
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.
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
import sys
import subprocess
import tempfile
import re
SERIAL_SCRIPTS = [
# These tests involve enough shielded spends (consuming all CPU
# cores) that we can't run them in parallel.
'mergetoaddress_sapling.py',
'mergetoaddress_sprout.py',
'wallet_shieldingcoinbase.py',
]
BASE_SCRIPTS= [
# Scripts that are run by the travis build process
# Longest test should go first, to favor running tests in parallel
# vv Tests less than 5m vv
'wallet.py',
'wallet_shieldcoinbase_sprout.py',
'sprout_sapling_migration.py',
'remove_sprout_shielding.py',
'zcjoinsplitdoublespend.py',
# vv Tests less than 2m vv
'zcjoinsplit.py',
'mergetoaddress_mixednotes.py',
'wallet_shieldcoinbase_sapling.py',
'turnstile.py',
'walletbackup.py',
'zkey_import_export.py',
'prioritisetransaction.py',
'wallet_changeaddresses.py',
'wallet_listreceived.py',
'mempool_tx_expiry.py',
'finalsaplingroot.py',
'wallet_overwintertx.py',
'wallet_persistence.py',
'wallet_listnotes.py',
# vv Tests less than 60s vv
'fundrawtransaction.py',
'reorg_limit.py',
'mempool_limit.py',
'p2p-fullblocktest.py',
'paymentdisclosure.py',
# vv Tests less than 30s vv
'wallet_1941.py',
'wallet_addresses.py',
'wallet_anchorfork.py',
'wallet_changeindicator.py',
'wallet_import_export.py',
'wallet_nullifiers.py',
'wallet_sapling.py',
'wallet_sendmany_any_taddr.py',
'wallet_treestate.py',
'listtransactions.py',
'mempool_resurrect_test.py',
'txn_doublespend.py',
'txn_doublespend.py --mineblock',
'getchaintips.py',
'rawtransactions.py',
'getrawtransaction_insight.py',
'rest.py',
'mempool_spendcoinbase.py',
'mempool_reorg.py',
'mempool_nu_activation.py',
'httpbasics.py',
'multi_rpc.py',
'zapwallettxes.py',
'proxy_test.py',
'merkle_blocks.py',
'signrawtransactions.py',
'signrawtransaction_offline.py',
'key_import_export.py',
'nodehandling.py',
'reindex.py',
'addressindex.py',
'spentindex.py',
'timestampindex.py',
'decodescript.py',
'blockchain.py',
'disablewallet.py',
'keypool.py',
'getblocktemplate.py',
'bip65-cltv-p2p.py',
'bipdersig-p2p.py',
'p2p_nu_peer_management.py',
'rewind_index.py',
'p2p_txexpiry_dos.py',
'p2p_txexpiringsoon.py',
'p2p_node_bloom.py',
'regtest_signrawtransaction.py',
'shorter_block_times.py',
'mining_shielded_coinbase.py',
'coinbase_funding_streams.py',
'framework.py',
'sapling_rewind_check.py',
'feature_zip221.py',
'upgrade_golden.py',
'post_heartwood_rollback.py',
'feature_logging.py',
'feature_walletfile.py',
]
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
# vv Tests less than 2m vv
'getblocktemplate_longpoll.py',
# vv Tests less than 60s vv
'rpcbind_test.py',
# vv Tests less than 30s vv
'getblocktemplate_proposals.py',
'forknotify.py',
'hardforkdetection.py',
'invalidateblock.py',
'receivedby.py',
'maxblocksinflight.py',
'invalidblockrequest.py',
# 'forknotify.py',
'p2p-acceptblock.py',
'wallet_db_flush.py',
]
ALL_SCRIPTS = SERIAL_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)
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
zmq # Silences pyflakes
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:
# No individual tests have been specified. Run base tests, and
# optionally ZMQ tests and extended tests.
test_list = SERIAL_SCRIPTS + 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 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)
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/zcashd' + exeext
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()
flags.append(coverage.flag)
print("Initializing coverage directory at %s\n" % coverage.dir)
else:
coverage = None
if len(test_list) > 1 and jobs > 1:
# Populate cache
subprocess.check_output([tests_dir + 'create_cache.py'] + flags)
#Run Tests
all_passed = True
time_sum = 0
time0 = time.time()
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]
for _ in range(len(test_list)):
(name, stdout, stderr, passed, duration) = job_queue.get_next()
all_passed = all_passed and passed
time_sum += duration
print('\n' + BOLD[1] + name + BOLD[0] + ":")
print('' if passed else stdout + '\n', end='')
print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='')
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)))
if coverage:
coverage.report_rpc_coverage()
print("Cleaning up coverage data")
coverage.cleanup()
sys.exit(not all_passed)
class RPCTestHandler:
"""
Trigger the testscrips passed in via the list.
"""
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
# In case there is a graveyard of zombie bitcoinds, we can apply a
# pseudorandom offset to hopefully jump over them.
# (625 is PORT_RANGE/MAX_NODES)
self.portseed_offset = int(time.time() * 1000) % 625
self.jobs = []
def get_next(self):
while self.num_running < self.num_jobs and self.test_list:
# Add tests
self.num_running += 1
t = self.test_list.pop(0)
port_seed = ["--portseed={}".format(len(self.test_list) + self.portseed_offset)]
log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
self.jobs.append((t,
time.time(),
subprocess.Popen((self.tests_dir + t).split() + self.flags + port_seed,
universal_newlines=True,
stdout=log_stdout,
stderr=log_stderr),
log_stdout,
log_stderr))
# Run serial scripts on their own. We always run these first,
# so we won't have added any other jobs yet.
if t in SERIAL_SCRIPTS:
break
if not self.jobs:
raise IndexError('pop from empty list')
while True:
# Return first proc that finishes
time.sleep(.5)
for j in self.jobs:
(name, time0, proc, log_out, log_err) = j
if proc.poll() is not None:
log_out.seek(0), log_err.seek(0)
[stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)]
log_out.close(), log_err.close()
passed = stderr == "" and proc.returncode == 0
self.num_running -= 1
self.jobs.remove(j)
return name, stdout, stderr, passed, int(time.time() - time0)
print('.', end='', flush=True)
class RPCCoverage(object):
"""
Coverage reporting utilities for pull-tester.
Coverage calculation works by having each test script subprocess write
coverage files into a particular directory. These files contain the RPC
commands invoked during testing, as well as a complete listing of RPC
commands per `bitcoin-cli help` (`rpc_interface.txt`).
After all tests complete, the commands run are combined and diff'd against
the complete list to calculate uncovered RPC commands.
See also: qa/rpc-tests/test_framework/coverage.py
"""
def __init__(self):
self.dir = tempfile.mkdtemp(prefix="coverage")
self.flag = '--coveragedir=%s' % self.dir
def report_rpc_coverage(self):
"""
Print out RPC commands that were unexercised by tests.
"""
uncovered = self._get_uncovered_rpc_commands()
if uncovered:
print("Uncovered RPC commands:")
print("".join((" - %s\n" % i) for i in sorted(uncovered)))
else:
print("All RPC commands covered.")
def cleanup(self):
return shutil.rmtree(self.dir)
def _get_uncovered_rpc_commands(self):
"""
Return a set of currently untested RPC commands.
"""
# This is shared from `qa/rpc-tests/test-framework/coverage.py`
reference_filename = 'rpc_interface.txt'
coverage_file_prefix = 'coverage.'
coverage_ref_filename = os.path.join(self.dir, reference_filename)
coverage_filenames = set()
all_cmds = set()
covered_cmds = set()
if not os.path.isfile(coverage_ref_filename):
raise RuntimeError("No coverage reference found")
with open(coverage_ref_filename, 'r') as f:
all_cmds.update([i.strip() for i in f.readlines()])
for root, dirs, files in os.walk(self.dir):
for filename in files:
if filename.startswith(coverage_file_prefix):
coverage_filenames.add(os.path.join(root, filename))
for filename in coverage_filenames:
with open(filename, 'r') as f:
covered_cmds.update([i.strip() for i in f.readlines()])
return all_cmds - covered_cmds
if __name__ == '__main__':
main()

View File

@ -1,179 +0,0 @@
#!/bin/bash
set -e -o pipefail
CURDIR=$(cd $(dirname "$0"); pwd)
# Get BUILDDIR and REAL_BITCOIND
. "${CURDIR}/tests-config.sh"
export BITCOIND=${REAL_BITCOIND}
export BITCOINCLI=${REAL_BITCOINCLI}
#Run the tests
testScripts=(
'paymentdisclosure.py'
'prioritisetransaction.py'
'wallet_treestate.py'
'wallet_anchorfork.py'
'wallet_changeaddresses.py'
'wallet_changeindicator.py'
'wallet_import_export.py'
'wallet_sendmany_any_taddr.py'
'wallet_shieldingcoinbase.py'
'wallet_shieldcoinbase_sprout.py'
'wallet_shieldcoinbase_sapling.py'
'wallet_listreceived.py'
'wallet.py'
'wallet_overwintertx.py'
'wallet_persistence.py'
'wallet_nullifiers.py'
'wallet_1941.py'
'wallet_addresses.py'
'wallet_sapling.py'
'wallet_listnotes.py'
'mergetoaddress_sprout.py'
'mergetoaddress_sapling.py'
'mergetoaddress_mixednotes.py'
'listtransactions.py'
'mempool_resurrect_test.py'
'txn_doublespend.py'
'txn_doublespend.py --mineblock'
'getchaintips.py'
'rawtransactions.py'
'getrawtransaction_insight.py'
'rest.py'
'mempool_limit.py'
'mempool_spendcoinbase.py'
'mempool_reorg.py'
'mempool_nu_activation.py'
'mempool_tx_expiry.py'
'httpbasics.py'
'multi_rpc.py'
'zapwallettxes.py'
'proxy_test.py'
'merkle_blocks.py'
'fundrawtransaction.py'
'signrawtransactions.py'
'signrawtransaction_offline.py'
'walletbackup.py'
'key_import_export.py'
'nodehandling.py'
'reindex.py'
'addressindex.py'
'spentindex.py'
'timestampindex.py'
'decodescript.py'
'blockchain.py'
'disablewallet.py'
'zcjoinsplit.py'
'zcjoinsplitdoublespend.py'
'zkey_import_export.py'
'reorg_limit.py'
'getblocktemplate.py'
'bip65-cltv-p2p.py'
'bipdersig-p2p.py'
'p2p_nu_peer_management.py'
'rewind_index.py'
'p2p_txexpiry_dos.py'
'p2p_txexpiringsoon.py'
'p2p_node_bloom.py'
'regtest_signrawtransaction.py'
'finalsaplingroot.py'
'shorter_block_times.py'
'sprout_sapling_migration.py'
'turnstile.py'
'mining_shielded_coinbase.py'
'coinbase_funding_streams.py'
'framework.py'
'sapling_rewind_check.py'
'feature_zip221.py'
'upgrade_golden.py'
'post_heartwood_rollback.py'
'feature_logging.py'
'remove_sprout_shielding.py'
'feature_walletfile.py'
);
testScriptsExt=(
'getblocktemplate_longpoll.py'
'getblocktemplate_proposals.py'
'pruning.py'
'forknotify.py'
'hardforkdetection.py'
'invalidateblock.py'
'keypool.py'
'receivedby.py'
'rpcbind_test.py'
# 'script_test.py'
'smartfees.py'
'maxblocksinflight.py'
'invalidblockrequest.py'
# 'forknotify.py'
'p2p-acceptblock.py'
'wallet_db_flush.py'
);
if [ "x$ENABLE_ZMQ" = "x1" ]; then
testScripts+=('zmq_test.py')
fi
extArg="-extended"
passOn=${@#$extArg}
successCount=0
declare -a failures
function runTestScript
{
local testName="$1"
shift
echo -e "=== Running testscript ${testName} ==="
local startTime=$(date +%s)
if eval "$@"
then
successCount=$(expr $successCount + 1)
echo "--- Success: ${testName} ($(($(date +%s) - $startTime))s) ---"
else
failures[${#failures[@]}]="$testName"
echo "!!! FAIL: ${testName} ($(($(date +%s) - $startTime))s) !!!"
fi
echo
}
if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then
for (( i = 0; i < ${#testScripts[@]}; i++ ))
do
if [ -z "$1" ] || [ "${1:0:1}" == "-" ] || [ "$1" == "${testScripts[$i]}" ] || [ "$1.py" == "${testScripts[$i]}" ]
then
runTestScript \
"${testScripts[$i]}" \
"${BUILDDIR}/qa/rpc-tests/${testScripts[$i]}" \
--srcdir "${BUILDDIR}/src" ${passOn}
fi
done
for (( i = 0; i < ${#testScriptsExt[@]}; i++ ))
do
if [ "$1" == $extArg ] || [ "$1" == "${testScriptsExt[$i]}" ] || [ "$1.py" == "${testScriptsExt[$i]}" ]
then
runTestScript \
"${testScriptsExt[$i]}" \
"${BUILDDIR}/qa/rpc-tests/${testScriptsExt[$i]}" \
--srcdir "${BUILDDIR}/src" ${passOn}
fi
done
echo -e "\n\nTests completed: $(expr $successCount + ${#failures[@]})"
echo "successes $successCount; failures: ${#failures[@]}"
if [ ${#failures[@]} -gt 0 ]
then
echo -e "\nFailing tests: ${failures[*]}"
exit 1
else
exit 0
fi
else
echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled"
fi

View File

@ -1,38 +0,0 @@
#!/bin/bash
# Copyright (c) 2013-2014 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
ZCASH_LOAD_TIMEOUT=500
DATADIR="@abs_top_builddir@/.zcash"
rm -rf "$DATADIR"
mkdir -p "$DATADIR"/regtest
touch "$DATADIR/zcash.conf"
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/zcashd@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 "$ZCASH_LOAD_TIMEOUT" && 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 "$ZCASH_LOAD_TIMEOUT" && 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

View File

@ -1,17 +0,0 @@
#!/bin/bash
# Copyright (c) 2013-2014 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
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
REAL_BITCOIND="$BUILDDIR/src/zcashd${EXEEXT}"
REAL_BITCOINCLI="$BUILDDIR/src/zcash-cli${EXEEXT}"

View File

@ -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

View File

@ -1,5 +1,5 @@
Regression tests of RPC interface
=================================
Regression tests
================
### [test_framework/test_framework.py](test_framework/test_framework.py)
Base class for RPC regression tests.
@ -7,40 +7,102 @@ Base class for RPC regression tests.
### [test_framework/util.py](test_framework/util.py)
Generally useful functions.
Notes
=====
### [test_framework/mininode.py](test_framework/mininode.py)
Basic code to support p2p connectivity to a bitcoind.
You can run a single test by calling `qa/pull-tester/rpc-tests.sh <testname>`.
### [test_framework/comptool.py](test_framework/comptool.py)
Framework for comparison-tool style, p2p tests.
Run all possible tests with `qa/pull-tester/rpc-tests.sh -extended`.
### [test_framework/script.py](test_framework/script.py)
Utilities for manipulating transaction scripts (originally from python-bitcoinlib)
Possible options:
### [test_framework/blockstore.py](test_framework/blockstore.py)
Implements disk-backed block and tx storage.
```
-h, --help show this help message and exit
--nocleanup Leave zcashds and test.* datadir on exit or error
--noshutdown Don't stop bitcoinds after the test execution
--srcdir=SRCDIR Source directory containing zcashd/zcash-cli (default:
../../src)
--tmpdir=TMPDIR Root directory for datadirs
--tracerpc Print out all RPC calls as they are made
```
### [test_framework/key.py](test_framework/key.py)
Wrapper around OpenSSL EC_Key (originally from python-bitcoinlib)
If you set the environment variable `PYTHON_DEBUG=1` you will get some debug output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.sh wallet`).
### [test_framework/bignum.py](test_framework/bignum.py)
Helpers for script.py
A 200-block -regtest blockchain and wallets for four nodes
is created the first time a regression test is run and
is stored in the cache/ directory. Each node has the miner
subsidy from 25 mature blocks (25*10=250 ZEC) in its wallet.
### [test_framework/blocktools.py](test_framework/blocktools.py)
Helper functions for creating blocks and transactions.
After the first run, the cache/ blockchain and wallets are
copied into a temporary directory and used as the initial
test state.
P2P test design notes
---------------------
If you get into a bad state, you should be able
to recover with:
## Mininode
* ```mininode.py``` contains all the definitions for objects that pass
over the network (```CBlock```, ```CTransaction```, etc, along with the network-level
wrappers for them, ```msg_block```, ```msg_tx```, etc).
* P2P tests have two threads. One thread handles all network communication
with the bitcoind(s) being tested (using python's asyncore package); the other
implements the test logic.
* ```NodeConn``` is the class used to connect to a bitcoind. If you implement
a callback class that derives from ```NodeConnCB``` and pass that to the
```NodeConn``` object, your code will receive the appropriate callbacks when
events of interest arrive. NOTE: be sure to call
```self.create_callback_map()``` in your derived classes' ```__init__```
function, so that the correct mappings are set up between p2p messages and your
callback functions.
* You can pass the same handler to multiple ```NodeConn```'s if you like, or pass
different ones to each -- whatever makes the most sense for your test.
* Call ```NetworkThread.start()``` after all ```NodeConn``` objects are created to
start the networking thread. (Continue with the test logic in your existing
thread.)
* RPC calls are available in p2p tests.
* Can be used to write free-form tests, where specific p2p-protocol behavior
is tested. Examples: ```p2p-accept-block.py```, ```maxblocksinflight.py```.
## Comptool
* Testing framework for writing tests that compare the block/tx acceptance
behavior of a bitcoind against 1 or more other bitcoind instances, or against
known outcomes, or both.
* Set the ```num_nodes``` variable (defined in ```ComparisonTestFramework```) to start up
1 or more nodes. If using 1 node, then ```--testbinary``` can be used as a command line
option to change the bitcoind binary used by the test. If using 2 or more nodes,
then ```--refbinary``` can be optionally used to change the bitcoind that will be used
on nodes 2 and up.
* Implement a (generator) function called ```get_tests()``` which yields ```TestInstance```s.
Each ```TestInstance``` consists of:
- a list of ```[object, outcome, hash]``` entries
* ```object``` is a ```CBlock```, ```CTransaction```, or
```CBlockHeader```. ```CBlock```'s and ```CTransaction```'s are tested for
acceptance. ```CBlockHeader```s can be used so that the test runner can deliver
complete headers-chains when requested from the bitcoind, to allow writing
tests where blocks can be delivered out of order but still processed by
headers-first bitcoind's.
* ```outcome``` is ```True```, ```False```, or ```None```. If ```True```
or ```False```, the tip is compared with the expected tip -- either the
block passed in, or the hash specified as the optional 3rd entry. If
```None``` is specified, then the test will compare all the bitcoind's
being tested to see if they all agree on what the best tip is.
* ```hash``` is the block hash of the tip to compare against. Optional to
specify; if left out then the hash of the block passed in will be used as
the expected tip. This allows for specifying an expected tip while testing
the handling of either invalid blocks or blocks delivered out of order,
which complete a longer chain.
- ```sync_every_block```: ```True/False```. If ```False```, then all blocks
are inv'ed together, and the test runner waits until the node receives the
last one, and tests only the last block for tip acceptance using the
outcome and specified tip. If ```True```, then each block is tested in
sequence and synced (this is slower when processing many blocks).
- ```sync_every_transaction```: ```True/False```. Analogous to
```sync_every_block```, except if the outcome on the last tx is "None",
then the contents of the entire mempool are compared across all bitcoind
connections. If ```True``` or ```False```, then only the last tx's
acceptance is tested against the given outcome.
* For examples of tests written in this framework, see
```invalidblockrequest.py``` and ```p2p-fullblocktest.py```.
```bash
rm -rf cache
killall zcashd
```

View File

@ -18,7 +18,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
initialize_chain_clean,
start_nodes,
stop_nodes,
connect_nodes,
@ -44,16 +43,17 @@ from binascii import hexlify, unhexlify
class AddressIndexTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def setup_network(self):
# -insightexplorer causes addressindex to be enabled (fAddressIndex = true)
args_insight = ('-debug', '-txindex', '-experimentalfeatures', '-insightexplorer')
# -lightwallet also causes addressindex to be enabled
args_lightwallet = ('-debug', '-txindex', '-experimentalfeatures', '-lightwalletd')
self.nodes = start_nodes(4, self.options.tmpdir, [args_insight] * 3 + [args_lightwallet])
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [args_insight] * 3 + [args_lightwallet])
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)
@ -237,7 +237,7 @@ class AddressIndexTest(BitcoinTestFramework):
# Test DisconnectBlock() by invalidating the most recent mined block
tip = self.nodes[1].getchaintips()[0]
for i in range(3):
for i in range(self.num_nodes):
node = self.nodes[i]
# the value 4 UTXO is no longer in our balance
check_balance(i, addr1, (expected - 4) * COIN, expected * COIN)

View File

@ -1,8 +1,7 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import start_nodes
@ -26,10 +25,11 @@ TODO: factor out common code from {bipdersig-p2p,bip65-cltv-p2p}.py.
class BIP65Test(ComparisonTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
def setup_network(self):
self.nodes = start_nodes(1, self.options.tmpdir,
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
self.is_network_split = False
@ -63,9 +63,10 @@ class BIP65Test(ComparisonTestFramework):
def get_tests(self):
self.coinbase_blocks = self.nodes[0].generate(1)
self.nodes[0].generate(100)
height = 102 # height of the next block to build
hashTip = self.nodes[0].getbestblockhash()
hashFinalSaplingRoot = int("0x" + self.nodes[0].getblock(hashTip)['finalsaplingroot'] , 0)
self.tip = int ("0x" + hashTip , 0)
self.tip = int("0x" + hashTip , 0)
self.nodeaddress = self.nodes[0].getnewaddress()
'''Check that the rules are enforced.'''
@ -81,7 +82,7 @@ class BIP65Test(ComparisonTestFramework):
self.block_time = gbt["mintime"] + 1
self.block_bits = int("0x" + gbt["bits"], 0)
block = create_block(self.tip, create_coinbase(101),
block = create_block(self.tip, create_coinbase(height),
self.block_time, self.block_bits,
hashFinalSaplingRoot)
block.nVersion = 4

View File

@ -1,8 +1,7 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import start_nodes
@ -11,7 +10,7 @@ from test_framework.blocktools import create_coinbase, create_block
from test_framework.comptool import TestInstance, TestManager
from test_framework.script import CScript
from binascii import unhexlify
import io
from io import BytesIO
'''
@ -26,10 +25,11 @@ TODO: factor out common code from {bipdersig-p2p,bip65-cltv-p2p}.py.
class BIP66Test(ComparisonTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
def setup_network(self):
self.nodes = start_nodes(1, self.options.tmpdir,
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
self.is_network_split = False
@ -47,7 +47,7 @@ class BIP66Test(ComparisonTestFramework):
rawtx = node.createrawtransaction(inputs, outputs)
signresult = node.signrawtransaction(rawtx)
tx = CTransaction()
f = io.BytesIO(unhexlify(signresult['hex']))
f = BytesIO(unhexlify(signresult['hex']))
tx.deserialize(f)
return tx
@ -71,9 +71,10 @@ class BIP66Test(ComparisonTestFramework):
def get_tests(self):
self.coinbase_blocks = self.nodes[0].generate(1)
self.nodes[0].generate(100)
height = 102 # height of the next block to build
hashTip = self.nodes[0].getbestblockhash()
hashFinalSaplingRoot = int("0x" + self.nodes[0].getblock(hashTip)['finalsaplingroot'], 0)
self.tip = int ("0x"+hashTip , 0)
self.tip = int("0x"+hashTip , 0)
self.nodeaddress = self.nodes[0].getnewaddress()
'''Check that the rules are enforced.'''
@ -89,7 +90,7 @@ class BIP66Test(ComparisonTestFramework):
self.block_time = gbt["mintime"] + 1
self.block_bits = int("0x" + gbt["bits"], 0)
block = create_block(self.tip, create_coinbase(101),
block = create_block(self.tip, create_coinbase(height),
self.block_time, self.block_bits,
hashFinalSaplingRoot)
block.nVersion = 4

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -12,7 +12,6 @@ import decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
initialize_chain,
assert_equal,
start_nodes,
connect_nodes_bi,
@ -26,12 +25,13 @@ class BlockchainTest(BitcoinTestFramework):
"""
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain(self.options.tmpdir)
def __init__(self):
super().__init__()
self.setup_clean_chain = False
self.num_nodes = 2
def setup_network(self, split=False):
self.nodes = start_nodes(2, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes, 0, 1)
self.is_network_split = False
self.sync_all()

View File

@ -12,7 +12,6 @@ from test_framework.util import (
assert_equal,
bitcoind_processes,
connect_nodes,
initialize_chain_clean,
start_node,
BLOSSOM_BRANCH_ID,
HEARTWOOD_BRANCH_ID,
@ -20,9 +19,10 @@ from test_framework.util import (
)
class CoinbaseFundingStreamsTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = True
def start_node_with(self, index, extra_args=[]):
args = [

29
qa/rpc-tests/create_cache.py Executable file
View File

@ -0,0 +1,29 @@
#!/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.
#
# Helper script to create the cache
# (see BitcoinTestFramework.setup_chain)
#
from test_framework.test_framework import BitcoinTestFramework
class CreateCache(BitcoinTestFramework):
def __init__(self):
super().__init__()
# Test network and test nodes are not required:
self.num_nodes = 0
self.nodes = []
def setup_network(self):
pass
def run_test(self):
pass
if __name__ == '__main__':
CreateCache().main()

View File

@ -1,10 +1,10 @@
#!/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 https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_nodes, hex_str_to_bytes, bytes_to_hex_str
from test_framework.mininode import CTransaction
from io import BytesIO
@ -13,12 +13,13 @@ from io import BytesIO
class DecodeScriptTest(BitcoinTestFramework):
"""Tests decoding scripts via RPC command "decodescript"."""
def setup_chain(self):
print('Initializing test directory ' + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
def setup_network(self, split=False):
self.nodes = start_nodes(1, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def decodescript_script_sig(self):

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -8,17 +8,18 @@
#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_nodes
from test_framework.util import start_nodes
class DisableWalletTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
def setup_network(self, split=False):
self.nodes = start_nodes(1, self.options.tmpdir, [['-disablewallet']])
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [['-disablewallet']])
self.is_network_split = False
self.sync_all()

View File

@ -12,7 +12,6 @@ from test_framework.util import (
assert_equal,
bytes_to_hex_str,
hex_str_to_bytes,
initialize_chain_clean,
start_nodes,
)
@ -24,16 +23,17 @@ CHAIN_HISTORY_ROOT_VERSION = 2010200
# Verify block header field 'hashLightClientRoot' is set correctly for Heartwood blocks.
class Zip221Test(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, extra_args=[[
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
'-nuparams=2bb40e60:1', # Blossom
'-nuparams=f5b9230b:10', # Heartwood
'-nurejectoldversions=false',
]] * 4)
]] * self.num_nodes)
def node_for_block(self, height):
block_header = CBlockHeader()

View File

@ -9,7 +9,6 @@ from test_framework.util import (
assert_equal,
connect_nodes_bi,
get_coinbase_address,
initialize_chain_clean,
start_nodes,
wait_and_assert_operationid_status,
)
@ -24,14 +23,15 @@ NULL_FIELD = "0000000000000000000000000000000000000000000000000000000000000000"
# is updated when Sapling transactions with outputs (commitments) are mined into a block.
class FinalSaplingRootTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def setup_network(self, split=False):
self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[[
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
'-txindex' # Avoid JSONRPC error: No information available about transaction
]] * 4 )
]] * self.num_nodes)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -14,6 +14,11 @@ import os
class ForkNotifyTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
alert_filename = None # Set by setup_network
def setup_network(self):

View File

@ -7,16 +7,16 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_raises,
connect_nodes,
initialize_chain_clean,
start_node,
check_node_log,
)
class FrameworkTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = True
def start_node_with(self, index, extra_args=[]):
args = []

View File

@ -1,12 +1,12 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_greater_than, \
initialize_chain_clean, start_nodes, connect_nodes_bi, stop_nodes, \
start_nodes, connect_nodes_bi, stop_nodes, \
wait_bitcoinds
from decimal import Decimal
@ -14,12 +14,13 @@ from decimal import Decimal
# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
def setup_network(self, split=False):
self.nodes = start_nodes(4, self.options.tmpdir,
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-experimentalfeatures', '-developerencryptwallet']] * 4)
connect_nodes_bi(self.nodes,0,1)
@ -32,7 +33,15 @@ class RawTransactionsTest(BitcoinTestFramework):
def run_test(self):
print("Mining blocks...")
feeTolerance = Decimal("0.00000002") #if the fee's positive delta is higher than this value tests will fail, neg. delta always fail the tests
min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
# if the fee's positive delta is higher than this value tests will fail,
# neg. delta always fail the tests.
# The size of the signature of every input may be at most 2 bytes larger
# than a minimum sized signature.
# = 2 bytes * minRelayTxFeePerByte
feeTolerance = max(2 * min_relay_tx_fee/1000, Decimal("0.00000001"))
self.nodes[2].generate(1)
self.sync_all()
@ -41,7 +50,7 @@ class RawTransactionsTest(BitcoinTestFramework):
watchonly_address = self.nodes[0].getnewaddress()
watchonly_pubkey = self.nodes[0].validateaddress(watchonly_address)["pubkey"]
watchonly_amount = 200
watchonly_amount = Decimal(200)
self.nodes[3].importpubkey(watchonly_pubkey, "", True)
watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address, watchonly_amount)
self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(), watchonly_amount / 10)
@ -202,7 +211,7 @@ class RawTransactionsTest(BitcoinTestFramework):
matchingOuts = 0
for i, out in enumerate(dec_tx['vout']):
totalOut += out['value']
if out['scriptPubKey']['addresses'][0] in outputs :
if out['scriptPubKey']['addresses'][0] in outputs:
matchingOuts+=1
else:
assert_equal(i, rawtxfund['changepos'])
@ -442,7 +451,7 @@ class RawTransactionsTest(BitcoinTestFramework):
stop_nodes(self.nodes)
wait_bitcoinds()
self.nodes = start_nodes(4, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)

View File

@ -5,7 +5,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, connect_nodes_bi, \
initialize_chain_clean, start_nodes
start_nodes
class GetBlockTemplateTest(BitcoinTestFramework):
@ -13,12 +13,13 @@ class GetBlockTemplateTest(BitcoinTestFramework):
Test getblocktemplate.
'''
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = True
def setup_network(self, split=False):
self.nodes = start_nodes(2, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
self.is_network_split=False
self.sync_all()

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -49,6 +49,11 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
Test longpolling with getblocktemplate.
'''
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
def run_test(self):
print("Warning: this test will take about 70 seconds in the best case. Be patient.")
self.nodes[0].generate(10)

View File

@ -1,10 +1,11 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import connect_nodes_bi
from binascii import a2b_hex, b2a_hex
from hashlib import sha256
@ -68,7 +69,7 @@ def genmrklroot(leaflist):
cur = n
return cur[0]
def template_to_bytes(tmpl, txlist):
def template_to_bytearray(tmpl, txlist):
blkver = pack('<L', tmpl['version'])
mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
reserved = b'\0'*32
@ -79,10 +80,10 @@ def template_to_bytes(tmpl, txlist):
blk += varlenEncode(len(txlist))
for tx in txlist:
blk += tx
return blk
return bytearray(blk)
def template_to_hex(tmpl, txlist):
return b2x(template_to_bytes(tmpl, txlist))
return b2x(template_to_bytearray(tmpl, txlist))
def assert_template(node, tmpl, txlist, expect):
rsp = node.getblocktemplate({'data':template_to_hex(tmpl, txlist),'mode':'proposal'})
@ -94,6 +95,15 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
Test block proposals with getblocktemplate.
'''
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
def setup_network(self):
self.nodes = self.setup_nodes()
connect_nodes_bi(self.nodes, 0, 1)
def run_test(self):
node = self.nodes[0]
node.generate(1) # Mine a block to leave initial block download
@ -159,7 +169,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
tmpl['bits'] = realbits
# Test 9: Bad merkle root
rawtmpl = template_to_bytes(tmpl, txlist)
rawtmpl = template_to_bytearray(tmpl, txlist)
rawtmpl[4+32] = (rawtmpl[4+32] + 1) % 0x100
rsp = node.getblocktemplate({'data':b2x(rawtmpl),'mode':'proposal'})
if rsp != 'bad-txnmrklroot':

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -12,9 +12,12 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class GetChainTipsTest (BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
def run_test (self):
BitcoinTestFramework.run_test (self)
tips = self.nodes[0].getchaintips ()
assert_equal (len (tips), 1)

View File

@ -11,7 +11,6 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.util import initialize_chain_clean
from test_framework.util import start_nodes, stop_nodes, connect_nodes
from test_framework.util import wait_bitcoinds
@ -20,15 +19,16 @@ from test_framework.mininode import COIN
class GetrawtransactionTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = True
def setup_network(self):
# -insightexplorer causes spentindex to be enabled (fSpentIndex = true)
self.nodes = start_nodes(3, self.options.tmpdir,
[['-debug', '-txindex', '-experimentalfeatures', '-insightexplorer']]*3)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
[['-debug', '-txindex', '-experimentalfeatures', '-insightexplorer']] * self.num_nodes)
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -8,25 +8,30 @@
#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, start_nodes, str_to_b64str
from test_framework.util import assert_equal, str_to_b64str
from http.client import HTTPConnection, BAD_REQUEST, NOT_FOUND
from urllib.parse import urlparse
import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir)
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = False
def setup_network(self):
self.nodes = self.setup_nodes()
def run_test(self):
#################################################
# lowlevel check for http persistent connection #
#################################################
url = urlparse(self.nodes[0].url)
url = urllib.parse.urlparse(self.nodes[0].url)
authpair = url.username + ':' + url.password
headers = {"Authorization": "Basic " + str_to_b64str(authpair)}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
@ -43,7 +48,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
# same should be if we add keep-alive because this should be the std. behaviour
headers = {"Authorization": "Basic " + str_to_b64str(authpair), "Connection": "keep-alive"}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
@ -60,7 +65,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
# now do the same with "Connection: close"
headers = {"Authorization": "Basic " + str_to_b64str(authpair), "Connection":"close"}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
@ -68,22 +73,22 @@ class HTTPBasicsTest (BitcoinTestFramework):
assert_equal(conn.sock!=None, False) # now the connection must be closed after the response
# node1 (2nd node) is running with disabled keep-alive option
urlNode1 = urlparse(self.nodes[1].url)
urlNode1 = urllib.parse.urlparse(self.nodes[1].url)
authpair = urlNode1.username + ':' + urlNode1.password
headers = {"Authorization": "Basic " + str_to_b64str(authpair)}
conn = HTTPConnection(urlNode1.hostname, urlNode1.port)
conn = http.client.HTTPConnection(urlNode1.hostname, urlNode1.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
assert_equal(b'"error":null' in out1, True)
# node2 (third node) is running with standard keep-alive parameters which means keep-alive is on
urlNode2 = urlparse(self.nodes[2].url)
urlNode2 = urllib.parse.urlparse(self.nodes[2].url)
authpair = urlNode2.username + ':' + urlNode2.password
headers = {"Authorization": "Basic " + str_to_b64str(authpair)}
conn = HTTPConnection(urlNode2.hostname, urlNode2.port)
conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
@ -91,17 +96,17 @@ class HTTPBasicsTest (BitcoinTestFramework):
assert_equal(conn.sock!=None, True) # connection must be closed because bitcoind should use keep-alive by default
# Check excessive request size
conn = HTTPConnection(urlNode2.hostname, urlNode2.port)
conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port)
conn.connect()
conn.request('GET', '/' + ('x'*1000), '', headers)
out1 = conn.getresponse()
assert_equal(out1.status, NOT_FOUND)
assert_equal(out1.status, http.client.NOT_FOUND)
conn = HTTPConnection(urlNode2.hostname, urlNode2.port)
conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port)
conn.connect()
conn.request('GET', '/' + ('x'*10000), '', headers)
out1 = conn.getresponse()
assert_equal(out1.status, BAD_REQUEST)
assert_equal(out1.status, http.client.BAD_REQUEST)
if __name__ == '__main__':

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -8,15 +8,16 @@
#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_node, \
from test_framework.util import start_node, \
connect_nodes_bi, sync_blocks
import time
class InvalidateTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 3
def setup_network(self):
self.nodes = []

View File

@ -1,8 +1,7 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import assert_equal
@ -28,6 +27,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
super().__init__()
self.num_nodes = 1
def run_test(self):
@ -40,18 +40,20 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
def get_tests(self):
if self.tip is None:
self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
self.tip = int("0x" + self.nodes[0].getbestblockhash(), 0)
self.block_time = int(time.time())+1
'''
Create a new block with an anyone-can-spend coinbase
'''
block = create_block(self.tip, create_coinbase(), self.block_time)
height = 1
block = create_block(self.tip, create_coinbase(height), self.block_time)
self.block_time += 1
block.solve()
# Save the coinbase for later
self.block1 = block
self.tip = block.sha256
height += 1
yield TestInstance([[block, True]])
'''
@ -59,11 +61,12 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
'''
test = TestInstance(sync_every_block=False)
for i in range(100):
block = create_block(self.tip, create_coinbase(), self.block_time)
block = create_block(self.tip, create_coinbase(height), self.block_time)
block.solve()
self.tip = block.sha256
self.block_time += 1
test.blocks_and_transactions.append([block, True])
height += 1
yield test
'''
@ -73,7 +76,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
coinbase, spend of that spend). Duplicate the 3rd transaction to
leave merkle root and blockheader unchanged but invalidate the block.
'''
block2 = create_block(self.tip, create_coinbase(), self.block_time)
block2 = create_block(self.tip, create_coinbase(height), self.block_time)
self.block_time += 1
# chr(81) is OP_TRUE
@ -95,11 +98,12 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
self.tip = block2.sha256
yield TestInstance([[block2, False], [block2_orig, True]])
height += 1
'''
Make sure that a totally screwed up block is not valid.
'''
block3 = create_block(self.tip, create_coinbase(), self.block_time)
block3 = create_block(self.tip, create_coinbase(height), self.block_time)
self.block_time += 1
block3.vtx[0].vout[0].nValue = 100*100000000 # Too high!
block3.vtx[0].sha256=None

View File

@ -6,21 +6,23 @@
from decimal import Decimal
from functools import reduce
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than, start_nodes, initialize_chain_clean, connect_nodes_bi
from test_framework.util import assert_equal, assert_greater_than, start_nodes, connect_nodes_bi
import logging
import sys
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout)
class KeyImportExportTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def setup_network(self, split=False):
self.nodes = start_nodes(4, self.options.tmpdir )
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir )
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)

View File

@ -1,21 +1,14 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
# Exercise the wallet keypool, and interaction with wallet encryption/locking
# Add python-bitcoinrpc to module search path:
from test_framework.authproxy import JSONRPCException
from test_framework.util import check_json_precision, initialize_chain, \
start_nodes, start_node, stop_nodes, wait_bitcoinds, bitcoind_processes
import os
import sys
import shutil
import tempfile
import traceback
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, \
start_nodes, start_node, bitcoind_processes
def check_array_result(object_array, to_match, expected):
"""
@ -38,92 +31,66 @@ def check_array_result(object_array, to_match, expected):
if num_matched == 0:
raise AssertionError("No objects matched %s"%(str(to_match)))
def run_test(nodes, tmpdir):
# Encrypt wallet and wait to terminate
nodes[0].encryptwallet('test')
bitcoind_processes[0].wait()
# Restart node 0
nodes[0] = start_node(0, tmpdir)
# Keep creating keys
addr = nodes[0].getnewaddress()
try:
class KeyPoolTest(BitcoinTestFramework):
def run_test(self):
nodes = self.nodes
# Encrypt wallet and wait to terminate
nodes[0].encryptwallet('test')
bitcoind_processes[0].wait()
# Restart node 0
nodes[0] = start_node(0, self.options.tmpdir)
# Keep creating keys
addr = nodes[0].getnewaddress()
raise AssertionError('Keypool should be exhausted after one address')
except JSONRPCException as e:
assert(e.error['code']==-12)
try:
addr = nodes[0].getnewaddress()
raise AssertionError('Keypool should be exhausted after one address')
except JSONRPCException as e:
assert(e.error['code']==-12)
# put three new keys in the keypool
nodes[0].walletpassphrase('test', 12000)
nodes[0].keypoolrefill(3)
nodes[0].walletlock()
# put three new keys in the keypool
nodes[0].walletpassphrase('test', 12000)
nodes[0].keypoolrefill(3)
nodes[0].walletlock()
# drain the keys
addr = set()
addr.add(nodes[0].getrawchangeaddress())
addr.add(nodes[0].getrawchangeaddress())
addr.add(nodes[0].getrawchangeaddress())
addr.add(nodes[0].getrawchangeaddress())
# assert that four unique addresses were returned
assert(len(addr) == 4)
# the next one should fail
try:
addr = nodes[0].getrawchangeaddress()
raise AssertionError('Keypool should be exhausted after three addresses')
except JSONRPCException as e:
assert(e.error['code']==-12)
# drain the keys
addr = set()
addr.add(nodes[0].getrawchangeaddress())
addr.add(nodes[0].getrawchangeaddress())
addr.add(nodes[0].getrawchangeaddress())
addr.add(nodes[0].getrawchangeaddress())
# assert that four unique addresses were returned
assert(len(addr) == 4)
# the next one should fail
try:
addr = nodes[0].getrawchangeaddress()
raise AssertionError('Keypool should be exhausted after three addresses')
except JSONRPCException as e:
assert(e.error['code']==-12)
# refill keypool with three new addresses
nodes[0].walletpassphrase('test', 12000)
nodes[0].keypoolrefill(3)
nodes[0].walletlock()
def main():
import optparse
# drain them by mining
nodes[0].generate(1)
nodes[0].generate(1)
nodes[0].generate(1)
nodes[0].generate(1)
try:
nodes[0].generate(1)
raise AssertionError('Keypool should be exhausted after three addesses')
except JSONRPCException as e:
assert_equal(e.error['code'], -12)
parser = optparse.OptionParser(usage="%prog [options]")
parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
help="Leave bitcoinds and test.* datadir on exit or error")
parser.add_option("--srcdir", dest="srcdir", default="../../src",
help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
help="Root directory for datadirs")
(options, args) = parser.parse_args()
def __init__(self):
super().__init__()
self.setup_clean_chain = False
self.num_nodes = 1
os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']
check_json_precision()
success = False
nodes = []
try:
print("Initializing test directory "+options.tmpdir)
if not os.path.isdir(options.tmpdir):
os.makedirs(options.tmpdir)
initialize_chain(options.tmpdir)
nodes = start_nodes(1, options.tmpdir, extra_args=[['-experimentalfeatures', '-developerencryptwallet']])
run_test(nodes, options.tmpdir)
success = True
except AssertionError as e:
print("Assertion failed: "+e.message)
except JSONRPCException as e:
print("JSONRPC error: "+e.error['message'])
traceback.print_tb(sys.exc_info()[2])
except Exception as e:
print("Unexpected exception caught during testing: ", e.error['message'], str(sys.exc_info()[0]))
traceback.print_tb(sys.exc_info()[2])
if not options.nocleanup:
print("Cleaning up")
stop_nodes(nodes)
wait_bitcoinds()
shutil.rmtree(options.tmpdir)
if success:
print("Tests successful")
sys.exit(0)
else:
print("Failed")
sys.exit(1)
def setup_network(self):
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[['-experimentalfeatures', '-developerencryptwallet']])
if __name__ == '__main__':
main()
KeyPoolTest().main()

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -31,6 +31,10 @@ def check_array_result(object_array, to_match, expected):
raise AssertionError("No objects matched %s"%(str(to_match)))
class ListTransactionsTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
def run_test(self):
# Simple send, 0 to 1:

View File

@ -1,14 +1,12 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \
EarlyDisconnectError, CInv, msg_inv, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_nodes, \
p2p_port
from test_framework.util import start_nodes, p2p_port
import os
import time
@ -87,12 +85,13 @@ class MaxBlocksInFlightTest(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="Binary to test max block requests behavior")
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
def setup_network(self):
self.nodes = start_nodes(1, self.options.tmpdir,
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1']],
binary=[self.options.testbinary])

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2019 The Zcash developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -8,7 +8,6 @@ from test_framework.util import (
assert_equal,
get_coinbase_address,
fail,
initialize_chain_clean,
start_nodes,
wait_and_assert_operationid_status,
)
@ -18,10 +17,6 @@ from time import sleep
# Test wallet behaviour with Sapling addresses
class MempoolLimit(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def setup_nodes(self):
extra_args = [
["-debug=mempool", '-mempooltxcostlimit=8000'], # 2 transactions at min cost
@ -30,17 +25,22 @@ class MempoolLimit(BitcoinTestFramework):
# Let node 3 hold one more transaction
["-debug=mempool", '-mempooltxcostlimit=12000'], # 3 transactions at min cost
]
return start_nodes(4, self.options.tmpdir, extra_args)
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
def check_mempool_sizes(self, expected_size, check_node3=True):
for i in range(4 if check_node3 else 3):
for i in range(self.num_nodes if check_node3 else self.num_nodes - 1):
mempool = self.nodes[i].getrawmempool()
if len(mempool) != expected_size:
# print all nodes' mempools before failing
for i in range(4):
for i in range(self.num_nodes):
print("Mempool for node {}: {}".format(i, mempool))
fail("Fail: Mempool for node {}: size={}, expected={}".format(i, len(mempool), expected_size))
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
def run_test(self):
print("Mining blocks...")
self.sync_all()

View File

@ -5,7 +5,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal, assert_true, initialize_chain_clean,
assert_equal, assert_true,
start_node, connect_nodes, wait_and_assert_operationid_status,
get_coinbase_address
)
@ -17,6 +17,11 @@ class MempoolUpgradeActivationTest(BitcoinTestFramework):
alert_filename = None # Set by setup_network
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = True
def setup_network(self):
args = ["-checkmempool", "-debug=mempool", "-blockmaxsize=4000",
"-nuparams=2bb40e60:200", # Blossom
@ -28,10 +33,6 @@ class MempoolUpgradeActivationTest(BitcoinTestFramework):
self.is_network_split = False
self.sync_all
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 2)
def run_test(self):
self.nodes[1].generate(100)
self.sync_all()

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -15,6 +15,10 @@ from test_framework.util import assert_equal, assert_raises, start_node, connect
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = False
alert_filename = None # Set by setup_network

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -15,6 +15,11 @@ from test_framework.util import assert_equal, start_node
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
self.setup_clean_chain = False
def setup_network(self):
# Just need one node for this test
args = ["-checkmempool", "-debug=mempool"]

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -22,6 +22,11 @@ from test_framework.util import assert_equal, assert_greater_than, assert_raises
# Create one-input, one-output, no-fee transaction:
class MempoolSpendCoinbaseTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
self.setup_clean_chain = False
def setup_network(self):
# Just need one node for this test
args = ["-checkmempool", "-debug=mempool"]

View File

@ -21,11 +21,11 @@ TX_EXPIRY_DELTA = 10
class MempoolTxExpiryTest(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir,
return start_nodes(self.num_nodes, self.options.tmpdir,
[[
"-txexpirydelta=%d" % TX_EXPIRY_DELTA,
"-debug=mempool"
]] * 4)
]] * self.num_nodes)
# Test before, at, and after expiry block
# chain is at block height 199 when run_test executes

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -11,14 +11,15 @@ import string
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_raises, \
initialize_chain_clean, start_node, connect_nodes
start_node, connect_nodes
class MerkleBlockTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
def setup_network(self):
self.nodes = []

View File

@ -14,7 +14,6 @@ from test_framework.util import (
assert_raises,
bitcoind_processes,
connect_nodes,
initialize_chain_clean,
start_node,
wait_and_assert_operationid_status,
check_node_log,
@ -22,9 +21,10 @@ from test_framework.util import (
class ShieldCoinbaseTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def start_node_with(self, index, extra_args=[]):
args = [

View File

@ -1,5 +1,5 @@
#!/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.
@ -8,23 +8,21 @@
#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
initialize_chain,
start_nodes,
str_to_b64str,
)
from test_framework.util import str_to_b64str, assert_equal
import os
from http.client import HTTPConnection
from urllib.parse import urlparse
import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir)
def __init__(self):
super().__init__()
self.setup_clean_chain = False
self.num_nodes = 1
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain(self.options.tmpdir)
super().setup_chain()
#Append rpcauth to zcash.conf before initialization
rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
@ -32,12 +30,15 @@ class HTTPBasicsTest (BitcoinTestFramework):
f.write(rpcauth+"\n")
f.write(rpcauth2+"\n")
def setup_network(self):
self.nodes = self.setup_nodes()
def run_test(self):
##################################################
# Check correctness of the rpcauth config option #
##################################################
url = urlparse(self.nodes[0].url)
url = urllib.parse.urlparse(self.nodes[0].url)
#Old authpair
authpair = url.username + ':' + url.password
@ -53,7 +54,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
headers = {"Authorization": "Basic " + str_to_b64str(authpair)}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
@ -63,7 +64,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
#Use new authpair to confirm both work
headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
@ -74,7 +75,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
authpairnew = "rtwrong:"+password
headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
@ -85,7 +86,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
authpairnew = "rt:"+password+"wrong"
headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
@ -96,7 +97,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
authpairnew = "rt2:"+password2
headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
@ -107,7 +108,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
authpairnew = "rt2:"+password2+"wrong"
headers = {"Authorization": "Basic " + str_to_b64str(authpairnew)}
conn = HTTPConnection(url.hostname, url.port)
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -11,9 +11,15 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, connect_nodes_bi, p2p_port
import time
from urllib.parse import urlparse
import urllib.parse
class NodeHandlingTest (BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
def run_test(self):
###########################
# setban/listbanned tests #
@ -45,7 +51,7 @@ class NodeHandlingTest (BitcoinTestFramework):
###########################
# RPC disconnectnode test #
###########################
url = urlparse(self.nodes[1].url)
url = urllib.parse.urlparse(self.nodes[1].url)
self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1)))
time.sleep(2) #disconnecting a node needs a little bit of time
for node in self.nodes[0].getpeerinfo():

View File

@ -1,14 +1,13 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
from test_framework.mininode import CBlockHeader, CInv, NodeConn, NodeConnCB, \
NetworkThread, msg_block, msg_headers, msg_inv, msg_ping, msg_pong, \
mininode_lock
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_node, p2p_port
from test_framework.blocktools import create_block, create_coinbase
@ -118,8 +117,10 @@ class AcceptBlockTest(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to test")
def setup_chain(self):
initialize_chain_clean(self.options.tmpdir, 2)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 2
def setup_network(self):
# Node0 will be used to test behavior of processing unrequested blocks
@ -151,14 +152,14 @@ class AcceptBlockTest(BitcoinTestFramework):
# 1. Have both nodes mine a block (leave IBD)
[ n.generate(1) for n in self.nodes ]
tips = [ int ("0x" + n.getbestblockhash(), 0) for n in self.nodes ]
tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ]
# 2. Send one block that builds on each tip.
# This should be accepted.
blocks_h2 = [] # the height 2 blocks on each node's chain
block_time = time.time() + 1
block_time = int(time.time()) + 1
for i in range(2):
blocks_h2.append(create_block(tips[i], create_coinbase(), block_time))
blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time))
blocks_h2[i].solve()
block_time += 1
test_node.send_message(msg_block(blocks_h2[0]))
@ -172,7 +173,7 @@ class AcceptBlockTest(BitcoinTestFramework):
# 3. Send another block that builds on the original tip.
blocks_h2f = [] # Blocks at height 2 that fork off the main chain
for i in range(2):
blocks_h2f.append(create_block(tips[i], create_coinbase(), blocks_h2[i].nTime+1))
blocks_h2f.append(create_block(tips[i], create_coinbase(2), blocks_h2[i].nTime+1))
blocks_h2f[i].solve()
test_node.send_message(msg_block(blocks_h2f[0]))
white_node.send_message(msg_block(blocks_h2f[1]))
@ -191,7 +192,7 @@ class AcceptBlockTest(BitcoinTestFramework):
# 4. Now send another block that builds on the forking chain.
blocks_h3 = []
for i in range(2):
blocks_h3.append(create_block(blocks_h2f[i].sha256, create_coinbase(), blocks_h2f[i].nTime+1))
blocks_h3.append(create_block(blocks_h2f[i].sha256, create_coinbase(3), blocks_h2f[i].nTime+1))
blocks_h3[i].solve()
test_node.send_message(msg_block(blocks_h3[0]))
white_node.send_message(msg_block(blocks_h3[1]))
@ -222,7 +223,7 @@ class AcceptBlockTest(BitcoinTestFramework):
all_blocks = [] # node0's blocks
for j in range(2):
for i in range(288):
next_block = create_block(tips[j].sha256, create_coinbase(), tips[j].nTime+1)
next_block = create_block(tips[j].sha256, create_coinbase(i + 4), tips[j].nTime+1)
next_block.solve()
if j==0:
test_node.send_message(msg_block(next_block))

283
qa/rpc-tests/p2p-fullblocktest.py Executable file
View File

@ -0,0 +1,283 @@
#!/usr/bin/env python3
# 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.test_framework import ComparisonTestFramework
from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.comptool import TestManager, TestInstance
from test_framework.key import CECKey
from test_framework.mininode import (
CBlockHeader,
COutPoint,
CTransaction,
CTxIn,
CTxOut,
NetworkThread,
)
from test_framework.script import CScript, SignatureHash, SIGHASH_ALL, OP_CHECKSIG, OP_TRUE
from test_framework.util import SAPLING_BRANCH_ID
import random
import time
class PreviousSpendableOutput(object):
def __init__(self, tx = CTransaction(), n = -1):
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.
'''
class FullBlockTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
super().__init__()
self.num_nodes = 1
self.block_heights = {}
self.coinbase_key = CECKey()
self.coinbase_key.set_secretbytes(b"horsebattery")
self.coinbase_pubkey = self.coinbase_key.get_pubkey()
self.block_time = int(time.time())+1
self.tip = None
self.blocks = {}
def run_test(self):
test = TestManager(self, self.options.tmpdir)
test.add_all_connections(self.nodes)
NetworkThread().start() # Start up network handling in another thread
test.run()
def add_transactions_to_block(self, block, tx_list):
[ tx.rehash() for tx in tx_list ]
block.vtx.extend(tx_list)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
return block
# Create a block on top of self.tip, and advance self.tip to point to the new block
# if spend is specified, then 1 satoshi will be spent from that to an anyone-can-spend output,
# and rest will go to fees.
def next_block(self, number, spend=None, additional_coinbase_value=0, script=None):
if self.tip == None:
base_block_hash = self.genesis_hash
else:
base_block_hash = self.tip.sha256
# First create the coinbase
height = self.block_heights[base_block_hash] + 1
coinbase = create_coinbase(height, self.coinbase_pubkey)
coinbase.vout[0].nValue += additional_coinbase_value
if (spend != None):
coinbase.vout[0].nValue += spend.tx.vout[spend.n].nValue - 1 # all but one satoshi to fees
coinbase.rehash()
block = create_block(base_block_hash, coinbase, self.block_time)
if (spend != None):
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(spend.tx.sha256, spend.n), "", 0xffffffff)) # no signature yet
# This copies the java comparison tool testing behavior: the first
# txout has a garbage scriptPubKey, "to make sure we're not
# pre-verifying too much" (?)
tx.vout.append(CTxOut(0, CScript([random.randint(0,255), height & 255])))
if script == None:
tx.vout.append(CTxOut(1, CScript([OP_TRUE])))
else:
tx.vout.append(CTxOut(1, script))
# Now sign it if necessary
scriptSig = ""
scriptPubKey = bytearray(spend.tx.vout[spend.n].scriptPubKey)
if (scriptPubKey[0] == OP_TRUE): # looks like an anyone-can-spend
scriptSig = CScript([OP_TRUE])
else:
# We have to actually sign it
(sighash, err) = SignatureHash(
spend.tx.vout[spend.n].scriptPubKey,
tx,
0,
SIGHASH_ALL,
spend.tx.vout[spend.n].nValue,
SAPLING_BRANCH_ID,
)
scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))])
tx.vin[0].scriptSig = scriptSig
# Now add the transaction to the block
block = self.add_transactions_to_block(block, [tx])
block.solve()
self.tip = block
self.block_heights[block.sha256] = height
self.block_time += 1
assert number not in self.blocks
self.blocks[number] = block
return block
def get_tests(self):
self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
self.block_heights[self.genesis_hash] = 0
spendable_outputs = []
# save the current tip so it can be spent by a later block
def save_spendable_output():
spendable_outputs.append(self.tip)
# get an output that we previous marked as spendable
def get_spendable_output():
return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0)
# returns a test case that asserts that the current tip was accepted
def accepted():
return TestInstance([[self.tip, True]])
# returns a test case that asserts that the current tip was rejected
def rejected():
return TestInstance([[self.tip, False]])
# move the tip back to a previous block
def tip(number):
self.tip = self.blocks[number]
# creates a new block and advances the tip to that block
block = self.next_block
# Create a new block
block(0)
save_spendable_output()
yield accepted()
# Now we need that block to mature so we can spend the coinbase.
test = TestInstance(sync_every_block=False)
for i in range(100):
block(1000 + i)
test.blocks_and_transactions.append([self.tip, True])
save_spendable_output()
yield test
# Start by bulding a couple of blocks on top (which output is spent is in parentheses):
# genesis -> b1 (0) -> b2 (1)
out0 = get_spendable_output()
block(1, spend=out0)
save_spendable_output()
yield accepted()
out1 = get_spendable_output()
block(2, spend=out1)
# Inv again, then deliver twice (shouldn't break anything).
yield accepted()
# so fork like this:
#
# genesis -> b1 (0) -> b2 (1)
# \-> b3 (1)
#
# Nothing should happen at this point. We saw b2 first so it takes priority.
tip(1)
block(3, spend=out1)
# Deliver twice (should still not break anything)
yield rejected()
# Now we add another block to make the alternative chain longer.
#
# genesis -> b1 (0) -> b2 (1)
# \-> b3 (1) -> b4 (2)
out2 = get_spendable_output()
block(4, spend=out2)
yield accepted()
# ... and back to the first chain.
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b3 (1) -> b4 (2)
tip(2)
block(5, spend=out2)
save_spendable_output()
yield rejected()
out3 = get_spendable_output()
block(6, spend=out3)
yield accepted()
# Try to create a fork that double-spends
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b7 (2) -> b8 (4)
# \-> b3 (1) -> b4 (2)
tip(5)
block(7, spend=out2)
yield rejected()
out4 = get_spendable_output()
block(8, spend=out4)
yield rejected()
# Try to create a block that has too much fee
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b9 (4)
# \-> b3 (1) -> b4 (2)
tip(6)
block(9, spend=out4, additional_coinbase_value=1)
yield rejected()
# Create a fork that ends in a block with too much fee (the one that causes the reorg)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b10 (3) -> b11 (4)
# \-> b3 (1) -> b4 (2)
tip(5)
block(10, spend=out3)
yield rejected()
block(11, spend=out4, additional_coinbase_value=1)
yield rejected()
# Try again, but with a valid fork first
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
# \-> b12 (3) -> b13 (4) -> b14 (5)
# (b12 added last)
# \-> b3 (1) -> b4 (2)
tip(5)
b12 = block(12, spend=out3)
save_spendable_output()
#yield TestInstance([[b12, False]])
b13 = block(13, spend=out4)
# Deliver the block header for b12, and the block b13.
# b13 should be accepted but the tip won't advance until b12 is delivered.
yield TestInstance([[CBlockHeader(b12), None], [b13, False]])
save_spendable_output()
out5 = get_spendable_output()
# b14 is invalid, but the node won't know that until it tries to connect
# Tip still can't advance because b12 is missing
block(14, spend=out5, additional_coinbase_value=1)
yield rejected()
yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13.
# Test that a block with a lot of checksigs is okay
lots_of_checksigs = CScript([OP_CHECKSIG] * (1000000 // 50 - 1))
tip(13)
block(15, spend=out5, script=lots_of_checksigs)
yield accepted()
# Test that a block with too many checksigs is rejected
out6 = get_spendable_output()
too_many_checksigs = CScript([OP_CHECKSIG] * (1000000 // 50))
block(16, spend=out6, script=too_many_checksigs)
yield rejected()
if __name__ == '__main__':
FullBlockTest().main()

View File

@ -8,18 +8,19 @@ from test_framework.mininode import NodeConn, NetworkThread, CInv, \
msg_mempool, msg_getdata, msg_tx, mininode_lock, SAPLING_PROTO_VERSION
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, connect_nodes_bi, fail, \
initialize_chain_clean, p2p_port, start_nodes, sync_blocks, sync_mempools
p2p_port, start_nodes, sync_blocks, sync_mempools
from tx_expiry_helper import TestNode, create_transaction
class TxExpiringSoonTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = True
def setup_network(self):
self.nodes = start_nodes(3, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes, 0, 1)
# We don't connect node 2

View File

@ -6,8 +6,7 @@
from test_framework.mininode import NodeConn, NetworkThread, \
msg_tx, SAPLING_PROTO_VERSION
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import initialize_chain_clean, start_nodes, \
p2p_port, assert_equal
from test_framework.util import start_nodes, p2p_port, assert_equal
from tx_expiry_helper import TestNode, create_transaction
import time
@ -15,12 +14,13 @@ import time
class TxExpiryDoSTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
def __init__(self):
super().__init__()
self.num_nodes = 1
self.setup_clean_chain = True
def setup_network(self):
self.nodes = start_nodes(1, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
test_node = TestNode()

View File

@ -5,7 +5,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_node, connect_nodes_bi, wait_and_assert_operationid_status, \
get_coinbase_address
@ -13,9 +13,10 @@ from decimal import Decimal
class PaymentDisclosureTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = True
def setup_network(self, split=False):
args = ['-debug=zrpcunsafe,paymentdisclosure', '-experimentalfeatures', '-paymentdisclosure', '-txindex=1']

View File

@ -12,7 +12,6 @@ from test_framework.util import (
assert_equal,
bitcoind_processes,
connect_nodes_bi,
initialize_chain,
nuparams,
start_node,
start_nodes,
@ -29,12 +28,8 @@ NO_CANOPY = [nuparams(BLOSSOM_BRANCH_ID, 205), nuparams(HEARTWOOD_BRANCH_ID, 21
class PostHeartwoodRollbackTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain(self.options.tmpdir)
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, extra_args=[
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
HAS_CANOPY,
HAS_CANOPY,
NO_CANOPY,

View File

@ -1,5 +1,5 @@
#!/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 https://www.opensource.org/licenses/mit-license.php .
@ -36,6 +36,10 @@ addnode connect to generic DNS name
class ProxyTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
self.have_ipv6 = test_ipv6_local()
# Create two proxies on different ports
# ... one unauthenticated
@ -77,7 +81,7 @@ class ProxyTest(BitcoinTestFramework):
]
if self.have_ipv6:
args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
return start_nodes(4, self.options.tmpdir, extra_args=args)
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
def node_test(self, node, proxies, auth, test_onion=True):
rv = []

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -13,18 +13,22 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import initialize_chain_clean, start_node, \
from test_framework.util import start_node, \
connect_nodes, stop_node, sync_blocks
import os.path
import time
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)
return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.)
class PruneTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 3
self.utxo = []
self.address = ["",""]
@ -46,10 +50,6 @@ class PruneTest(BitcoinTestFramework):
self.txouts = self.txouts + script_pubkey
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def setup_network(self):
self.nodes = []
self.is_network_split = False
@ -78,7 +78,7 @@ class PruneTest(BitcoinTestFramework):
self.nodes[1].generate(200)
sync_blocks(self.nodes[0:2])
self.nodes[0].generate(150)
# Then mine enough full blocks to create more than 550MB of data
# Then mine enough full blocks to create more than 550MiB of data
for i in range(645):
self.mine_full_block(self.nodes[0], self.address[0])
@ -88,7 +88,7 @@ class PruneTest(BitcoinTestFramework):
if not os.path.isfile(self.prunedir+"blk00000.dat"):
raise AssertionError("blk00000.dat is missing, pruning too early")
print("Success")
print("Though we're already using more than 550MB, current usage:", calc_usage(self.prunedir))
print("Though we're already using more than 550MiB, current usage:", calc_usage(self.prunedir))
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):
@ -126,7 +126,7 @@ class PruneTest(BitcoinTestFramework):
# Reorg back with 25 block chain from node 0
self.utxo = self.nodes[0].listunspent()
for i in range(25):
for i in range(25):
self.mine_full_block(self.nodes[0],self.address[0])
# Create connections in the order so both nodes can see the reorg at the same time

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -10,7 +10,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_nodes, connect_nodes_bi, assert_raises
from decimal import Decimal
@ -18,12 +18,13 @@ from decimal import Decimal
# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 3
def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
#connect to a local machine for debugging
#url = "http://bitcoinrpc:DP6DvqZtqXarpeNWyN3LZTFchCCyCUuHwNF7E8pX99x1@%s:%d" % ('127.0.0.1', 18232)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -53,6 +53,11 @@ def check_array_result(object_array, to_match, expected, should_not_find = False
class ReceivedByTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
def run_test(self):
'''
listreceivedbyaddress Test

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -8,15 +8,16 @@
#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_node, stop_node, wait_bitcoinds
class ReindexTest(BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
def setup_network(self):
self.nodes = []

View File

@ -8,7 +8,6 @@ from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
initialize_chain,
start_nodes, get_coinbase_address,
wait_and_assert_operationid_status,
nuparams, BLOSSOM_BRANCH_ID, HEARTWOOD_BRANCH_ID, CANOPY_BRANCH_ID
@ -23,12 +22,8 @@ HAS_CANOPY = ['-nurejectoldversions=false',
]
class RemoveSproutShieldingTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain(self.options.tmpdir)
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, extra_args=[HAS_CANOPY]*4)
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[HAS_CANOPY] * self.num_nodes)
def run_test (self):

View File

@ -11,8 +11,11 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
check_node,
connect_nodes_bi,
start_node,
sync_blocks,
)
import tempfile
from time import sleep
def check_stopped(i, timeout=10):
@ -28,6 +31,17 @@ def check_stopped(i, timeout=10):
class ReorgLimitTest(BitcoinTestFramework):
def setup_nodes(self):
self.log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
nodes = []
nodes.append(start_node(0, self.options.tmpdir, stderr=self.log_stderr))
nodes.append(start_node(1, self.options.tmpdir))
nodes.append(start_node(2, self.options.tmpdir))
nodes.append(start_node(3, self.options.tmpdir))
return nodes
def run_test(self):
assert(self.nodes[0].getblockcount() == 200)
assert(self.nodes[2].getblockcount() == 200)
@ -66,19 +80,28 @@ class ReorgLimitTest(BitcoinTestFramework):
assert(self.nodes[0].getblockcount() == 400)
assert(self.nodes[2].getblockcount() == 401)
print("Sync nodes to force a reorg")
connect_nodes_bi(self.nodes, 0, 2)
self.is_network_split = False
# sync_blocks uses RPC calls to wait for nodes to be synced, so don't
# call it here, because it will have a non-specific connection error
# when Node 0 stops. Instead, we explicitly check for the process itself
# to stop.
try:
print("Sync nodes to force a reorg")
connect_nodes_bi(self.nodes, 0, 2)
self.is_network_split = False
# sync_blocks uses RPC calls to wait for nodes to be synced, so don't
# call it here, because it will have a non-specific connection error
# when Node 0 stops. Instead, we explicitly check for the process itself
# to stop.
print("Check Node 0 is no longer running")
assert(check_stopped(0))
print("Check Node 0 is no longer running")
assert(check_stopped(0))
# Dummy stop to enable the test to tear down
self.nodes[0].stop = lambda: True
# Check that node 0 stopped for the expected reason.
self.log_stderr.seek(0)
stderr = self.log_stderr.read().decode('utf-8')
expected_msg = "A block chain reorganization has been detected that would roll back 100 blocks!"
if expected_msg not in stderr:
raise AssertionError("Expected error \"" + expected_msg + "\" not found in:\n" + stderr)
finally:
self.log_stderr.close()
# Dummy stop to enable the test to tear down
self.nodes[0].stop = lambda: True
if __name__ == '__main__':
ReorgLimitTest().main()

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -9,18 +9,17 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than, \
initialize_chain_clean, start_nodes, connect_nodes_bi
start_nodes, connect_nodes_bi
import struct
import binascii
import json
import io
from io import BytesIO
from codecs import encode
from decimal import Decimal
from http.client import HTTPConnection
from urllib.parse import urlparse
import http.client
import urllib.parse
def deser_uint256(f):
r = 0
@ -31,7 +30,7 @@ def deser_uint256(f):
# allows simple http get calls
def http_get_call(host, port, path, response_object = 0):
conn = HTTPConnection(host, port)
conn = http.client.HTTPConnection(host, port)
conn.request('GET', path)
if response_object:
@ -41,7 +40,7 @@ def http_get_call(host, port, path, response_object = 0):
# allows simple http post calls with a request body
def http_post_call(host, port, path, requestdata = '', response_object = 0):
conn = HTTPConnection(host, port)
conn = http.client.HTTPConnection(host, port)
conn.request('POST', path, requestdata)
if response_object:
@ -52,12 +51,13 @@ def http_post_call(host, port, path, requestdata = '', response_object = 0):
class RESTTest (BitcoinTestFramework):
FORMAT_SEPARATOR = "."
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 3
def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
@ -65,7 +65,7 @@ class RESTTest (BitcoinTestFramework):
self.sync_all()
def run_test(self):
url = urlparse(self.nodes[0].url)
url = urllib.parse.urlparse(self.nodes[0].url)
print("Mining blocks...")
self.nodes[0].generate(1)
@ -145,7 +145,7 @@ class RESTTest (BitcoinTestFramework):
binaryRequest += struct.pack("i", 0);
bin_response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', binaryRequest)
output = io.BytesIO()
output = BytesIO()
output.write(bin_response)
output.seek(0)
chainHeight = struct.unpack("i", output.read(4))[0]

View File

@ -4,9 +4,9 @@
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_nodes, start_node, connect_nodes_bi, bitcoind_processes, \
nuparams, OVERWINTER_BRANCH_ID, SAPLING_BRANCH_ID
nuparams, sync_blocks, OVERWINTER_BRANCH_ID, SAPLING_BRANCH_ID
import time
@ -15,15 +15,16 @@ FAKE_OVERWINTER = [nuparams(OVERWINTER_BRANCH_ID, 10), nuparams(SAPLING_BRANCH_I
class RewindBlockIndexTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = True
def setup_network(self, split=False):
# Node 0 - Overwinter, then Sprout, then Overwinter again
# Node 1 - Sprout
# Node 2 - Overwinter
self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
FAKE_OVERWINTER,
FAKE_SPROUT,
FAKE_OVERWINTER,
@ -47,7 +48,7 @@ class RewindBlockIndexTest (BitcoinTestFramework):
print("Mining diverging blocks")
block10s = self.nodes[1].generate(1)[0]
block10o = self.nodes[2].generate(1)[0]
self.sync_all()
sync_blocks(self.nodes, allow_different_tips=True)
assert_equal(self.nodes[0].getbestblockhash(), block10o)
assert_equal(self.nodes[1].getbestblockhash(), block10s)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -7,153 +7,118 @@
# Dependency: python-bitcoinrpc
from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
bitcoind_processes,
check_json_precision,
get_rpc_proxy,
initialize_chain,
rpc_port,
rpc_url,
start_nodes,
stop_nodes,
wait_bitcoinds,
)
from test_framework.netutil import addr_to_hex, get_bind_addrs, all_interfaces
import os
import sys
import shutil
import tempfile
import traceback
def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected):
'''
Start a node with requested rpcallowip and rpcbind parameters,
then try to connect, and check if the set of bound addresses
matches the expected set.
'''
expected = [(addr_to_hex(addr), port) for (addr, port) in expected]
base_args = ['-disablewallet', '-nolisten']
if allow_ips:
base_args += ['-rpcallowip=' + x for x in allow_ips]
binds = ['-rpcbind='+addr for addr in addresses]
nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to)
try:
pid = bitcoind_processes[0].pid
assert_equal(set(get_bind_addrs(pid)), set(expected))
finally:
stop_nodes(nodes)
wait_bitcoinds()
def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
'''
Start a node with rpcwallow IP, and request getinfo
at a non-localhost IP.
'''
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
nodes = start_nodes(1, tmpdir, [base_args])
try:
# connect to node through non-loopback interface
url = "http://rt:rt@%s:%d" % (rpchost, rpcport,)
node = get_rpc_proxy(url, 1)
node.getinfo()
finally:
node = None # make sure connection will be garbage collected and closed
stop_nodes(nodes)
wait_bitcoinds()
def run_test(tmpdir):
assert(sys.platform.startswith('linux')) # due to OS-specific network stats queries, this test works only on Linux
# find the first non-loopback interface for testing
non_loopback_ip = None
for name,ip in all_interfaces():
if ip != '127.0.0.1':
non_loopback_ip = ip
break
if non_loopback_ip is None:
assert(not 'This test requires at least one non-loopback IPv4 interface')
print("Using interface %s for testing" % non_loopback_ip)
class RPCBindTest(BitcoinTestFramework):
defaultport = rpc_port(0)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
# check default without rpcallowip (IPv4 and IPv6 localhost)
run_bind_test(tmpdir, None, '127.0.0.1', [],
[('127.0.0.1', defaultport), ('::1', defaultport)])
# check default with rpcallowip (IPv6 any)
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', [],
[('::0', defaultport)])
# check only IPv4 localhost (explicit)
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],
[('127.0.0.1', defaultport)])
# check only IPv4 localhost (explicit) with alternative port
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],
[('127.0.0.1', 32171)])
# check only IPv4 localhost (explicit) with multiple alternative ports on same host
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'],
[('127.0.0.1', 32171), ('127.0.0.1', 32172)])
# check only IPv6 localhost (explicit)
run_bind_test(tmpdir, ['[::1]'], '[::1]', ['[::1]'],
[('::1', defaultport)])
# check both IPv4 and IPv6 localhost (explicit)
run_bind_test(tmpdir, ['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],
[('127.0.0.1', defaultport), ('::1', defaultport)])
# check only non-loopback interface
run_bind_test(tmpdir, [non_loopback_ip], non_loopback_ip, [non_loopback_ip],
[(non_loopback_ip, defaultport)])
# Check that with invalid rpcallowip, we are denied
run_allowip_test(tmpdir, [non_loopback_ip], non_loopback_ip, defaultport)
try:
run_allowip_test(tmpdir, ['1.1.1.1'], non_loopback_ip, defaultport)
assert(not 'Connection not denied by rpcallowip as expected')
except ValueError:
def setup_network(self):
pass
def main():
import optparse
def setup_nodes(self):
pass
parser = optparse.OptionParser(usage="%prog [options]")
parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
help="Leave bitcoinds and test.* datadir on exit or error")
parser.add_option("--srcdir", dest="srcdir", default="../../src",
help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
help="Root directory for datadirs")
(options, args) = parser.parse_args()
def run_bind_test(self, allow_ips, connect_to, addresses, expected):
'''
Start a node with requested rpcallowip and rpcbind parameters,
then try to connect, and check if the set of bound addresses
matches the expected set.
'''
expected = [(addr_to_hex(addr), port) for (addr, port) in expected]
base_args = ['-disablewallet', '-nolisten']
if allow_ips:
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)
wait_bitcoinds()
os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']
def run_allowip_test(self, allow_ips, rpchost, rpcport):
'''
Start a node with rpcwallow IP, and request getinfo
at a non-localhost IP.
'''
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.getinfo()
finally:
node = None # make sure connection will be garbage collected and closed
stop_nodes(self.nodes)
wait_bitcoinds()
check_json_precision()
def run_test(self):
# due to OS-specific network stats queries, this test works only on Linux
assert(sys.platform.startswith('linux'))
# find the first non-loopback interface for testing
non_loopback_ip = None
for name,ip in all_interfaces():
if ip != '127.0.0.1':
non_loopback_ip = ip
break
if non_loopback_ip is None:
assert(not 'This test requires at least one non-loopback IPv4 interface')
print("Using interface %s for testing" % non_loopback_ip)
success = False
try:
print("Initializing test directory "+options.tmpdir)
if not os.path.isdir(options.tmpdir):
os.makedirs(options.tmpdir)
initialize_chain(options.tmpdir)
defaultport = rpc_port(0)
run_test(options.tmpdir)
# check default without rpcallowip (IPv4 and IPv6 localhost)
self.run_bind_test(None, '127.0.0.1', [],
[('127.0.0.1', defaultport), ('::1', defaultport)])
# check default with rpcallowip (IPv6 any)
self.run_bind_test(['127.0.0.1'], '127.0.0.1', [],
[('::0', defaultport)])
# check only IPv4 localhost (explicit)
self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],
[('127.0.0.1', defaultport)])
# check only IPv4 localhost (explicit) with alternative port
self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],
[('127.0.0.1', 32171)])
# check only IPv4 localhost (explicit) with multiple alternative ports on same host
self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'],
[('127.0.0.1', 32171), ('127.0.0.1', 32172)])
# check only IPv6 localhost (explicit)
self.run_bind_test(['[::1]'], '[::1]', ['[::1]'],
[('::1', defaultport)])
# check both IPv4 and IPv6 localhost (explicit)
self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],
[('127.0.0.1', defaultport), ('::1', defaultport)])
# check only non-loopback interface
self.run_bind_test([non_loopback_ip], non_loopback_ip, [non_loopback_ip],
[(non_loopback_ip, defaultport)])
success = True
except AssertionError as e:
print("Assertion failed: "+e.message)
except Exception as e:
print("Unexpected exception caught during testing: "+str(e))
traceback.print_tb(sys.exc_info()[2])
if not options.nocleanup:
print("Cleaning up")
wait_bitcoinds()
shutil.rmtree(options.tmpdir)
if success:
print("Tests successful")
sys.exit(0)
else:
print("Failed")
sys.exit(1)
# Check that with invalid rpcallowip, we are denied
self.run_allowip_test([non_loopback_ip], non_loopback_ip, defaultport)
try:
self.run_allowip_test(['1.1.1.1'], non_loopback_ip, defaultport)
assert(not 'Connection not denied by rpcallowip as expected')
except JSONRPCException:
pass
if __name__ == '__main__':
main()
RPCBindTest().main()

View File

@ -28,25 +28,29 @@ length computation (40b5d5e3ea4b602c34c4efaba0b9f6171dddfef5) corrects the issue
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (assert_equal, assert_true,
initialize_chain_clean, start_nodes, start_node, connect_nodes_bi,
assert_start_raises_init_error,
start_nodes, start_node, connect_nodes_bi,
bitcoind_processes,
nuparams, OVERWINTER_BRANCH_ID, SAPLING_BRANCH_ID)
import re
import logging
import sys
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout)
HAS_SAPLING = [nuparams(OVERWINTER_BRANCH_ID, 10), nuparams(SAPLING_BRANCH_ID, 15)]
NO_SAPLING = [nuparams(OVERWINTER_BRANCH_ID, 10), nuparams(SAPLING_BRANCH_ID, 150)]
class SaplingRewindTest(BitcoinTestFramework):
def setup_chain(self):
logging.info("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = True
# This mirrors how the network was setup in the bash test
def setup_network(self, split=False):
logging.info("Initializing the network in "+self.options.tmpdir)
self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
HAS_SAPLING, # The first two nodes have a correct view of the network,
HAS_SAPLING, # the third will rewind after upgrading.
NO_SAPLING
@ -91,35 +95,15 @@ class SaplingRewindTest(BitcoinTestFramework):
# Restart the nodes, reconnect, and sync the network. This succeeds if "-reindex" is passed.
logging.info("Reconnecting the network...")
try:
# expect an exception; the node will refuse to fully start because its last point of
# agreement with the rest of the network was prior to the network upgrade activation
self.nodes[2] = start_node(2, self.options.tmpdir, extra_args=HAS_SAPLING) # + ["-reindex"])
except:
logpath = self.options.tmpdir + "/node2/regtest/debug.log"
found = False
with open(logpath, 'r', encoding='utf8') as f:
for line in f:
# Search for the rollback message in the debug log, and ensure that it has the
# correct expected rollback length.
m = re.search(r'roll back ([0-9]+)', line)
if m is None:
continue
elif m.group(1) == "120":
found = True
break
else:
raise AssertionError("Incorrect rollback length %s found, expected 120." %(m.group(1)))
if not found:
raise AssertionError("Expected rollback message not found in log file.")
# expect an exception; the node will refuse to fully start because its last point of
# agreement with the rest of the network was prior to the network upgrade activation
assert_start_raises_init_error(2, self.options.tmpdir, HAS_SAPLING, "roll back 120")
# restart the node with -reindex to allow the test to complete gracefully,
# otherwise the node shutdown call in test cleanup will throw an error since
# it can't connect
self.nodes[2] = start_node(2, self.options.tmpdir, extra_args=NO_SAPLING + ["-reindex"])
else:
raise AssertionError("Expected node to halt due to excessive rewind length.")
# restart the node with -reindex to allow the test to complete gracefully,
# otherwise the node shutdown call in test cleanup will throw an error since
# it can't connect
self.nodes[2] = start_node(2, self.options.tmpdir, extra_args=NO_SAPLING + ["-reindex"])
if __name__ == '__main__':
SaplingRewindTest().main()

View File

@ -1,250 +0,0 @@
#!/usr/bin/env python3
#
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
'''
Test notes:
This test uses the script_valid and script_invalid tests from the unittest
framework to do end-to-end testing where we compare that two nodes agree on
whether blocks containing a given test script are valid.
We generally ignore the script flags associated with each test (since we lack
the precision to test each script using those flags in this framework), but
for tests with SCRIPT_VERIFY_P2SH, we can use a block time after the BIP16
switchover date to try to test with that flag enabled (and for tests without
that flag, we use a block time before the switchover date).
NOTE: This test is very slow and may take more than 40 minutes to run.
'''
from test_framework.test_framework import ComparisonTestFramework
from test_framework.comptool import TestInstance, TestManager
from test_framework.mininode import NetworkThread
from test_framework.blocktools import create_block, create_coinbase, create_transaction
from test_framework.script import CScript, CScriptOp, CScriptNum, OPCODES_BY_NAME
import os
import json
script_valid_file = "../../src/test/data/script_valid.json"
script_invalid_file = "../../src/test/data/script_invalid.json"
# Pass in a set of json files to open.
class ScriptTestFile(object):
def __init__(self, files):
self.files = files
self.index = -1
self.data = []
def load_files(self):
for f in self.files:
self.data.extend(json.loads(open(os.path.dirname(os.path.abspath(__file__))+"/"+f).read()))
# Skip over records that are not long enough to be tests
def get_records(self):
while (self.index < len(self.data)):
if len(self.data[self.index]) >= 3:
yield self.data[self.index]
self.index += 1
# Helper for parsing the flags specified in the .json files
SCRIPT_VERIFY_NONE = 0
SCRIPT_VERIFY_P2SH = 1
SCRIPT_VERIFY_STRICTENC = 1 << 1
SCRIPT_VERIFY_LOW_S = 1 << 3
SCRIPT_VERIFY_NULLDUMMY = 1 << 4
SCRIPT_VERIFY_SIGPUSHONLY = 1 << 5
SCRIPT_VERIFY_MINIMALDATA = 1 << 6
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = 1 << 7
SCRIPT_VERIFY_CLEANSTACK = 1 << 8
flag_map = {
"": SCRIPT_VERIFY_NONE,
"NONE": SCRIPT_VERIFY_NONE,
"P2SH": SCRIPT_VERIFY_P2SH,
"STRICTENC": SCRIPT_VERIFY_STRICTENC,
"LOW_S": SCRIPT_VERIFY_LOW_S,
"NULLDUMMY": SCRIPT_VERIFY_NULLDUMMY,
"SIGPUSHONLY": SCRIPT_VERIFY_SIGPUSHONLY,
"MINIMALDATA": SCRIPT_VERIFY_MINIMALDATA,
"DISCOURAGE_UPGRADABLE_NOPS": SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
"CLEANSTACK": SCRIPT_VERIFY_CLEANSTACK,
}
def ParseScriptFlags(flag_string):
flags = 0
for x in flag_string.split(","):
if x in flag_map:
flags |= flag_map[x]
else:
print("Error: unrecognized script flag: ", x)
return flags
'''
Given a string that is a scriptsig or scriptpubkey from the .json files above,
convert it to a CScript()
'''
# Replicates behavior from core_read.cpp
def ParseScript(json_script):
script = json_script.split(" ")
parsed_script = CScript()
for x in script:
if len(x) == 0:
# Empty string, ignore.
pass
elif x.isdigit() or (len(x) >= 1 and x[0] == "-" and x[1:].isdigit()):
# Number
n = int(x, 0)
if (n == -1) or (n >= 1 and n <= 16):
parsed_script = CScript(bytes(parsed_script) + bytes(CScript([n])))
else:
parsed_script += CScriptNum(int(x, 0))
elif x.startswith("0x"):
# Raw hex data, inserted NOT pushed onto stack:
for i in range(2, len(x), 2):
parsed_script = CScript(bytes(parsed_script) + bytes(chr(int(x[i:i+2],16))))
elif x.startswith("'") and x.endswith("'") and len(x) >= 2:
# Single-quoted string, pushed as data.
parsed_script += CScript([x[1:-1]])
else:
# opcode, e.g. OP_ADD or ADD:
tryopname = "OP_" + x
if tryopname in OPCODES_BY_NAME:
parsed_script += CScriptOp(OPCODES_BY_NAME["OP_" + x])
else:
print("ParseScript: error parsing '%s'" % x)
return ""
return parsed_script
class TestBuilder(object):
def create_credit_tx(self, scriptPubKey):
# self.tx1 is a coinbase transaction, modeled after the one created by script_tests.cpp
# This allows us to reuse signatures created in the unit test framework.
self.tx1 = create_coinbase() # this has a bip34 scriptsig,
self.tx1.vin[0].scriptSig = CScript([0, 0]) # but this matches the unit tests
self.tx1.vout[0].nValue = 0
self.tx1.vout[0].scriptPubKey = scriptPubKey
self.tx1.rehash()
def create_spend_tx(self, scriptSig):
self.tx2 = create_transaction(self.tx1, 0, CScript(), 0)
self.tx2.vin[0].scriptSig = scriptSig
self.tx2.vout[0].scriptPubKey = CScript()
self.tx2.rehash()
def rehash(self):
self.tx1.rehash()
self.tx2.rehash()
# This test uses the (default) two nodes provided by ComparisonTestFramework,
# specified on the command line with --testbinary and --refbinary.
# See comptool.py
class ScriptTest(ComparisonTestFramework):
def run_test(self):
# Set up the comparison tool TestManager
test = TestManager(self, self.options.tmpdir)
test.add_all_connections(self.nodes)
# Load scripts
self.scripts = ScriptTestFile([script_valid_file, script_invalid_file])
self.scripts.load_files()
# Some variables we re-use between test instances (to build blocks)
self.tip = None
self.block_time = None
NetworkThread().start() # Start up network handling in another thread
test.run()
def generate_test_instance(self, pubkeystring, scriptsigstring):
scriptpubkey = ParseScript(pubkeystring)
scriptsig = ParseScript(scriptsigstring)
test = TestInstance(sync_every_block=False)
test_build = TestBuilder()
test_build.create_credit_tx(scriptpubkey)
test_build.create_spend_tx(scriptsig)
test_build.rehash()
block = create_block(self.tip, test_build.tx1, self.block_time)
self.block_time += 1
block.solve()
self.tip = block.sha256
test.blocks_and_transactions = [[block, True]]
for i in range(100):
block = create_block(self.tip, create_coinbase(), self.block_time)
self.block_time += 1
block.solve()
self.tip = block.sha256
test.blocks_and_transactions.append([block, True])
block = create_block(self.tip, create_coinbase(), self.block_time)
self.block_time += 1
block.vtx.append(test_build.tx2)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
block.solve()
test.blocks_and_transactions.append([block, None])
return test
# This generates the tests for TestManager.
def get_tests(self):
self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
self.block_time = 1333230000 # before the BIP16 switchover
'''
Create a new block with an anyone-can-spend coinbase
'''
block = create_block(self.tip, create_coinbase(), self.block_time)
self.block_time += 1
block.solve()
self.tip = block.sha256
yield TestInstance(objects=[[block, True]])
'''
Build out to 100 blocks total, maturing the coinbase.
'''
test = TestInstance(objects=[], sync_every_block=False, sync_every_tx=False)
for i in range(100):
b = create_block(self.tip, create_coinbase(), self.block_time)
b.solve()
test.blocks_and_transactions.append([b, True])
self.tip = b.sha256
self.block_time += 1
yield test
''' Iterate through script tests. '''
counter = 0
for script_test in self.scripts.get_records():
''' Reset the blockchain to genesis block + 100 blocks. '''
if self.nodes[0].getblockcount() > 101:
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(102))
self.nodes[1].invalidateblock(self.nodes[1].getblockhash(102))
self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
[scriptsig, scriptpubkey, flags] = script_test[0:3]
flags = ParseScriptFlags(flags)
# We can use block time to determine whether the nodes should be
# enforcing BIP16.
#
# We intentionally let the block time grow by 1 each time.
# This forces the block hashes to differ between tests, so that
# a call to invalidateblock doesn't interfere with a later test.
if (flags & SCRIPT_VERIFY_P2SH):
self.block_time = 1333238400 + counter # Advance to enforcing BIP16
else:
self.block_time = 1333230000 + counter # Before the BIP16 switchover
print("Script test: [%s]" % script_test)
yield self.generate_test_instance(scriptpubkey, scriptsig)
counter += 1
if __name__ == '__main__':
ScriptTest().main()

View File

@ -8,21 +8,21 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
get_coinbase_address,
initialize_chain_clean,
start_nodes,
wait_and_assert_operationid_status,
)
class ShorterBlockTimes(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir, [[
'-nuparams=2bb40e60:106', # Blossom
]] * 4)
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def setup_nodes(self):
return start_nodes(self.num_nodes, self.options.tmpdir, [[
'-nuparams=2bb40e60:106', # Blossom
]] * self.num_nodes)
def run_test(self):
print("Mining blocks...")

View File

@ -1,22 +1,22 @@
#!/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 https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, initialize_chain_clean, \
start_nodes
from test_framework.util import assert_equal, start_nodes
class SignRawTransactionsTest(BitcoinTestFramework):
"""Tests transaction signing via RPC command "signrawtransaction"."""
def setup_chain(self):
print('Initializing test directory ' + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 1
def setup_network(self, split=False):
self.nodes = start_nodes(1, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def successful_signing_test(self):

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2015 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -112,7 +112,7 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
print([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]])
delta = 1.0e-6 # account for rounding error
last_e = max(fees_seen)
for e in filter(lambda x: x >= 0, all_estimates):
for e in [x for x in all_estimates if x >= 0]:
# Estimates should be within the bounds of what transactions fees actually were:
if float(e)+delta < min(fees_seen) or float(e)-delta > max(fees_seen):
raise AssertionError("Estimated fee (%f) out of range (%f,%f)"
@ -142,6 +142,11 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
class EstimateFeeTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = False
def setup_network(self):
'''
We'll setup the network to have 3 nodes that all mine with different parameters.
@ -215,7 +220,7 @@ class EstimateFeeTest(BitcoinTestFramework):
from_index = random.randint(1,2)
(txhex, fee) = small_txpuzzle_randfee(self.nodes[from_index], self.confutxo,
self.memutxo, Decimal("0.005"), min_fee, min_fee)
tx_kbytes = (len(txhex)/2)/1000.0
tx_kbytes = (len(txhex) // 2) / 1000.0
self.fees_per_kb.append(float(fee)/tx_kbytes)
sync_mempools(self.nodes[0:3],.1)
mined = mining_node.getblock(mining_node.generate(1)[0],True)["tx"]

View File

@ -6,7 +6,7 @@
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_true, get_coinbase_address, \
initialize_chain_clean, start_nodes, wait_and_assert_operationid_status, \
start_nodes, wait_and_assert_operationid_status, \
wait_and_assert_operationid_status_result
SAPLING_ADDR = 'zregtestsapling1ssqj3f3majnl270985gqcdqedd9t4nlttjqskccwevj2v20sc25deqspv3masufnwcdy67cydyy'
@ -49,9 +49,14 @@ def check_migration_status(node, destination_address, migration_state):
class SproutSaplingMigration(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def setup_nodes(self):
extra_args = [[
]] * 4
]] * self.num_nodes
# Add migration parameters to nodes[0]
extra_args[0] = extra_args[0] + [
'-migration',
@ -60,11 +65,7 @@ class SproutSaplingMigration(BitcoinTestFramework):
]
assert_equal(3, len(extra_args[0]))
assert_equal(0, len(extra_args[1]))
return start_nodes(4, self.options.tmpdir, extra_args)
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
def run_migration_test(self, node, sproutAddr, saplingAddr, target_height):
# Make sure we are in a good state to run the test

View File

@ -1,4 +1,4 @@
#
#!/usr/bin/env python3
#
# bignum.py
#

View File

@ -1,3 +1,4 @@
#!/usr/bin/env python3
# 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
@ -6,13 +7,14 @@
from .mininode import CBlock, CBlockHeader, CBlockLocator, CTransaction, msg_block, msg_headers, msg_tx
import sys
import io
import dbm.dumb as dbm
from io import BytesIO
import dbm.ndbm
class BlockStore():
def __init__(self, datadir):
self.blockDB = dbm.open(datadir + "/blocks", 'c')
self.blockDB = dbm.ndbm.open(datadir + "/blocks", 'c')
self.currentBlock = 0
self.headers_map = dict()
def close(self):
self.blockDB.close()
@ -23,30 +25,36 @@ class BlockStore():
serialized_block = self.blockDB[repr(blockhash)]
except KeyError:
return None
f = io.BytesIO(serialized_block)
f = BytesIO(serialized_block)
ret = CBlock()
ret.deserialize(f)
ret.calc_sha256()
return ret
def get_header(self, blockhash):
try:
return self.headers_map[blockhash]
except KeyError:
return None
# Note: this pulls full blocks out of the database just to retrieve
# the headers -- perhaps we could keep a separate data structure
# to avoid this overhead.
def headers_for(self, locator, hash_stop, current_tip=None):
if current_tip is None:
current_tip = self.currentBlock
current_block = self.get(current_tip)
if current_block is None:
current_block_header = self.get_header(current_tip)
if current_block_header is None:
return None
response = msg_headers()
headersList = [ CBlockHeader(current_block) ]
headersList = [ current_block_header ]
maxheaders = 2000
while (headersList[0].sha256 not in locator.vHave):
prevBlockHash = headersList[0].hashPrevBlock
prevBlock = self.get(prevBlockHash)
if prevBlock is not None:
headersList.insert(0, CBlockHeader(prevBlock))
prevBlockHeader = self.get_header(prevBlockHash)
if prevBlockHeader is not None:
headersList.insert(0, prevBlockHeader)
else:
break
headersList = headersList[:maxheaders] # truncate if we have too many
@ -64,6 +72,10 @@ class BlockStore():
except TypeError as e:
print("Unexpected error: ", sys.exc_info()[0], e.args)
self.currentBlock = block.sha256
self.headers_map[block.sha256] = CBlockHeader(block)
def add_header(self, header):
self.headers_map[header.sha256] = header
def get_blocks(self, inv):
responses = []
@ -96,7 +108,7 @@ class BlockStore():
class TxStore(object):
def __init__(self, datadir):
self.txDB = dbm.open(datadir + "/transactions", 'c')
self.txDB = dbm.ndbm.open(datadir + "/transactions", 'c')
def close(self):
self.txDB.close()
@ -107,7 +119,7 @@ class TxStore(object):
serialized_tx = self.txDB[repr(txhash)]
except KeyError:
return None
f = io.BytesIO(serialized_tx)
f = BytesIO(serialized_tx)
ret = CTransaction()
ret.deserialize(f)
ret.calc_sha256()

View File

@ -1,11 +1,11 @@
#!/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 https://www.opensource.org/licenses/mit-license.php .
#
from .mininode import CBlock, CTransaction, CTxIn, CTxOut, COutPoint
from .script import CScript, OP_0, OP_EQUAL, OP_HASH160
from .script import CScript, OP_0, OP_EQUAL, OP_HASH160, OP_TRUE, OP_CHECKSIG
# Create a block (with regtest difficulty)
def create_block(hashprev, coinbase, nTime=None, nBits=None, hashFinalSaplingRoot=None):
@ -44,19 +44,21 @@ def serialize_script_num(value):
r[-1] |= 0x80
return r
counter=1
# Create an anyone-can-spend coinbase transaction, assuming no miner fees
def create_coinbase(heightAdjust = 0):
global counter
# Create a coinbase transaction, assuming no miner fees.
# If pubkey is passed in, the coinbase output will be a P2PK output;
# otherwise an anyone-can-spend output.
def create_coinbase(height, pubkey = None):
coinbase = CTransaction()
coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff),
CScript([counter+heightAdjust, OP_0]), 0xffffffff))
counter += 1
CScript([height, OP_0]), 0xffffffff))
coinbaseoutput = CTxOut()
coinbaseoutput.nValue = int(12.5*100000000)
halvings = int((counter+heightAdjust)/150) # regtest
halvings = int(height/150) # regtest
coinbaseoutput.nValue >>= halvings
coinbaseoutput.scriptPubKey = b""
if (pubkey != None):
coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG])
else:
coinbaseoutput.scriptPubKey = CScript([OP_TRUE])
coinbase.vout = [ coinbaseoutput ]
if halvings == 0: # regtest
froutput = CTxOut()

View File

@ -1,12 +1,24 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
from .mininode import CBlock, CTransaction, CInv, NodeConn, NodeConnCB, \
msg_inv, msg_getheaders, msg_ping, msg_mempool, mininode_lock, MAX_INV_SZ
from .blockstore import BlockStore, TxStore
from .mininode import (
CBlock,
CBlockHeader,
CTransaction,
CInv,
msg_block,
msg_getheaders,
msg_inv,
msg_mempool,
msg_ping,
mininode_lock,
MAX_INV_SZ,
NodeConn,
NodeConnCB,
)
from .util import p2p_port
import time
@ -123,12 +135,19 @@ class TestNode(NodeConnCB):
# Instances of these are generated by the test generator, and fed into the
# comptool.
#
# "blocks_and_transactions" should be an array of [obj, True/False/None]:
# - obj is either a CBlock or a CTransaction, and
# "blocks_and_transactions" should be an array of
# [obj, True/False/None, hash/None]:
# - obj is either a CBlock, CBlockHeader, or a CTransaction, and
# - the second value indicates whether the object should be accepted
# into the blockchain or mempool (for tests where we expect a certain
# answer), or "None" if we don't expect a certain answer and are just
# comparing the behavior of the nodes being tested.
# - the third value is the hash to test the tip against (if None or omitted,
# use the hash of the block)
# - NOTE: if a block header, no test is performed; instead the header is
# just added to the block_store. This is to facilitate block delivery
# when communicating with headers-first clients (when withholding an
# intermediate block).
# sync_every_block: if True, then each block will be inv'ed, synced, and
# nodes will be tested based on the outcome for the block. If False,
# then inv's accumulate until all blocks are processed (or max inv size
@ -195,7 +214,6 @@ class TestManager(object):
if not wait_until(blocks_requested, attempts=20*num_blocks):
# print [ c.cb.block_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested block")
# --> Answer request (we did this inline!)
# Send getheaders message
[ c.cb.send_getheaders() for c in self.connections ]
@ -218,7 +236,6 @@ class TestManager(object):
if not wait_until(transaction_requested, attempts=20*num_events):
# print [ c.cb.tx_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested transaction")
# --> Answer request (we did this inline!)
# Get the mempool
[ c.cb.send_mempool() for c in self.connections ]
@ -272,29 +289,55 @@ class TestManager(object):
# We use these variables to keep track of the last block
# and last transaction in the tests, which are used
# if we're not syncing on every block or every tx.
[ block, block_outcome ] = [ None, None ]
[ block, block_outcome, tip ] = [ None, None, None ]
[ tx, tx_outcome ] = [ None, None ]
invqueue = []
for b_or_t, outcome in test_instance.blocks_and_transactions:
for test_obj in test_instance.blocks_and_transactions:
b_or_t = test_obj[0]
outcome = test_obj[1]
# Determine if we're dealing with a block or tx
if isinstance(b_or_t, CBlock): # Block test runner
block = b_or_t
block_outcome = outcome
tip = block.sha256
# each test_obj can have an optional third argument
# to specify the tip we should compare with
# (default is to use the block being tested)
if len(test_obj) >= 3:
tip = test_obj[2]
# Add to shared block_store, set as current block
# If there was an open getdata request for the block
# previously, and we didn't have an entry in the
# block_store, then immediately deliver, because the
# node wouldn't send another getdata request while
# the earlier one is outstanding.
first_block_with_hash = True
if self.block_store.get(block.sha256) is not None:
first_block_with_hash = False
with mininode_lock:
self.block_store.add_block(block)
for c in self.connections:
c.cb.block_request_map[block.sha256] = False
if first_block_with_hash and block.sha256 in c.cb.block_request_map and c.cb.block_request_map[block.sha256] == True:
# There was a previous request for this block hash
# Most likely, we delivered a header for this block
# but never had the block to respond to the getdata
c.send_message(msg_block(block))
else:
c.cb.block_request_map[block.sha256] = False
# Either send inv's to each node and sync, or add
# to invqueue for later inv'ing.
if (test_instance.sync_every_block):
[ c.cb.send_inv(block) for c in self.connections ]
self.sync_blocks(block.sha256, 1)
if (not self.check_results(block.sha256, outcome)):
if (not self.check_results(tip, outcome)):
raise AssertionError("Test failed at test %d" % test_number)
else:
invqueue.append(CInv(2, block.sha256))
elif isinstance(b_or_t, CBlockHeader):
block_header = b_or_t
self.block_store.add_header(block_header)
else: # Tx test runner
assert(isinstance(b_or_t, CTransaction))
tx = b_or_t
@ -322,9 +365,8 @@ class TestManager(object):
if len(invqueue) > 0:
[ c.send_message(msg_inv(invqueue)) for c in self.connections ]
invqueue = []
self.sync_blocks(block.sha256,
len(test_instance.blocks_and_transactions))
if (not self.check_results(block.sha256, block_outcome)):
self.sync_blocks(block.sha256, len(test_instance.blocks_and_transactions))
if (not self.check_results(tip, block_outcome)):
raise AssertionError("Block test failed at test %d" % test_number)
if (not test_instance.sync_every_tx and tx is not None):
if len(invqueue) > 0:

View File

@ -1,3 +1,8 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
"""
This module contains utilities for doing coverage analysis on the RPC
interface.

View File

@ -0,0 +1,215 @@
# Copyright (c) 2011 Sam Rushing
#
# key.py - OpenSSL wrapper
#
# This file is modified from python-bitcoinlib.
#
"""ECC secp256k1 crypto routines
WARNING: This module does not mlock() secrets; your private keys may end up on
disk in swap! Use with caution!
"""
import ctypes
import ctypes.util
import hashlib
import sys
ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library ('ssl') or 'libeay32')
ssl.BN_new.restype = ctypes.c_void_p
ssl.BN_new.argtypes = []
ssl.BN_bin2bn.restype = ctypes.c_void_p
ssl.BN_bin2bn.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p]
ssl.BN_CTX_free.restype = None
ssl.BN_CTX_free.argtypes = [ctypes.c_void_p]
ssl.BN_CTX_new.restype = ctypes.c_void_p
ssl.BN_CTX_new.argtypes = []
ssl.ECDH_compute_key.restype = ctypes.c_int
ssl.ECDH_compute_key.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]
ssl.ECDSA_sign.restype = ctypes.c_int
ssl.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
ssl.ECDSA_verify.restype = ctypes.c_int
ssl.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
ssl.EC_KEY_free.restype = None
ssl.EC_KEY_free.argtypes = [ctypes.c_void_p]
ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
ssl.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int]
ssl.EC_KEY_get0_group.restype = ctypes.c_void_p
ssl.EC_KEY_get0_group.argtypes = [ctypes.c_void_p]
ssl.EC_KEY_get0_public_key.restype = ctypes.c_void_p
ssl.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p]
ssl.EC_KEY_set_private_key.restype = ctypes.c_int
ssl.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
ssl.EC_KEY_set_conv_form.restype = None
ssl.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, ctypes.c_int]
ssl.EC_KEY_set_public_key.restype = ctypes.c_int
ssl.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
ssl.i2o_ECPublicKey.restype = ctypes.c_void_p
ssl.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
ssl.EC_POINT_new.restype = ctypes.c_void_p
ssl.EC_POINT_new.argtypes = [ctypes.c_void_p]
ssl.EC_POINT_free.restype = None
ssl.EC_POINT_free.argtypes = [ctypes.c_void_p]
ssl.EC_POINT_mul.restype = ctypes.c_int
ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
# this specifies the curve used with ECDSA.
NID_secp256k1 = 714 # from openssl/obj_mac.h
# Thx to Sam Devlin for the ctypes magic 64-bit fix.
def _check_result(val, func, args):
if val == 0:
raise ValueError
else:
return ctypes.c_void_p (val)
ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
ssl.EC_KEY_new_by_curve_name.errcheck = _check_result
class CECKey(object):
"""Wrapper around OpenSSL's EC_KEY"""
POINT_CONVERSION_COMPRESSED = 2
POINT_CONVERSION_UNCOMPRESSED = 4
def __init__(self):
self.k = ssl.EC_KEY_new_by_curve_name(NID_secp256k1)
def __del__(self):
if ssl:
ssl.EC_KEY_free(self.k)
self.k = None
def set_secretbytes(self, secret):
priv_key = ssl.BN_bin2bn(secret, 32, ssl.BN_new())
group = ssl.EC_KEY_get0_group(self.k)
pub_key = ssl.EC_POINT_new(group)
ctx = ssl.BN_CTX_new()
if not ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx):
raise ValueError("Could not derive public key from the supplied secret.")
ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx)
ssl.EC_KEY_set_private_key(self.k, priv_key)
ssl.EC_KEY_set_public_key(self.k, pub_key)
ssl.EC_POINT_free(pub_key)
ssl.BN_CTX_free(ctx)
return self.k
def set_privkey(self, key):
self.mb = ctypes.create_string_buffer(key)
return ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
def set_pubkey(self, key):
self.mb = ctypes.create_string_buffer(key)
return ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
def get_privkey(self):
size = ssl.i2d_ECPrivateKey(self.k, 0)
mb_pri = ctypes.create_string_buffer(size)
ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri)))
return mb_pri.raw
def get_pubkey(self):
size = ssl.i2o_ECPublicKey(self.k, 0)
mb = ctypes.create_string_buffer(size)
ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb)))
return mb.raw
def get_raw_ecdh_key(self, other_pubkey):
ecdh_keybuffer = ctypes.create_string_buffer(32)
r = ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32,
ssl.EC_KEY_get0_public_key(other_pubkey.k),
self.k, 0)
if r != 32:
raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed')
return ecdh_keybuffer.raw
def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):
# FIXME: be warned it's not clear what the kdf should be as a default
r = self.get_raw_ecdh_key(other_pubkey)
return kdf(r)
def sign(self, hash):
# FIXME: need unit tests for below cases
if not isinstance(hash, bytes):
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
if len(hash) != 32:
raise ValueError('Hash must be exactly 32 bytes long')
sig_size0 = ctypes.c_uint32()
sig_size0.value = ssl.ECDSA_size(self.k)
mb_sig = ctypes.create_string_buffer(sig_size0.value)
result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
assert 1 == result
return mb_sig.raw[:sig_size0.value]
def verify(self, hash, sig):
"""Verify a DER signature"""
return ssl.ECDSA_verify(0, hash, len(hash), sig, len(sig), self.k) == 1
def set_compressed(self, compressed):
if compressed:
form = self.POINT_CONVERSION_COMPRESSED
else:
form = self.POINT_CONVERSION_UNCOMPRESSED
ssl.EC_KEY_set_conv_form(self.k, form)
class CPubKey(bytes):
"""An encapsulated public key
Attributes:
is_valid - Corresponds to CPubKey.IsValid()
is_fullyvalid - Corresponds to CPubKey.IsFullyValid()
is_compressed - Corresponds to CPubKey.IsCompressed()
"""
def __new__(cls, buf, _cec_key=None):
self = super(CPubKey, cls).__new__(cls, buf)
if _cec_key is None:
_cec_key = CECKey()
self._cec_key = _cec_key
self.is_fullyvalid = _cec_key.set_pubkey(self) != 0
return self
@property
def is_valid(self):
return len(self) > 0
@property
def is_compressed(self):
return len(self) == 33
def verify(self, hash, sig):
return self._cec_key.verify(hash, sig)
def __str__(self):
return repr(self)
def __repr__(self):
# Always have represent as b'<secret>' so test cases don't have to
# change for py2/3
if sys.version > '3':
return '%s(%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__())
else:
return '%s(b%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__())

View File

@ -1,7 +1,12 @@
# mininode.py - Bitcoin P2P network half-a-node
#
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
# Copyright (c) 2010-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://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.
@ -46,7 +51,7 @@ OVERWINTER_PROTO_VERSION = 170003
SAPLING_PROTO_VERSION = 170006
BLOSSOM_PROTO_VERSION = 170008
MY_SUBVERSION = b"/python-mininode-tester:0.0.1/"
MY_SUBVERSION = b"/python-mininode-tester:0.0.3/"
SPROUT_VERSION_GROUP_ID = 0x00000000
OVERWINTER_VERSION_GROUP_ID = 0x03C48270
@ -757,9 +762,8 @@ class CTransaction(object):
self.calc_sha256()
def calc_sha256(self):
serialized = self.serialize()
if self.sha256 is None:
self.sha256 = uint256_from_str(hash256(serialized))
self.sha256 = uint256_from_str(hash256(self.serialize()))
self.hash = hash256(self.serialize())[::-1].hex()
def is_valid(self):
@ -1607,43 +1611,48 @@ class NodeConn(asyncore.dispatcher):
self.sendbuf = self.sendbuf[sent:]
def got_data(self):
while True:
if len(self.recvbuf) < 4:
return
if self.recvbuf[:4] != self.MAGIC_BYTES[self.network]:
raise ValueError("got garbage %r" % (self.recvbuf,))
if self.ver_recv < 209:
if len(self.recvbuf) < 4 + 12 + 4:
try:
while True:
if len(self.recvbuf) < 4:
return
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
checksum = None
if len(self.recvbuf) < 4 + 12 + 4 + msglen:
return
msg = self.recvbuf[4+12+4:4+12+4+msglen]
self.recvbuf = self.recvbuf[4+12+4+msglen:]
else:
if len(self.recvbuf) < 4 + 12 + 4 + 4:
return
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
checksum = self.recvbuf[4+12+4:4+12+4+4]
if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen:
return
msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen]
th = sha256(msg)
h = sha256(th)
if checksum != h[:4]:
raise ValueError("got bad checksum %r" % (self.recvbuf,))
self.recvbuf = self.recvbuf[4+12+4+4+msglen:]
if command in self.messagemap:
f = BytesIO(msg)
t = self.messagemap[command]()
t.deserialize(f)
self.got_message(t)
else:
self.show_debug_msg("Unknown command: '" + command + "' " +
if self.recvbuf[:4] != self.MAGIC_BYTES[self.network]:
raise ValueError("got garbage %r" % (self.recvbuf,))
if self.ver_recv < 209:
if len(self.recvbuf) < 4 + 12 + 4:
return
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
checksum = None
if len(self.recvbuf) < 4 + 12 + 4 + msglen:
return
msg = self.recvbuf[4+12+4:4+12+4+msglen]
self.recvbuf = self.recvbuf[4+12+4+msglen:]
else:
if len(self.recvbuf) < 4 + 12 + 4 + 4:
return
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
checksum = self.recvbuf[4+12+4:4+12+4+4]
if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen:
return
msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen]
th = sha256(msg)
h = sha256(th)
if checksum != h[:4]:
raise ValueError("got bad checksum %r" % (self.recvbuf,))
self.recvbuf = self.recvbuf[4+12+4+4+msglen:]
if command in self.messagemap:
f = BytesIO(msg)
t = self.messagemap[command]()
t.deserialize(f)
self.got_message(t)
else:
self.show_debug_msg("Unknown command: '" + command + "' " +
repr(msg))
except Exception as e:
print('got_data:', repr(e))
# import traceback
# traceback.print_tb(sys.exc_info()[2])
def send_message(self, message, pushbuf=False):
if self.state != b"connected" and not pushbuf:

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .

View File

@ -1,10 +1,13 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
# script.py
#
# This file is modified from python-bitcoinlib.
#
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
#
"""Scripts
@ -22,7 +25,7 @@ if sys.version > '3':
from pyblake2 import blake2b
import struct
from test_framework import bignum
from test_framework.bignum import bn2vch
from test_framework.mininode import (CTransaction, CTxOut, hash256, ser_string, ser_uint256)
MAX_SCRIPT_SIZE = 10000
@ -659,7 +662,7 @@ class CScript(bytes):
elif other == -1:
other = bytes([OP_1NEGATE])
else:
other = CScriptOp.encode_op_pushdata(bignum.bn2vch(other))
other = CScriptOp.encode_op_pushdata(bn2vch(other))
elif isinstance(other, (bytes, bytearray)):
other = bytes(CScriptOp.encode_op_pushdata(other))
return other

View File

@ -1,5 +1,5 @@
#!/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 https://www.opensource.org/licenses/mit-license.php .
'''

View File

@ -1,14 +1,14 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
# Base class for RPC testing
# Add python-bitcoinrpc to module search path:
import logging
import optparse
import os
import sys
import shutil
import tempfile
import traceback
@ -16,7 +16,6 @@ import traceback
from .authproxy import JSONRPCException
from .util import (
initialize_chain,
assert_equal,
start_nodes,
connect_nodes_bi,
sync_blocks,
@ -26,26 +25,32 @@ from .util import (
enable_coverage,
check_json_precision,
initialize_chain_clean,
PortSeed,
)
class BitcoinTestFramework(object):
# These may be over-ridden by subclasses:
def __init__(self):
self.num_nodes = 4
self.setup_clean_chain = False
self.nodes = None
def run_test(self):
for node in self.nodes:
assert_equal(node.getblockcount(), 200)
assert_equal(node.getbalance(), 25*10)
raise NotImplementedError
def add_options(self, parser):
pass
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain(self.options.tmpdir)
if self.setup_clean_chain:
initialize_chain_clean(self.options.tmpdir, self.num_nodes)
else:
initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir)
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir)
return start_nodes(self.num_nodes, self.options.tmpdir)
def setup_network(self, split = False):
self.nodes = self.setup_nodes()
@ -95,7 +100,6 @@ class BitcoinTestFramework(object):
self.setup_network(False)
def main(self):
import optparse
parser = optparse.OptionParser(usage="%prog [options]")
parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
@ -104,43 +108,45 @@ class BitcoinTestFramework(object):
help="Don't stop bitcoinds after the test execution")
parser.add_option("--srcdir", dest="srcdir", default="../../src",
help="Source directory containing bitcoind/bitcoin-cli (default: %default)")
parser.add_option("--cachedir", dest="cachedir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../cache"),
help="Directory for caching pregenerated datadirs")
parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
help="Root directory for datadirs")
parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
help="Print out all RPC calls as they are made")
parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int',
help="The seed to use for assigning port numbers (default: current process id)")
parser.add_option("--coveragedir", dest="coveragedir",
help="Write tested RPC commands into this directory")
self.add_options(parser)
(self.options, self.args) = parser.parse_args()
self.options.tmpdir += '/' + str(self.options.port_seed)
if self.options.trace_rpc:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
if self.options.coveragedir:
enable_coverage(self.options.coveragedir)
PortSeed.n = self.options.port_seed
os.environ['PATH'] = self.options.srcdir+":"+os.environ['PATH']
check_json_precision()
success = False
try:
if not os.path.isdir(self.options.tmpdir):
os.makedirs(self.options.tmpdir)
os.makedirs(self.options.tmpdir, exist_ok=False)
self.setup_chain()
self.setup_network()
self.run_test()
success = True
except JSONRPCException as e:
print("JSONRPC error: "+e.error['message'])
traceback.print_tb(sys.exc_info()[2])
except AssertionError as e:
print("Assertion failed: "+ str(e))
print("Assertion failed: " + str(e))
traceback.print_tb(sys.exc_info()[2])
except KeyError as e:
print("key not found: "+ str(e))
@ -148,6 +154,8 @@ class BitcoinTestFramework(object):
except Exception as e:
print("Unexpected exception caught during testing: "+str(e))
traceback.print_tb(sys.exc_info()[2])
except KeyboardInterrupt as e:
print("Exiting after " + repr(e))
if not self.options.noshutdown:
print("Stopping nodes")
@ -176,9 +184,10 @@ class BitcoinTestFramework(object):
class ComparisonTestFramework(BitcoinTestFramework):
# Can override the num_nodes variable to indicate how many nodes to run.
def __init__(self):
super().__init__()
self.num_nodes = 2
self.setup_clean_chain = True
def add_options(self, parser):
parser.add_option("--testbinary", dest="testbinary",
@ -188,10 +197,6 @@ class ComparisonTestFramework(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to use for reference nodes (if any)")
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, self.num_nodes)
def setup_network(self):
self.nodes = start_nodes(
self.num_nodes, self.options.tmpdir,

View File

@ -1,4 +1,5 @@
# Copyright (c) 2014 The Bitcoin Core developers
#!/usr/bin/env python3
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -7,7 +8,6 @@
# Helpful routines for regression testing
#
# Add python-bitcoinrpc to module search path:
import os
import sys
@ -15,6 +15,7 @@ from binascii import hexlify, unhexlify
from base64 import b64encode
from decimal import Decimal, ROUND_DOWN
import json
import http.client
import random
import shutil
import subprocess
@ -37,6 +38,18 @@ BLOSSOM_BRANCH_ID = 0x2BB40E60
HEARTWOOD_BRANCH_ID = 0xF5B9230B
CANOPY_BRANCH_ID = 0xE9FF75A6
# The maximum number of nodes a single test can spawn
MAX_NODES = 8
# Don't assign rpc or p2p ports lower than this
PORT_MIN = 11000
# The number of ports to "reserve" for p2p and rpc, each
PORT_RANGE = 5000
class PortSeed:
# Must be initialized with a unique integer for each process
n = None
def enable_coverage(dirname):
"""Maintain a log of which RPC calls are made during testing."""
global COVERAGE_DIR
@ -70,9 +83,11 @@ def get_rpc_proxy(url, node_number, timeout=None):
def p2p_port(n):
return 11000 + n + os.getpid()%999
assert(n <= MAX_NODES)
return PORT_MIN + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)
def rpc_port(n):
return 12000 + n + os.getpid()%999
return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)
def check_json_precision():
"""Make sure json library being used does not lose precision converting BTC values"""
@ -90,31 +105,41 @@ def hex_str_to_bytes(hex_str):
def str_to_b64str(string):
return b64encode(string.encode('utf-8')).decode('ascii')
def sync_blocks(rpc_connections, wait=1):
def sync_blocks(rpc_connections, wait=0.125, timeout=60, allow_different_tips=False):
"""
Wait until everybody has the same block count, and has notified
all internal listeners of them
Wait until everybody has the same tip, and has notified
all internal listeners of them.
If allow_different_tips is True, waits until everyone has
the same block count.
"""
while True:
counts = [ x.getblockcount() for x in rpc_connections ]
if counts == [ counts[0] ]*len(counts):
while timeout > 0:
if allow_different_tips:
tips = [ x.getblockcount() for x in rpc_connections ]
else:
tips = [ x.getbestblockhash() for x in rpc_connections ]
if tips == [ tips[0] ]*len(tips):
break
time.sleep(wait)
timeout -= wait
# Now that the block counts are in sync, wait for the internal
# notifications to finish
while True:
while timeout > 0:
notified = [ x.getblockchaininfo()['fullyNotified'] for x in rpc_connections ]
if notified == [ True ] * len(notified):
break
return True
time.sleep(wait)
timeout -= wait
def sync_mempools(rpc_connections, wait=1):
raise AssertionError("Block sync failed")
def sync_mempools(rpc_connections, wait=0.5, timeout=60):
"""
Wait until everybody has the same transactions in their memory
pools, and has notified all internal listeners of them
"""
while True:
while timeout > 0:
pool = set(rpc_connections[0].getrawmempool())
num_match = 1
for i in range(1, len(rpc_connections)):
@ -123,14 +148,18 @@ def sync_mempools(rpc_connections, wait=1):
if num_match == len(rpc_connections):
break
time.sleep(wait)
timeout -= wait
# Now that the mempools are in sync, wait for the internal
# notifications to finish
while True:
while timeout > 0:
notified = [ x.getmempoolinfo()['fullyNotified'] for x in rpc_connections ]
if notified == [ True ] * len(notified):
break
return True
time.sleep(wait)
timeout -= wait
raise AssertionError("Mempool sync failed")
bitcoind_processes = {}
@ -138,18 +167,31 @@ def initialize_datadir(dirname, n):
datadir = os.path.join(dirname, "node"+str(n))
if not os.path.isdir(datadir):
os.makedirs(datadir)
rpc_u, rpc_p = rpc_auth_pair(n)
with open(os.path.join(datadir, "zcash.conf"), 'w', encoding='utf8') as f:
f.write("regtest=1\n")
f.write("showmetrics=0\n")
f.write("rpcuser=rt\n")
f.write("rpcpassword=rt\n")
f.write("rpcuser=" + rpc_u + "\n")
f.write("rpcpassword=" + rpc_p + "\n")
f.write("port="+str(p2p_port(n))+"\n")
f.write("rpcport="+str(rpc_port(n))+"\n")
f.write("listenonion=0\n")
return datadir
def rpc_auth_pair(n):
return 'rpcuser💻' + str(n), 'rpcpass🔑' + str(n)
def rpc_url(i, rpchost=None):
return "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
rpc_u, rpc_p = rpc_auth_pair(i)
host = '127.0.0.1'
port = rpc_port(i)
if rpchost:
parts = rpchost.split(':')
if len(parts) == 2:
host, port = parts
else:
host = rpchost
return "http://%s:%s@%s:%d" % (rpc_u, rpc_p, host, int(port))
def wait_for_bitcoind_start(process, url, i):
'''
@ -171,10 +213,10 @@ def wait_for_bitcoind_start(process, url, i):
raise # unknown JSON RPC exception
time.sleep(0.25)
def initialize_chain(test_dir):
def initialize_chain(test_dir, num_nodes, cachedir):
"""
Create (or copy from cache) a 200-block-long chain and
4 wallets.
Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
Afterward, create num_nodes copies from the cache
"""
# Due to the consensus change fix for the timejacking attack, we need to
@ -193,24 +235,28 @@ def initialize_chain(test_dir):
# default). Therefore, if the logic between the completion of any two
# adjacent calls to `generate` within a test takes longer than 2.5 minutes,
# the excess will subtract from the slack.
if os.path.isdir(os.path.join("cache", "node0")):
if os.stat("cache").st_mtime + (60 * 60) < time.time():
if os.path.isdir(os.path.join(cachedir, "node0")):
if os.stat(cachedir).st_mtime + (60 * 60) < time.time():
print("initialize_chain(): Removing stale cache")
shutil.rmtree("cache")
shutil.rmtree(cachedir)
if (not os.path.isdir(os.path.join("cache","node0"))
or not os.path.isdir(os.path.join("cache","node1"))
or not os.path.isdir(os.path.join("cache","node2"))
or not os.path.isdir(os.path.join("cache","node3"))):
assert num_nodes <= MAX_NODES
create_cache = False
for i in range(MAX_NODES):
if not os.path.isdir(os.path.join(cachedir, 'node'+str(i))):
create_cache = True
break
if create_cache:
#find and delete old cache directories if any exist
for i in range(4):
if os.path.isdir(os.path.join("cache","node"+str(i))):
shutil.rmtree(os.path.join("cache","node"+str(i)))
for i in range(MAX_NODES):
if os.path.isdir(os.path.join(cachedir,"node"+str(i))):
shutil.rmtree(os.path.join(cachedir,"node"+str(i)))
# Create cache directories, run bitcoinds:
for i in range(4):
datadir=initialize_datadir("cache", i)
for i in range(MAX_NODES):
datadir=initialize_datadir(cachedir, i)
args = [ os.getenv("BITCOIND", "bitcoind"), "-keypool=1", "-datadir="+datadir, "-discover=0" ]
args.extend([
'-nuparams=5ba81b19:1', # Overwinter
@ -226,15 +272,18 @@ def initialize_chain(test_dir):
print("initialize_chain: RPC successfully started")
rpcs = []
for i in range(4):
for i in range(MAX_NODES):
try:
rpcs.append(get_rpc_proxy(rpc_url(i), i))
except:
sys.stderr.write("Error connecting to "+rpc_url(i)+"\n")
sys.exit(1)
# Create a 200-block-long chain; each of the 4 nodes
# Create a 200-block-long chain; each of the 4 first nodes
# gets 25 mature blocks and 25 immature.
# Note: To preserve compatibility with older versions of
# initialize_chain, only 4 nodes will generate coins.
#
# Blocks are created with timestamps 2.5 minutes apart (matching the
# chain defaulting above to Sapling active), starting 200 * 2.5 minutes
# before the current time.
@ -253,14 +302,14 @@ def initialize_chain(test_dir):
# Shut them down, and clean up cache directories:
stop_nodes(rpcs)
wait_bitcoinds()
for i in range(4):
os.remove(log_filename("cache", i, "debug.log"))
os.remove(log_filename("cache", i, "db.log"))
os.remove(log_filename("cache", i, "peers.dat"))
os.remove(log_filename("cache", i, "fee_estimates.dat"))
for i in range(MAX_NODES):
os.remove(log_filename(cachedir, i, "debug.log"))
os.remove(log_filename(cachedir, i, "db.log"))
os.remove(log_filename(cachedir, i, "peers.dat"))
os.remove(log_filename(cachedir, i, "fee_estimates.dat"))
for i in range(4):
from_dir = os.path.join("cache", "node"+str(i))
for i in range(num_nodes):
from_dir = os.path.join(cachedir, "node"+str(i))
to_dir = os.path.join(test_dir, "node"+str(i))
shutil.copytree(from_dir, to_dir)
initialize_datadir(test_dir, i) # Overwrite port/rpcport in zcash.conf
@ -344,8 +393,8 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None):
"""
Start multiple bitcoinds, return RPC connections to them
"""
if extra_args is None: extra_args = [ None for i in range(num_nodes) ]
if binary is None: binary = [ None for i in range(num_nodes) ]
if extra_args is None: extra_args = [ None for _ in range(num_nodes) ]
if binary is None: binary = [ None for _ in range(num_nodes) ]
rpcs = []
try:
for i in range(num_nodes):
@ -363,13 +412,19 @@ def check_node(i):
return bitcoind_processes[i].returncode
def stop_node(node, i):
node.stop()
try:
node.stop()
except http.client.CannotSendRequest as e:
print("WARN: Unable to stop node: " + repr(e))
bitcoind_processes[i].wait()
del bitcoind_processes[i]
def stop_nodes(nodes):
for node in nodes:
node.stop()
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
def set_node_times(nodes, t):

View File

@ -32,7 +32,7 @@ from test_framework.util import (
get_coinbase_address,
start_node, start_nodes,
sync_blocks, sync_mempools,
initialize_chain_clean, connect_nodes_bi,
connect_nodes_bi,
wait_and_assert_operationid_status,
bitcoind_processes,
check_node_log
@ -44,12 +44,13 @@ TURNSTILE_ARGS = ['-experimentalfeatures',
class TurnstileTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def __init__(self):
super().__init__()
self.num_nodes = 3
self.setup_clean_chain = True
def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
self.is_network_split=False

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -14,6 +14,11 @@ from test_framework.util import assert_equal, connect_nodes, \
class TxnMallTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = False
def add_options(self, parser):
parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")

View File

@ -1,12 +1,12 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_greater_than, \
initialize_chain_clean, start_nodes, start_node, connect_nodes_bi, \
start_nodes, start_node, connect_nodes_bi, \
stop_nodes, sync_blocks, sync_mempools, wait_and_assert_operationid_status, \
wait_bitcoinds
@ -14,9 +14,10 @@ from decimal import Decimal
class WalletTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir)

View File

@ -13,8 +13,8 @@ from decimal import Decimal
class WalletNullifiersTest (BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir,
extra_args=[['-experimentalfeatures', '-developerencryptwallet']] * 4)
return start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-experimentalfeatures', '-developerencryptwallet']] * self.num_nodes)
def run_test (self):
# add zaddr to node 0

View File

@ -9,7 +9,6 @@ from test_framework.util import (
assert_greater_than,
connect_nodes_bi,
get_coinbase_address,
initialize_chain_clean,
start_nodes,
wait_and_assert_operationid_status,
)
@ -19,16 +18,17 @@ from decimal import Decimal
class WalletOverwinterTxTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.num_nodes = 4
self.setup_clean_chain = True
def setup_network(self, split=False):
self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[[
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
"-nuparams=2bb40e60:200",
"-debug=zrpcunsafe",
"-txindex",
]] * 4 )
]] * self.num_nodes)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)

View File

@ -8,7 +8,6 @@ from test_framework.authproxy import JSONRPCException
from test_framework.util import (
assert_equal,
get_coinbase_address,
start_nodes,
wait_and_assert_operationid_status,
)
@ -17,9 +16,6 @@ from decimal import Decimal
# Test wallet behaviour with Sapling addresses
class WalletSaplingTest(BitcoinTestFramework):
def setup_nodes(self):
return start_nodes(4, self.options.tmpdir)
def run_test(self):
# Sanity-check the test harness
assert_equal(self.nodes[0].getblockcount(), 200)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
@ -35,7 +35,7 @@ and confirm again balances are correct.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_nodes, start_node, connect_nodes, stop_node, \
sync_blocks, sync_mempools
@ -44,14 +44,16 @@ import shutil
from random import randint
from decimal import Decimal
import logging
import sys
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout)
class WalletBackupTest(BitcoinTestFramework):
def setup_chain(self):
logging.info("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
# This mirrors how the network was setup in the bash test
def setup_network(self, split=False):
@ -62,7 +64,7 @@ class WalletBackupTest(BitcoinTestFramework):
# nodes 1, 2,3 are spenders, let's give them a keypool=100
extra_args = [["-keypool=100", ed0], ["-keypool=100", ed1], ["-keypool=100", ed2], []]
self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
connect_nodes(self.nodes[2], 3)

View File

@ -1,22 +1,23 @@
#!/usr/bin/env python3
# Copyright (c) 2014 The Bitcoin Core developers
# Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, initialize_chain_clean, \
from test_framework.util import assert_equal, \
start_nodes, start_node, connect_nodes_bi, bitcoind_processes
class ZapWalletTXesTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
def __init__(self):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 3
def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir)
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)

View File

@ -10,6 +10,10 @@ from test_framework.util import assert_equal, start_node, \
class JoinSplitTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 1
def setup_network(self):
self.nodes = []
self.is_network_split = False

View File

@ -9,8 +9,9 @@ from test_framework.util import assert_equal, assert_greater_than, start_nodes,\
initialize_chain_clean, connect_nodes_bi, wait_and_assert_operationid_status
from functools import reduce
import logging
import sys
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout)
fee = Decimal('0.0001') # constant (but can be changed within reason)

View File

@ -1,5 +1,5 @@
#!/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 https://www.opensource.org/licenses/mit-license.php .
@ -15,6 +15,10 @@ import struct
class ZMQTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.num_nodes = 4
port = 28332
def setup_nodes(self):
@ -23,7 +27,7 @@ class ZMQTest(BitcoinTestFramework):
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port)
return start_nodes(4, self.options.tmpdir, extra_args=[
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)],
[],
[],

View File

@ -182,7 +182,7 @@ STAGE_COMMANDS = {
'util-test': util_test,
'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'],
'univalue': ['make', '-C', repofile('src/univalue'), 'check'],
'rpc': [repofile('qa/pull-tester/rpc-tests.sh')],
'rpc': [repofile('qa/pull-tester/rpc-tests.py')],
}

View File

@ -116,10 +116,6 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
}
}
bool IsValidMinerAddress(const MinerAddress& minerAddr) {
return minerAddr.which() != 0;
}
class AddFundingStreamValueToTx : public boost::static_visitor<bool>
{
private:
@ -742,7 +738,7 @@ void static BitcoinMiner(const CChainParams& chainparams)
try {
// Throw an error if no address valid for mining was provided.
if (!IsValidMinerAddress(minerAddress)) {
if (!boost::apply_visitor(IsValidMinerAddress(), minerAddress)) {
throw std::runtime_error("No miner address available (mining requires a wallet or -mineraddress)");
}

View File

@ -41,7 +41,24 @@ public:
}
};
bool IsValidMinerAddress(const MinerAddress& minerAddr);
class IsValidMinerAddress : public boost::static_visitor<bool>
{
public:
IsValidMinerAddress() {}
bool operator()(const InvalidMinerAddress &invalid) const {
return false;
}
bool operator()(const libzcash::SaplingPaymentAddress &pa) const {
return true;
}
bool operator()(const boost::shared_ptr<CReserveScript> &coinbaseScript) const {
// Return false if no script was provided. This can happen
// due to some internal error but also if the keypool is empty.
// In the latter case, already the pointer is NULL.
return coinbaseScript.get() && !coinbaseScript->reserveScript.empty();
}
};
struct CBlockTemplate
{

View File

@ -188,8 +188,14 @@ UniValue generate(const UniValue& params, bool fHelp)
MinerAddress minerAddress;
GetMainSignals().AddressForMining(minerAddress);
// If the keypool is exhausted, no script is returned at all. Catch this.
auto resv = boost::get<boost::shared_ptr<CReserveScript>>(&minerAddress);
if (resv && !resv->get()) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
// Throw an error if no address valid for mining was provided.
if (!IsValidMinerAddress(minerAddress)) {
if (!boost::apply_visitor(IsValidMinerAddress(), minerAddress)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "No miner address available (mining requires a wallet or -mineraddress)");
}
@ -622,7 +628,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
GetMainSignals().AddressForMining(minerAddress);
// Throw an error if no address valid for mining was provided.
if (!IsValidMinerAddress(minerAddress)) {
if (!boost::apply_visitor(IsValidMinerAddress(), minerAddress)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "No miner address available (mining requires a wallet or -mineraddress)");
}

View File

@ -4418,8 +4418,12 @@ void CWallet::GetAddressForMining(MinerAddress &minerAddress)
boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
CPubKey pubkey;
if (!rKey->GetReservedKey(pubkey))
if (!rKey->GetReservedKey(pubkey)) {
// Explicitly return nullptr to indicate that the keypool is empty.
rKey = nullptr;
minerAddress = rKey;
return;
}
rKey->reserveScript = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
minerAddress = rKey;